* bytecode.c (exec_byte_code): Use some more volatile variables
[emacs.git] / src / nsterm.m
blob47000da94da08c670da7e97165f371e96ccd5531
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013 Free Software
4 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 <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
69 #include "macfont.h"
70 #endif
71 #endif
73 /* call tracing */
74 #if 0
75 int term_trace_num = 0;
76 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
77                                 __FILE__, __LINE__, ++term_trace_num)
78 #else
79 #define NSTRACE(x)
80 #endif
82 extern NSString *NSMenuDidBeginTrackingNotification;
84 /* ==========================================================================
86     Local declarations
88    ========================================================================== */
90 /* Convert a symbol indexed with an NSxxx value to a value as defined
91    in keyboard.c (lispy_function_key). I hope this is a correct way
92    of doing things... */
93 static unsigned convert_ns_to_X_keysym[] =
95   NSHomeFunctionKey,            0x50,
96   NSLeftArrowFunctionKey,       0x51,
97   NSUpArrowFunctionKey,         0x52,
98   NSRightArrowFunctionKey,      0x53,
99   NSDownArrowFunctionKey,       0x54,
100   NSPageUpFunctionKey,          0x55,
101   NSPageDownFunctionKey,        0x56,
102   NSEndFunctionKey,             0x57,
103   NSBeginFunctionKey,           0x58,
104   NSSelectFunctionKey,          0x60,
105   NSPrintFunctionKey,           0x61,
106   NSClearLineFunctionKey,       0x0B,
107   NSExecuteFunctionKey,         0x62,
108   NSInsertFunctionKey,          0x63,
109   NSUndoFunctionKey,            0x65,
110   NSRedoFunctionKey,            0x66,
111   NSMenuFunctionKey,            0x67,
112   NSFindFunctionKey,            0x68,
113   NSHelpFunctionKey,            0x6A,
114   NSBreakFunctionKey,           0x6B,
116   NSF1FunctionKey,              0xBE,
117   NSF2FunctionKey,              0xBF,
118   NSF3FunctionKey,              0xC0,
119   NSF4FunctionKey,              0xC1,
120   NSF5FunctionKey,              0xC2,
121   NSF6FunctionKey,              0xC3,
122   NSF7FunctionKey,              0xC4,
123   NSF8FunctionKey,              0xC5,
124   NSF9FunctionKey,              0xC6,
125   NSF10FunctionKey,             0xC7,
126   NSF11FunctionKey,             0xC8,
127   NSF12FunctionKey,             0xC9,
128   NSF13FunctionKey,             0xCA,
129   NSF14FunctionKey,             0xCB,
130   NSF15FunctionKey,             0xCC,
131   NSF16FunctionKey,             0xCD,
132   NSF17FunctionKey,             0xCE,
133   NSF18FunctionKey,             0xCF,
134   NSF19FunctionKey,             0xD0,
135   NSF20FunctionKey,             0xD1,
136   NSF21FunctionKey,             0xD2,
137   NSF22FunctionKey,             0xD3,
138   NSF23FunctionKey,             0xD4,
139   NSF24FunctionKey,             0xD5,
141   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
142   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
143   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
145   NSTabCharacter,               0x09,
146   0x19,                         0x09,  /* left tab->regular since pass shift */
147   NSCarriageReturnCharacter,    0x0D,
148   NSNewlineCharacter,           0x0D,
149   NSEnterCharacter,             0x8D,
151   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
152   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
153   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
154   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
155   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
156   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
157   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
158   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
159   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
160   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
161   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
162   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
163   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
164   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
165   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
166   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
168   0x1B,                         0x1B   /* escape */
171 static Lisp_Object Qmodifier_value;
172 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
173 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
175 static Lisp_Object QUTF8_STRING;
177 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
178    the maximum font size to NOT antialias.  On GNUstep there is currently
179    no way to control this behavior. */
180 float ns_antialias_threshold;
182 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
183 NSString *ns_app_name = @"Emacs";  /* default changed later */
185 /* Display variables */
186 struct ns_display_info *x_display_list; /* Chain of existing displays */
187 Lisp_Object ns_display_name_list;
188 long context_menu_value = 0;
190 /* display update */
191 static struct frame *ns_updating_frame;
192 static NSView *focus_view = NULL;
193 static int ns_window_num = 0;
194 #ifdef NS_IMPL_GNUSTEP
195 static NSRect uRect;
196 #endif
197 static BOOL gsaved = NO;
198 static BOOL ns_fake_keydown = NO;
199 #ifdef NS_IMPL_COCOA
200 static BOOL ns_menu_bar_is_hidden = NO;
201 #endif
202 /*static int debug_lock = 0; */
204 /* event loop */
205 static BOOL send_appdefined = YES;
206 #define NO_APPDEFINED_DATA (-8)
207 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
208 static NSTimer *timed_entry = 0;
209 static NSTimer *scroll_repeat_entry = nil;
210 static fd_set select_readfds, select_writefds;
211 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
212 static int select_nfds = 0, select_valid = 0;
213 static struct timespec select_timeout = { 0, 0 };
214 static int selfds[2] = { -1, -1 };
215 static pthread_mutex_t select_mutex;
216 static int apploopnr = 0;
217 static NSAutoreleasePool *outerpool;
218 static struct input_event *emacs_event = NULL;
219 static struct input_event *q_event_ptr = NULL;
220 static int n_emacs_events_pending = 0;
221 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
222   *ns_pending_service_args;
223 static BOOL ns_do_open_file = NO;
224 static BOOL ns_last_use_native_fullscreen;
226 static struct {
227   struct input_event *q;
228   int nr, cap;
229 } hold_event_q = {
230   NULL, 0, 0
233 #ifdef NS_IMPL_COCOA
235  * State for pending menu activation:
236  * MENU_NONE     Normal state
237  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
238  *               run lisp to update the menu.
239  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
240  *               will open.
241  */
242 #define MENU_NONE 0
243 #define MENU_PENDING 1
244 #define MENU_OPENING 2
245 static int menu_will_open_state = MENU_NONE;
247 /* Saved position for menu click.  */
248 static CGPoint menu_mouse_point;
249 #endif
251 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
252 #define NS_FUNCTION_KEY_MASK 0x800000
253 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
254 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
255 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
256 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
257 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
258 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
259 #define EV_MODIFIERS(e)                               \
260     ((([e modifierFlags] & NSHelpKeyMask) ?           \
261            hyper_modifier : 0)                        \
262      | (!EQ (ns_right_alternate_modifier, Qleft) && \
263         (([e modifierFlags] & NSRightAlternateKeyMask) \
264          == NSRightAlternateKeyMask) ? \
265            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
266      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
267            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
268      | (([e modifierFlags] & NSShiftKeyMask) ?     \
269            shift_modifier : 0)                        \
270      | (!EQ (ns_right_control_modifier, Qleft) && \
271         (([e modifierFlags] & NSRightControlKeyMask) \
272          == NSRightControlKeyMask) ? \
273            parse_solitary_modifier (ns_right_control_modifier) : 0) \
274      | (([e modifierFlags] & NSControlKeyMask) ?      \
275            parse_solitary_modifier (ns_control_modifier) : 0)     \
276      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
277            parse_solitary_modifier (ns_function_modifier) : 0)    \
278      | (!EQ (ns_right_command_modifier, Qleft) && \
279         (([e modifierFlags] & NSRightCommandKeyMask) \
280          == NSRightCommandKeyMask) ? \
281            parse_solitary_modifier (ns_right_command_modifier) : 0) \
282      | (([e modifierFlags] & NSCommandKeyMask) ?      \
283            parse_solitary_modifier (ns_command_modifier):0))
285 #define EV_UDMODIFIERS(e)                                      \
286     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
287      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
288      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
289      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
290      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
291      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
292      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
293      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
294      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
296 #define EV_BUTTON(e)                                                         \
297     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
298       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
299      [e buttonNumber] - 1)
301 /* Convert the time field to a timestamp in milliseconds. */
302 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
304 /* This is a piece of code which is common to all the event handling
305    methods.  Maybe it should even be a function.  */
306 #define EV_TRAILER(e)                                                   \
307   {                                                                     \
308     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
309     EV_TRAILER2 (e);                                                    \
310   }
312 #define EV_TRAILER2(e)                                                  \
313   {                                                                     \
314       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
315       if (q_event_ptr)                                                  \
316         {                                                               \
317           n_emacs_events_pending++;                                     \
318           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
319         }                                                               \
320       else                                                              \
321         hold_event (emacs_event);                                       \
322       EVENT_INIT (*emacs_event);                                        \
323       ns_send_appdefined (-1);                                          \
324     }
326 /* TODO: get rid of need for these forward declarations */
327 static void ns_condemn_scroll_bars (struct frame *f);
328 static void ns_judge_scroll_bars (struct frame *f);
329 void x_set_frame_alpha (struct frame *f);
332 /* ==========================================================================
334     Utilities
336    ========================================================================== */
338 static void
339 hold_event (struct input_event *event)
341   if (hold_event_q.nr == hold_event_q.cap)
342     {
343       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
344       else hold_event_q.cap *= 2;
345       hold_event_q.q =
346         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
347     }
349   hold_event_q.q[hold_event_q.nr++] = *event;
350   /* Make sure ns_read_socket is called, i.e. we have input.  */
351   raise (SIGIO);
352   send_appdefined = YES;
355 static Lisp_Object
356 append2 (Lisp_Object list, Lisp_Object item)
357 /* --------------------------------------------------------------------------
358    Utility to append to a list
359    -------------------------------------------------------------------------- */
361   Lisp_Object array[2];
362   array[0] = list;
363   array[1] = list1 (item);
364   return Fnconc (2, &array[0]);
368 const char *
369 ns_etc_directory (void)
370 /* If running as a self-contained app bundle, return as a string the
371    filename of the etc directory, if present; else nil.  */
373   NSBundle *bundle = [NSBundle mainBundle];
374   NSString *resourceDir = [bundle resourcePath];
375   NSString *resourcePath;
376   NSFileManager *fileManager = [NSFileManager defaultManager];
377   BOOL isDir;
379   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
380   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
381     {
382       if (isDir) return [resourcePath UTF8String];
383     }
384   return NULL;
388 const char *
389 ns_exec_path (void)
390 /* If running as a self-contained app bundle, return as a path string
391    the filenames of the libexec and bin directories, ie libexec:bin.
392    Otherwise, return nil.
393    Normally, Emacs does not add its own bin/ directory to the PATH.
394    However, a self-contained NS build has a different layout, with
395    bin/ and libexec/ subdirectories in the directory that contains
396    Emacs.app itself.
397    We put libexec first, because init_callproc_1 uses the first
398    element to initialize exec-directory.  An alternative would be
399    for init_callproc to check for invocation-directory/libexec.
402   NSBundle *bundle = [NSBundle mainBundle];
403   NSString *resourceDir = [bundle resourcePath];
404   NSString *binDir = [bundle bundlePath];
405   NSString *resourcePath, *resourcePaths;
406   NSRange range;
407   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
408   NSFileManager *fileManager = [NSFileManager defaultManager];
409   NSArray *paths;
410   NSEnumerator *pathEnum;
411   BOOL isDir;
413   range = [resourceDir rangeOfString: @"Contents"];
414   if (range.location != NSNotFound)
415     {
416       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
417 #ifdef NS_IMPL_COCOA
418       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
419 #endif
420     }
422   paths = [binDir stringsByAppendingPaths:
423                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
424   pathEnum = [paths objectEnumerator];
425   resourcePaths = @"";
427   while ((resourcePath = [pathEnum nextObject]))
428     {
429       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
430         if (isDir)
431           {
432             if ([resourcePaths length] > 0)
433               resourcePaths
434                 = [resourcePaths stringByAppendingString: pathSeparator];
435             resourcePaths
436               = [resourcePaths stringByAppendingString: resourcePath];
437           }
438     }
439   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
441   return NULL;
445 const char *
446 ns_load_path (void)
447 /* If running as a self-contained app bundle, return as a path string
448    the filenames of the site-lisp, lisp and leim directories.
449    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
451   NSBundle *bundle = [NSBundle mainBundle];
452   NSString *resourceDir = [bundle resourcePath];
453   NSString *resourcePath, *resourcePaths;
454   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
455   NSFileManager *fileManager = [NSFileManager defaultManager];
456   BOOL isDir;
457   NSArray *paths = [resourceDir stringsByAppendingPaths:
458                               [NSArray arrayWithObjects:
459                                          @"site-lisp", @"lisp", @"leim", nil]];
460   NSEnumerator *pathEnum = [paths objectEnumerator];
461   resourcePaths = @"";
463   /* Hack to skip site-lisp.  */
464   if (no_site_lisp) resourcePath = [pathEnum nextObject];
466   while ((resourcePath = [pathEnum nextObject]))
467     {
468       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
469         if (isDir)
470           {
471             if ([resourcePaths length] > 0)
472               resourcePaths
473                 = [resourcePaths stringByAppendingString: pathSeparator];
474             resourcePaths
475               = [resourcePaths stringByAppendingString: resourcePath];
476           }
477     }
478   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
480   return NULL;
483 static void
484 ns_timeout (int usecs)
485 /* --------------------------------------------------------------------------
486      Blocking timer utility used by ns_ring_bell
487    -------------------------------------------------------------------------- */
489   struct timespec wakeup = timespec_add (current_timespec (),
490                                          make_timespec (0, usecs * 1000));
492   /* Keep waiting until past the time wakeup.  */
493   while (1)
494     {
495       struct timespec timeout, now = current_timespec ();
496       if (timespec_cmp (wakeup, now) <= 0)
497         break;
498       timeout = timespec_sub (wakeup, now);
500       /* Try to wait that long--but we might wake up sooner.  */
501       pselect (0, NULL, NULL, NULL, &timeout, NULL);
502     }
506 void
507 ns_release_object (void *obj)
508 /* --------------------------------------------------------------------------
509     Release an object (callable from C)
510    -------------------------------------------------------------------------- */
512     [(id)obj release];
516 void
517 ns_retain_object (void *obj)
518 /* --------------------------------------------------------------------------
519     Retain an object (callable from C)
520    -------------------------------------------------------------------------- */
522     [(id)obj retain];
526 void *
527 ns_alloc_autorelease_pool (void)
528 /* --------------------------------------------------------------------------
529      Allocate a pool for temporary objects (callable from C)
530    -------------------------------------------------------------------------- */
532   return [[NSAutoreleasePool alloc] init];
536 void
537 ns_release_autorelease_pool (void *pool)
538 /* --------------------------------------------------------------------------
539      Free a pool and temporary objects it refers to (callable from C)
540    -------------------------------------------------------------------------- */
542   ns_release_object (pool);
547 /* ==========================================================================
549     Focus (clipping) and screen update
551    ========================================================================== */
554 // Window constraining
555 // -------------------
557 // To ensure that the windows are not placed under the menu bar, they
558 // are typically moved by the call-back constrainFrameRect. However,
559 // by overriding it, it's possible to inhibit this, leaving the window
560 // in it's original position.
562 // It's possible to hide the menu bar. However, technically, it's only
563 // possible to hide it when the application is active. To ensure that
564 // this work properly, the menu bar and window constraining are
565 // deferred until the application becomes active.
567 // Even though it's not possible to manually move a window above the
568 // top of the screen, it is allowed if it's done programmatically,
569 // when the menu is hidden. This allows the editable area to cover the
570 // full screen height.
572 // Test cases
573 // ----------
575 // Use the following extra files:
577 //    init.el:
578 //       ;; Hide menu and place frame slightly above the top of the screen.
579 //       (setq ns-auto-hide-menu-bar t)
580 //       (set-frame-position (selected-frame) 0 -20)
582 // Test 1:
584 //    emacs -Q -l init.el
586 //    Result: No menu bar, and the title bar should be above the screen.
588 // Test 2:
590 //    emacs -Q
592 //    Result: Menu bar visible, frame placed immediately below the menu.
595 static void
596 ns_constrain_all_frames (void)
598   Lisp_Object tail, frame;
600   FOR_EACH_FRAME (tail, frame)
601     {
602       struct frame *f = XFRAME (frame);
603       if (FRAME_NS_P (f))
604         {
605           NSView *view = FRAME_NS_VIEW (f);
606           /* This no-op will trigger the default window placing
607            * constraint system. */
608           f->output_data.ns->dont_constrain = 0;
609           [[view window] setFrameOrigin:[[view window] frame].origin];
610         }
611     }
615 /* True, if the menu bar should be hidden.  */
617 static BOOL
618 ns_menu_bar_should_be_hidden (void)
620   return !NILP (ns_auto_hide_menu_bar)
621     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
625 /* Show or hide the menu bar, based on user setting.  */
627 static void
628 ns_update_auto_hide_menu_bar (void)
630 #ifdef NS_IMPL_COCOA
631 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
632   block_input ();
634   NSTRACE (ns_update_auto_hide_menu_bar);
636   if (NSApp != nil
637       && [NSApp isActive]
638       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
639     {
640       // Note, "setPresentationOptions" triggers an error unless the
641       // application is active.
642       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
644       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
645         {
646           NSApplicationPresentationOptions options
647             = NSApplicationPresentationAutoHideDock;
649           if (menu_bar_should_be_hidden)
650             options |= NSApplicationPresentationAutoHideMenuBar;
652           [NSApp setPresentationOptions: options];
654           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
656           if (!ns_menu_bar_is_hidden)
657             {
658               ns_constrain_all_frames ();
659             }
660         }
661     }
663   unblock_input ();
664 #endif
665 #endif
669 static void
670 ns_update_begin (struct frame *f)
671 /* --------------------------------------------------------------------------
672    Prepare for a grouped sequence of drawing calls
673    external (RIF) call; whole frame, called before update_window_begin
674    -------------------------------------------------------------------------- */
676   NSView *view = FRAME_NS_VIEW (f);
677   NSTRACE (ns_update_begin);
679   ns_update_auto_hide_menu_bar ();
681   ns_updating_frame = f;
682   [view lockFocus];
684   /* drawRect may have been called for say the minibuffer, and then clip path
685      is for the minibuffer.  But the display engine may draw more because
686      we have set the frame as garbaged.  So reset clip path to the whole
687      view.  */
688 #ifdef NS_IMPL_COCOA
689   {
690     NSBezierPath *bp;
691     NSRect r = [view frame];
692     NSRect cr = [[view window] frame];
693     /* If a large frame size is set, r may be larger than the window frame
694        before constrained.  In that case don't change the clip path, as we
695        will clear in to the tool bar and title bar.  */
696     if (r.size.height
697         + FRAME_NS_TITLEBAR_HEIGHT (f)
698         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
699       {
700         bp = [[NSBezierPath bezierPathWithRect: r] retain];
701         [bp setClip];
702         [bp release];
703       }
704   }
705 #endif
707 #ifdef NS_IMPL_GNUSTEP
708   uRect = NSMakeRect (0, 0, 0, 0);
709 #endif
713 static void
714 ns_update_window_begin (struct window *w)
715 /* --------------------------------------------------------------------------
716    Prepare for a grouped sequence of drawing calls
717    external (RIF) call; for one window, called after update_begin
718    -------------------------------------------------------------------------- */
720   struct frame *f = XFRAME (WINDOW_FRAME (w));
721   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
723   NSTRACE (ns_update_window_begin);
724   w->output_cursor = w->cursor;
726   block_input ();
728   if (f == hlinfo->mouse_face_mouse_frame)
729     {
730       /* Don't do highlighting for mouse motion during the update.  */
731       hlinfo->mouse_face_defer = 1;
733         /* If the frame needs to be redrawn,
734            simply forget about any prior mouse highlighting.  */
735       if (FRAME_GARBAGED_P (f))
736         hlinfo->mouse_face_window = Qnil;
738       /* (further code for mouse faces ifdef'd out in other terms elided) */
739     }
741   unblock_input ();
745 static void
746 ns_update_window_end (struct window *w, bool cursor_on_p,
747                       bool mouse_face_overwritten_p)
748 /* --------------------------------------------------------------------------
749    Finished a grouped sequence of drawing calls
750    external (RIF) call; for one window called before update_end
751    -------------------------------------------------------------------------- */
753   /* note: this fn is nearly identical in all terms */
754   if (!w->pseudo_window_p)
755     {
756       block_input ();
758       if (cursor_on_p)
759         display_and_set_cursor (w, 1,
760                                 w->output_cursor.hpos, w->output_cursor.vpos,
761                                 w->output_cursor.x, w->output_cursor.y);
763       if (draw_window_fringes (w, 1))
764         x_draw_vertical_border (w);
766       unblock_input ();
767     }
769   /* If a row with mouse-face was overwritten, arrange for
770      frame_up_to_date to redisplay the mouse highlight.  */
771   if (mouse_face_overwritten_p)
772     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
774   NSTRACE (update_window_end);
778 static void
779 ns_update_end (struct frame *f)
780 /* --------------------------------------------------------------------------
781    Finished a grouped sequence of drawing calls
782    external (RIF) call; for whole frame, called after update_window_end
783    -------------------------------------------------------------------------- */
785   EmacsView *view = FRAME_NS_VIEW (f);
787 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
788   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
790   block_input ();
792   [view unlockFocus];
793   [[view window] flushWindow];
795   unblock_input ();
796   ns_updating_frame = NULL;
797   NSTRACE (ns_update_end);
800 static void
801 ns_focus (struct frame *f, NSRect *r, int n)
802 /* --------------------------------------------------------------------------
803    Internal: Focus on given frame.  During small local updates this is used to
804      draw, however during large updates, ns_update_begin and ns_update_end are
805      called to wrap the whole thing, in which case these calls are stubbed out.
806      Except, on GNUstep, we accumulate the rectangle being drawn into, because
807      the back end won't do this automatically, and will just end up flushing
808      the entire window.
809    -------------------------------------------------------------------------- */
811 //  NSTRACE (ns_focus);
812 /* static int c =0;
813    fprintf (stderr, "focus: %d", c++);
814    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
815    fprintf (stderr, "\n"); */
817   if (f != ns_updating_frame)
818     {
819       NSView *view = FRAME_NS_VIEW (f);
820       if (view != focus_view)
821         {
822           if (focus_view != NULL)
823             {
824               [focus_view unlockFocus];
825               [[focus_view window] flushWindow];
826 /*debug_lock--; */
827             }
829           if (view)
830             [view lockFocus];
831           focus_view = view;
832 /*if (view) debug_lock++; */
833         }
834     }
836   /* clipping */
837   if (r)
838     {
839       [[NSGraphicsContext currentContext] saveGraphicsState];
840       if (n == 2)
841         NSRectClipList (r, 2);
842       else
843         NSRectClip (*r);
844       gsaved = YES;
845     }
849 static void
850 ns_unfocus (struct frame *f)
851 /* --------------------------------------------------------------------------
852      Internal: Remove focus on given frame
853    -------------------------------------------------------------------------- */
855 //  NSTRACE (ns_unfocus);
857   if (gsaved)
858     {
859       [[NSGraphicsContext currentContext] restoreGraphicsState];
860       gsaved = NO;
861     }
863   if (f != ns_updating_frame)
864     {
865       if (focus_view != NULL)
866         {
867           [focus_view unlockFocus];
868           [[focus_view window] flushWindow];
869           focus_view = NULL;
870 /*debug_lock--; */
871         }
872     }
876 static void
877 ns_clip_to_row (struct window *w, struct glyph_row *row,
878                 enum glyph_row_area area, BOOL gc)
879 /* --------------------------------------------------------------------------
880      Internal (but parallels other terms): Focus drawing on given row
881    -------------------------------------------------------------------------- */
883   struct frame *f = XFRAME (WINDOW_FRAME (w));
884   NSRect clip_rect;
885   int window_x, window_y, window_width;
887   window_box (w, area, &window_x, &window_y, &window_width, 0);
889   clip_rect.origin.x = window_x;
890   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
891   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
892   clip_rect.size.width = window_width;
893   clip_rect.size.height = row->visible_height;
895   ns_focus (f, &clip_rect, 1);
899 static void
900 ns_ring_bell (struct frame *f)
901 /* --------------------------------------------------------------------------
902      "Beep" routine
903    -------------------------------------------------------------------------- */
905   NSTRACE (ns_ring_bell);
906   if (visible_bell)
907     {
908       NSAutoreleasePool *pool;
909       struct frame *frame = SELECTED_FRAME ();
910       NSView *view;
912       block_input ();
913       pool = [[NSAutoreleasePool alloc] init];
915       view = FRAME_NS_VIEW (frame);
916       if (view != nil)
917         {
918           NSRect r, surr;
919           NSPoint dim = NSMakePoint (128, 128);
921           r = [view bounds];
922           r.origin.x += (r.size.width - dim.x) / 2;
923           r.origin.y += (r.size.height - dim.y) / 2;
924           r.size.width = dim.x;
925           r.size.height = dim.y;
926           surr = NSInsetRect (r, -2, -2);
927           ns_focus (frame, &surr, 1);
928           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
929           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
930                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
931           NSRectFill (r);
932           [[view window] flushWindow];
933           ns_timeout (150000);
934           [[view window] restoreCachedImage];
935           [[view window] flushWindow];
936           ns_unfocus (frame);
937         }
938       [pool release];
939       unblock_input ();
940     }
941   else
942     {
943       NSBeep ();
944     }
947 /* ==========================================================================
949     Frame / window manager related functions
951    ========================================================================== */
954 static void
955 ns_raise_frame (struct frame *f)
956 /* --------------------------------------------------------------------------
957      Bring window to foreground and make it active
958    -------------------------------------------------------------------------- */
960   NSView *view;
961   check_window_system (f);
962   view = FRAME_NS_VIEW (f);
963   block_input ();
964   if (FRAME_VISIBLE_P (f))
965     [[view window] makeKeyAndOrderFront: NSApp];
966   unblock_input ();
970 static void
971 ns_lower_frame (struct frame *f)
972 /* --------------------------------------------------------------------------
973      Send window to back
974    -------------------------------------------------------------------------- */
976   NSView *view;
977   check_window_system (f);
978   view = FRAME_NS_VIEW (f);
979   block_input ();
980   [[view window] orderBack: NSApp];
981   unblock_input ();
985 static void
986 ns_frame_raise_lower (struct frame *f, int raise)
987 /* --------------------------------------------------------------------------
988      External (hook)
989    -------------------------------------------------------------------------- */
991   NSTRACE (ns_frame_raise_lower);
993   if (raise)
994     ns_raise_frame (f);
995   else
996     ns_lower_frame (f);
1000 static void
1001 ns_frame_rehighlight (struct frame *frame)
1002 /* --------------------------------------------------------------------------
1003      External (hook): called on things like window switching within frame
1004    -------------------------------------------------------------------------- */
1006   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1007   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1009   NSTRACE (ns_frame_rehighlight);
1010   if (dpyinfo->x_focus_frame)
1011     {
1012       dpyinfo->x_highlight_frame
1013         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1014            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1015            : dpyinfo->x_focus_frame);
1016       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1017         {
1018           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1019           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1020         }
1021     }
1022   else
1023       dpyinfo->x_highlight_frame = 0;
1025   if (dpyinfo->x_highlight_frame &&
1026          dpyinfo->x_highlight_frame != old_highlight)
1027     {
1028       if (old_highlight)
1029         {
1030           x_update_cursor (old_highlight, 1);
1031           x_set_frame_alpha (old_highlight);
1032         }
1033       if (dpyinfo->x_highlight_frame)
1034         {
1035           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1036           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1037         }
1038     }
1042 void
1043 x_make_frame_visible (struct frame *f)
1044 /* --------------------------------------------------------------------------
1045      External: Show the window (X11 semantics)
1046    -------------------------------------------------------------------------- */
1048   NSTRACE (x_make_frame_visible);
1049   /* XXX: at some points in past this was not needed, as the only place that
1050      called this (frame.c:Fraise_frame ()) also called raise_lower;
1051      if this ends up the case again, comment this out again. */
1052   if (!FRAME_VISIBLE_P (f))
1053     {
1054       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1056       SET_FRAME_VISIBLE (f, 1);
1057       ns_raise_frame (f);
1059       /* Making a new frame from a fullscreen frame will make the new frame
1060          fullscreen also.  So skip handleFS as this will print an error.  */
1061       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1062           && [view isFullscreen])
1063         return;
1065       if (f->want_fullscreen != FULLSCREEN_NONE)
1066         {
1067           block_input ();
1068           [view handleFS];
1069           unblock_input ();
1070         }
1071     }
1075 void
1076 x_make_frame_invisible (struct frame *f)
1077 /* --------------------------------------------------------------------------
1078      External: Hide the window (X11 semantics)
1079    -------------------------------------------------------------------------- */
1081   NSView *view;
1082   NSTRACE (x_make_frame_invisible);
1083   check_window_system (f);
1084   view = FRAME_NS_VIEW (f);
1085   [[view window] orderOut: NSApp];
1086   SET_FRAME_VISIBLE (f, 0);
1087   SET_FRAME_ICONIFIED (f, 0);
1091 void
1092 x_iconify_frame (struct frame *f)
1093 /* --------------------------------------------------------------------------
1094      External: Iconify window
1095    -------------------------------------------------------------------------- */
1097   NSView *view;
1098   struct ns_display_info *dpyinfo;
1100   NSTRACE (x_iconify_frame);
1101   check_window_system (f);
1102   view = FRAME_NS_VIEW (f);
1103   dpyinfo = FRAME_DISPLAY_INFO (f);
1105   if (dpyinfo->x_highlight_frame == f)
1106     dpyinfo->x_highlight_frame = 0;
1108   if ([[view window] windowNumber] <= 0)
1109     {
1110       /* the window is still deferred.  Make it very small, bring it
1111          on screen and order it out. */
1112       NSRect s = { { 100, 100}, {0, 0} };
1113       NSRect t;
1114       t = [[view window] frame];
1115       [[view window] setFrame: s display: NO];
1116       [[view window] orderBack: NSApp];
1117       [[view window] orderOut: NSApp];
1118       [[view window] setFrame: t display: NO];
1119     }
1120   [[view window] miniaturize: NSApp];
1123 /* Free X resources of frame F.  */
1125 void
1126 x_free_frame_resources (struct frame *f)
1128   NSView *view;
1129   struct ns_display_info *dpyinfo;
1130   Mouse_HLInfo *hlinfo;
1132   NSTRACE (x_free_frame_resources);
1133   check_window_system (f);
1134   view = FRAME_NS_VIEW (f);
1135   dpyinfo = FRAME_DISPLAY_INFO (f);
1136   hlinfo = MOUSE_HL_INFO (f);
1138   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1140   block_input ();
1142   free_frame_menubar (f);
1144   if (FRAME_FACE_CACHE (f))
1145     free_frame_faces (f);
1147   if (f == dpyinfo->x_focus_frame)
1148     dpyinfo->x_focus_frame = 0;
1149   if (f == dpyinfo->x_highlight_frame)
1150     dpyinfo->x_highlight_frame = 0;
1151   if (f == hlinfo->mouse_face_mouse_frame)
1152     reset_mouse_highlight (hlinfo);
1154   if (f->output_data.ns->miniimage != nil)
1155     [f->output_data.ns->miniimage release];
1157   [[view window] close];
1158   [view release];
1160   xfree (f->output_data.ns);
1162   unblock_input ();
1165 void
1166 x_destroy_window (struct frame *f)
1167 /* --------------------------------------------------------------------------
1168      External: Delete the window
1169    -------------------------------------------------------------------------- */
1171   NSTRACE (x_destroy_window);
1172   check_window_system (f);
1173   x_free_frame_resources (f);
1174   ns_window_num--;
1178 void
1179 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1180 /* --------------------------------------------------------------------------
1181      External: Position the window
1182    -------------------------------------------------------------------------- */
1184   NSView *view = FRAME_NS_VIEW (f);
1185   NSArray *screens = [NSScreen screens];
1186   NSScreen *fscreen = [screens objectAtIndex: 0];
1187   NSScreen *screen = [[view window] screen];
1189   NSTRACE (x_set_offset);
1191   block_input ();
1193   f->left_pos = xoff;
1194   f->top_pos = yoff;
1196   if (view != nil && screen && fscreen)
1197     {
1198       f->left_pos = f->size_hint_flags & XNegative
1199         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1200         : f->left_pos;
1201       /* We use visibleFrame here to take menu bar into account.
1202          Ideally we should also adjust left/top with visibleFrame.origin.  */
1204       f->top_pos = f->size_hint_flags & YNegative
1205         ? ([screen visibleFrame].size.height + f->top_pos
1206            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1207            - FRAME_TOOLBAR_HEIGHT (f))
1208         : f->top_pos;
1209 #ifdef NS_IMPL_GNUSTEP
1210       if (f->left_pos < 100)
1211         f->left_pos = 100;  /* don't overlap menu */
1212 #endif
1213       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1214          menu bar.  */
1215       f->output_data.ns->dont_constrain = 0;
1216       [[view window] setFrameTopLeftPoint:
1217                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1218                                     SCREENMAXBOUND ([fscreen frame].size.height
1219                                                     - NS_TOP_POS (f)))];
1220       f->size_hint_flags &= ~(XNegative|YNegative);
1221     }
1223   unblock_input ();
1227 void
1228 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1229 /* --------------------------------------------------------------------------
1230      Adjust window pixel size based on given character grid size
1231      Impl is a bit more complex than other terms, need to do some
1232      internal clipping.
1233    -------------------------------------------------------------------------- */
1235   EmacsView *view = FRAME_NS_VIEW (f);
1236   NSWindow *window = [view window];
1237   NSRect wr = [window frame];
1238   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1239   int pixelwidth, pixelheight;
1241   NSTRACE (x_set_window_size);
1243   if (view == nil)
1244     return;
1246 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1248   block_input ();
1250   check_frame_size (f, &rows, &cols);
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 && ! [view isFullscreen])
1260     {
1261     /* NOTE: previously this would generate wrong result if toolbar not
1262              yet displayed and fixing toolbar_height=32 helped, but
1263              now (200903) seems no longer needed */
1264     FRAME_TOOLBAR_HEIGHT (f) =
1265       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1266         - FRAME_NS_TITLEBAR_HEIGHT (f);
1267 #ifdef NS_IMPL_GNUSTEP
1268       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1269 #endif
1270     }
1271   else
1272     FRAME_TOOLBAR_HEIGHT (f) = 0;
1274   wr.size.width = pixelwidth + f->border_width;
1275   wr.size.height = pixelheight;
1276   if (! [view isFullscreen])
1277     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1278       + FRAME_TOOLBAR_HEIGHT (f);
1280   /* Do not try to constrain to this screen.  We may have multiple
1281      screens, and want Emacs to span those.  Constraining to screen
1282      prevents that, and that is not nice to the user.  */
1283  if (f->output_data.ns->zooming)
1284    f->output_data.ns->zooming = 0;
1285  else
1286    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1288   [view setRows: rows andColumns: cols];
1289   [window setFrame: wr display: YES];
1291 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1293   /* This is a trick to compensate for Emacs' managing the scrollbar area
1294      as a fixed number of standard character columns.  Instead of leaving
1295      blank space for the extra, we chopped it off above.  Now for
1296      left-hand scrollbars, we shift all rendering to the left by the
1297      difference between the real width and Emacs' imagined one.  For
1298      right-hand bars, don't worry about it since the extra is never used.
1299      (Obviously doesn't work for vertically split windows tho..) */
1300   {
1301     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1302       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1303                      - NS_SCROLL_BAR_WIDTH (f), 0)
1304       : NSMakePoint (0, 0);
1305     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1306     [view setBoundsOrigin: origin];
1307   }
1309   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1310   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1311   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1312 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1314   mark_window_cursors_off (XWINDOW (f->root_window));
1315   cancel_mouse_face (f);
1317   unblock_input ();
1321 static void
1322 ns_fullscreen_hook (struct frame *f)
1324   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1326   if (!FRAME_VISIBLE_P (f))
1327     return;
1329    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1330     {
1331       /* Old style fs don't initiate correctly if created from
1332          init/default-frame alist, so use a timer (not nice...).
1333       */
1334       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1335                                      selector: @selector (handleFS)
1336                                      userInfo: nil repeats: NO];
1337       return;
1338     }
1340   block_input ();
1341   [view handleFS];
1342   unblock_input ();
1345 /* ==========================================================================
1347     Color management
1349    ========================================================================== */
1352 NSColor *
1353 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1355   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1356   if (idx < 1 || idx >= color_table->avail)
1357     return nil;
1358   return color_table->colors[idx];
1362 unsigned long
1363 ns_index_color (NSColor *color, struct frame *f)
1365   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1366   ptrdiff_t idx;
1367   ptrdiff_t i;
1369   if (!color_table->colors)
1370     {
1371       color_table->size = NS_COLOR_CAPACITY;
1372       color_table->avail = 1; /* skip idx=0 as marker */
1373       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1374       color_table->colors[0] = nil;
1375       color_table->empty_indices = [[NSMutableSet alloc] init];
1376     }
1378   /* do we already have this color ? */
1379   for (i = 1; i < color_table->avail; i++)
1380     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1381       return i;
1383   if ([color_table->empty_indices count] > 0)
1384     {
1385       NSNumber *index = [color_table->empty_indices anyObject];
1386       [color_table->empty_indices removeObject: index];
1387       idx = [index unsignedLongValue];
1388     }
1389   else
1390     {
1391       if (color_table->avail == color_table->size)
1392         color_table->colors =
1393           xpalloc (color_table->colors, &color_table->size, 1,
1394                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1395       idx = color_table->avail++;
1396     }
1398   color_table->colors[idx] = color;
1399   [color retain];
1400 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1401   return idx;
1405 void
1406 ns_free_indexed_color (unsigned long idx, struct frame *f)
1408   struct ns_color_table *color_table;
1409   NSColor *color;
1410   NSNumber *index;
1412   if (!f)
1413     return;
1415   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1417   if (idx <= 0 || idx >= color_table->size) {
1418     message1 ("ns_free_indexed_color: Color index out of range.\n");
1419     return;
1420   }
1422   index = [NSNumber numberWithUnsignedInt: idx];
1423   if ([color_table->empty_indices containsObject: index]) {
1424     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1425     return;
1426   }
1428   color = color_table->colors[idx];
1429   [color release];
1430   color_table->colors[idx] = nil;
1431   [color_table->empty_indices addObject: index];
1432 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1436 static int
1437 ns_get_color (const char *name, NSColor **col)
1438 /* --------------------------------------------------------------------------
1439      Parse a color name
1440    -------------------------------------------------------------------------- */
1441 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1442    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1443    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1445   NSColor *new = nil;
1446   static char hex[20];
1447   int scaling;
1448   float r = -1.0, g, b;
1449   NSString *nsname = [NSString stringWithUTF8String: name];
1451 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1452   block_input ();
1454 #ifdef NS_IMPL_COCOA
1455   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1456     {
1457       NSString *defname = [[NSUserDefaults standardUserDefaults]
1458                             stringForKey: @"AppleHighlightColor"];
1460       if (defname != nil)
1461         nsname = defname;
1462       else if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1463         {
1464           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1465           unblock_input ();
1466           return 0;
1467         }
1468       else
1469         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1471       name = [nsname UTF8String];
1472     }
1473   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1474     {
1475       /* NOTE: OSX applications normally don't set foreground selection, but
1476          text may be unreadable if we don't.
1477       */
1478       if ((new = [NSColor selectedTextColor]) != nil)
1479         {
1480           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1481           unblock_input ();
1482           return 0;
1483         }
1485       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1486       name = [nsname UTF8String];
1487     }
1488 #endif // NS_IMPL_COCOA
1490   /* First, check for some sort of numeric specification. */
1491   hex[0] = '\0';
1493   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1494     {
1495       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1496       [scanner scanFloat: &r];
1497       [scanner scanFloat: &g];
1498       [scanner scanFloat: &b];
1499     }
1500   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1501     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1502   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1503     {
1504       int len = (strlen(name) - 1);
1505       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1506       int i;
1507       scaling = strlen(name+start) / 3;
1508       for (i = 0; i < 3; i++)
1509         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1510                  name + start + i * scaling);
1511       hex[3 * (scaling + 1) - 1] = '\0';
1512     }
1514   if (hex[0])
1515     {
1516       int rr, gg, bb;
1517       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1518       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1519         {
1520           r = rr / fscale;
1521           g = gg / fscale;
1522           b = bb / fscale;
1523         }
1524     }
1526   if (r >= 0.0F)
1527     {
1528       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1529       unblock_input ();
1530       return 0;
1531     }
1533   /* Otherwise, color is expected to be from a list */
1534   {
1535     NSEnumerator *lenum, *cenum;
1536     NSString *name;
1537     NSColorList *clist;
1539 #ifdef NS_IMPL_GNUSTEP
1540     /* XXX: who is wrong, the requestor or the implementation? */
1541     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1542         == NSOrderedSame)
1543       nsname = @"highlightColor";
1544 #endif
1546     lenum = [[NSColorList availableColorLists] objectEnumerator];
1547     while ( (clist = [lenum nextObject]) && new == nil)
1548       {
1549         cenum = [[clist allKeys] objectEnumerator];
1550         while ( (name = [cenum nextObject]) && new == nil )
1551           {
1552             if ([name compare: nsname
1553                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1554               new = [clist colorWithKey: name];
1555           }
1556       }
1557   }
1559   if (new)
1560     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1561   unblock_input ();
1562   return new ? 0 : 1;
1567 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1568 /* --------------------------------------------------------------------------
1569      Convert a Lisp string object to a NS color
1570    -------------------------------------------------------------------------- */
1572   NSTRACE (ns_lisp_to_color);
1573   if (STRINGP (color))
1574     return ns_get_color (SSDATA (color), col);
1575   else if (SYMBOLP (color))
1576     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1577   return 1;
1581 Lisp_Object
1582 ns_color_to_lisp (NSColor *col)
1583 /* --------------------------------------------------------------------------
1584      Convert a color to a lisp string with the RGB equivalent
1585    -------------------------------------------------------------------------- */
1587   EmacsCGFloat red, green, blue, alpha, gray;
1588   char buf[1024];
1589   const char *str;
1590   NSTRACE (ns_color_to_lisp);
1592   block_input ();
1593   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1595       if ((str =[[col colorNameComponent] UTF8String]))
1596         {
1597           unblock_input ();
1598           return build_string ((char *)str);
1599         }
1601     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1602         getRed: &red green: &green blue: &blue alpha: &alpha];
1603   if (red ==green && red ==blue)
1604     {
1605       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1606             getWhite: &gray alpha: &alpha];
1607       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1608                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1609       unblock_input ();
1610       return build_string (buf);
1611     }
1613   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1614             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1616   unblock_input ();
1617   return build_string (buf);
1621 void
1622 ns_query_color(void *col, XColor *color_def, int setPixel)
1623 /* --------------------------------------------------------------------------
1624          Get ARGB values out of NSColor col and put them into color_def.
1625          If setPixel, set the pixel to a concatenated version.
1626          and set color_def pixel to the resulting index.
1627    -------------------------------------------------------------------------- */
1629   EmacsCGFloat r, g, b, a;
1631   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1632   color_def->red   = r * 65535;
1633   color_def->green = g * 65535;
1634   color_def->blue  = b * 65535;
1636   if (setPixel == YES)
1637     color_def->pixel
1638       = ARGB_TO_ULONG((int)(a*255),
1639                       (int)(r*255), (int)(g*255), (int)(b*255));
1643 bool
1644 ns_defined_color (struct frame *f,
1645                   const char *name,
1646                   XColor *color_def,
1647                   bool alloc,
1648                   bool makeIndex)
1649 /* --------------------------------------------------------------------------
1650          Return true if named color found, and set color_def rgb accordingly.
1651          If makeIndex and alloc are nonzero put the color in the color_table,
1652          and set color_def pixel to the resulting index.
1653          If makeIndex is zero, set color_def pixel to ARGB.
1654          Return false if not found
1655    -------------------------------------------------------------------------- */
1657   NSColor *col;
1658   NSTRACE (ns_defined_color);
1660   block_input ();
1661   if (ns_get_color (name, &col) != 0) /* Color not found  */
1662     {
1663       unblock_input ();
1664       return 0;
1665     }
1666   if (makeIndex && alloc)
1667     color_def->pixel = ns_index_color (col, f);
1668   ns_query_color (col, color_def, !makeIndex);
1669   unblock_input ();
1670   return 1;
1674 void
1675 x_set_frame_alpha (struct frame *f)
1676 /* --------------------------------------------------------------------------
1677      change the entire-frame transparency
1678    -------------------------------------------------------------------------- */
1680   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1681   double alpha = 1.0;
1682   double alpha_min = 1.0;
1684   if (dpyinfo->x_highlight_frame == f)
1685     alpha = f->alpha[0];
1686   else
1687     alpha = f->alpha[1];
1689   if (FLOATP (Vframe_alpha_lower_limit))
1690     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1691   else if (INTEGERP (Vframe_alpha_lower_limit))
1692     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1694   if (alpha < 0.0)
1695     return;
1696   else if (1.0 < alpha)
1697     alpha = 1.0;
1698   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1699     alpha = alpha_min;
1701 #ifdef NS_IMPL_COCOA
1702   {
1703     EmacsView *view = FRAME_NS_VIEW (f);
1704   [[view window] setAlphaValue: alpha];
1705   }
1706 #endif
1710 /* ==========================================================================
1712     Mouse handling
1714    ========================================================================== */
1717 void
1718 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1719 /* --------------------------------------------------------------------------
1720      Programmatically reposition mouse pointer in pixel coordinates
1721    -------------------------------------------------------------------------- */
1723   NSTRACE (x_set_mouse_pixel_position);
1724   ns_raise_frame (f);
1725 #if 0
1726   /* FIXME: this does not work, and what about GNUstep? */
1727 #ifdef NS_IMPL_COCOA
1728   [FRAME_NS_VIEW (f) lockFocus];
1729   PSsetmouse ((float)pix_x, (float)pix_y);
1730   [FRAME_NS_VIEW (f) unlockFocus];
1731 #endif
1732 #endif
1736 void
1737 x_set_mouse_position (struct frame *f, int h, int v)
1738 /* --------------------------------------------------------------------------
1739      Programmatically reposition mouse pointer in character coordinates
1740    -------------------------------------------------------------------------- */
1742   int pix_x, pix_y;
1744   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1745   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1747   if (pix_x < 0) pix_x = 0;
1748   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1750   if (pix_y < 0) pix_y = 0;
1751   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1753   x_set_mouse_pixel_position (f, pix_x, pix_y);
1757 static int
1758 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1759 /*   ------------------------------------------------------------------------
1760      Called by EmacsView on mouseMovement events.  Passes on
1761      to emacs mainstream code if we moved off of a rect of interest
1762      known as last_mouse_glyph.
1763      ------------------------------------------------------------------------ */
1765   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1766   NSRect *r;
1768 //  NSTRACE (note_mouse_movement);
1770   dpyinfo->last_mouse_motion_frame = frame;
1771   r = &dpyinfo->last_mouse_glyph;
1773   /* Note, this doesn't get called for enter/leave, since we don't have a
1774      position.  Those are taken care of in the corresponding NSView methods. */
1776   /* has movement gone beyond last rect we were tracking? */
1777   if (x < r->origin.x || x >= r->origin.x + r->size.width
1778       || y < r->origin.y || y >= r->origin.y + r->size.height)
1779     {
1780       ns_update_begin (frame);
1781       frame->mouse_moved = 1;
1782       note_mouse_highlight (frame, x, y);
1783       remember_mouse_glyph (frame, x, y, r);
1784       ns_update_end (frame);
1785       return 1;
1786     }
1788   return 0;
1792 static void
1793 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1794                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1795                    Time *time)
1796 /* --------------------------------------------------------------------------
1797     External (hook): inform emacs about mouse position and hit parts.
1798     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1799     x & y should be position in the scrollbar (the whole bar, not the handle)
1800     and length of scrollbar respectively
1801    -------------------------------------------------------------------------- */
1803   id view;
1804   NSPoint position;
1805   Lisp_Object frame, tail;
1806   struct frame *f;
1807   struct ns_display_info *dpyinfo;
1809   NSTRACE (ns_mouse_position);
1811   if (*fp == NULL)
1812     {
1813       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1814       return;
1815     }
1817   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1819   block_input ();
1821   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1822     {
1823       /* TODO: we do not use this path at the moment because drag events will
1824            go directly to the EmacsScroller.  Leaving code in for now. */
1825       [dpyinfo->last_mouse_scroll_bar
1826           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1827       if (time)
1828         *time = dpyinfo->last_mouse_movement_time;
1829       dpyinfo->last_mouse_scroll_bar = nil;
1830     }
1831   else
1832     {
1833       /* Clear the mouse-moved flag for every frame on this display.  */
1834       FOR_EACH_FRAME (tail, frame)
1835         if (FRAME_NS_P (XFRAME (frame))
1836             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1837           XFRAME (frame)->mouse_moved = 0;
1839       dpyinfo->last_mouse_scroll_bar = nil;
1840       if (dpyinfo->last_mouse_frame
1841           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1842         f = dpyinfo->last_mouse_frame;
1843       else
1844         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1845                                     : SELECTED_FRAME ();
1847       if (f && FRAME_NS_P (f))
1848         {
1849           view = FRAME_NS_VIEW (*fp);
1851           position = [[view window] mouseLocationOutsideOfEventStream];
1852           position = [view convertPoint: position fromView: nil];
1853           remember_mouse_glyph (f, position.x, position.y,
1854                                 &dpyinfo->last_mouse_glyph);
1855 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1857           if (bar_window) *bar_window = Qnil;
1858           if (part) *part = 0; /*scroll_bar_handle; */
1860           if (x) XSETINT (*x, lrint (position.x));
1861           if (y) XSETINT (*y, lrint (position.y));
1862           if (time)
1863             *time = dpyinfo->last_mouse_movement_time;
1864           *fp = f;
1865         }
1866     }
1868   unblock_input ();
1872 static void
1873 ns_frame_up_to_date (struct frame *f)
1874 /* --------------------------------------------------------------------------
1875     External (hook): Fix up mouse highlighting right after a full update.
1876     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1877    -------------------------------------------------------------------------- */
1879   NSTRACE (ns_frame_up_to_date);
1881   if (FRAME_NS_P (f))
1882     {
1883       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1884       if (f == hlinfo->mouse_face_mouse_frame)
1885         {
1886           block_input ();
1887           ns_update_begin(f);
1888           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1889                                 hlinfo->mouse_face_mouse_x,
1890                                 hlinfo->mouse_face_mouse_y);
1891           ns_update_end(f);
1892           unblock_input ();
1893         }
1894     }
1898 static void
1899 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1900 /* --------------------------------------------------------------------------
1901     External (RIF): set frame mouse pointer type.
1902    -------------------------------------------------------------------------- */
1904   NSTRACE (ns_define_frame_cursor);
1905   if (FRAME_POINTER_TYPE (f) != cursor)
1906     {
1907       EmacsView *view = FRAME_NS_VIEW (f);
1908       FRAME_POINTER_TYPE (f) = cursor;
1909       [[view window] invalidateCursorRectsForView: view];
1910       /* Redisplay assumes this function also draws the changed frame
1911          cursor, but this function doesn't, so do it explicitly.  */
1912       x_update_cursor (f, 1);
1913     }
1918 /* ==========================================================================
1920     Keyboard handling
1922    ========================================================================== */
1925 static unsigned
1926 ns_convert_key (unsigned code)
1927 /* --------------------------------------------------------------------------
1928     Internal call used by NSView-keyDown.
1929    -------------------------------------------------------------------------- */
1931   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1932                                 / sizeof (convert_ns_to_X_keysym[0]));
1933   unsigned keysym;
1934   /* An array would be faster, but less easy to read. */
1935   for (keysym = 0; keysym < last_keysym; keysym += 2)
1936     if (code == convert_ns_to_X_keysym[keysym])
1937       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1938   return 0;
1939 /* if decide to use keyCode and Carbon table, use this line:
1940      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1944 char *
1945 x_get_keysym_name (int keysym)
1946 /* --------------------------------------------------------------------------
1947     Called by keyboard.c.  Not sure if the return val is important, except
1948     that it be unique.
1949    -------------------------------------------------------------------------- */
1951   static char value[16];
1952   NSTRACE (x_get_keysym_name);
1953   sprintf (value, "%d", keysym);
1954   return value;
1959 /* ==========================================================================
1961     Block drawing operations
1963    ========================================================================== */
1966 static void
1967 ns_redraw_scroll_bars (struct frame *f)
1969   int i;
1970   id view;
1971   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1972   NSTRACE (ns_redraw_scroll_bars);
1973   for (i =[subviews count]-1; i >= 0; i--)
1974     {
1975       view = [subviews objectAtIndex: i];
1976       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1977       [view display];
1978     }
1982 void
1983 ns_clear_frame (struct frame *f)
1984 /* --------------------------------------------------------------------------
1985       External (hook): Erase the entire frame
1986    -------------------------------------------------------------------------- */
1988   NSView *view = FRAME_NS_VIEW (f);
1989   NSRect r;
1991   NSTRACE (ns_clear_frame);
1993  /* comes on initial frame because we have
1994     after-make-frame-functions = select-frame */
1995  if (!FRAME_DEFAULT_FACE (f))
1996    return;
1998   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2000   r = [view bounds];
2002   block_input ();
2003   ns_focus (f, &r, 1);
2004   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2005   NSRectFill (r);
2006   ns_unfocus (f);
2008   /* as of 2006/11 or so this is now needed */
2009   ns_redraw_scroll_bars (f);
2010   unblock_input ();
2014 static void
2015 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2016 /* --------------------------------------------------------------------------
2017     External (RIF):  Clear section of frame
2018    -------------------------------------------------------------------------- */
2020   NSRect r = NSMakeRect (x, y, width, height);
2021   NSView *view = FRAME_NS_VIEW (f);
2022   struct face *face = FRAME_DEFAULT_FACE (f);
2024   if (!view || !face)
2025     return;
2027   NSTRACE (ns_clear_frame_area);
2029   r = NSIntersectionRect (r, [view frame]);
2030   ns_focus (f, &r, 1);
2031   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2033   NSRectFill (r);
2035   ns_unfocus (f);
2036   return;
2040 static void
2041 ns_scroll_run (struct window *w, struct run *run)
2042 /* --------------------------------------------------------------------------
2043     External (RIF):  Insert or delete n lines at line vpos
2044    -------------------------------------------------------------------------- */
2046   struct frame *f = XFRAME (w->frame);
2047   int x, y, width, height, from_y, to_y, bottom_y;
2049   NSTRACE (ns_scroll_run);
2051   /* begin copy from other terms */
2052   /* Get frame-relative bounding box of the text display area of W,
2053      without mode lines.  Include in this box the left and right
2054      fringe of W.  */
2055   window_box (w, ANY_AREA, &x, &y, &width, &height);
2057   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2058   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2059   bottom_y = y + height;
2061   if (to_y < from_y)
2062     {
2063       /* Scrolling up.  Make sure we don't copy part of the mode
2064          line at the bottom.  */
2065       if (from_y + run->height > bottom_y)
2066         height = bottom_y - from_y;
2067       else
2068         height = run->height;
2069     }
2070   else
2071     {
2072       /* Scrolling down.  Make sure we don't copy over the mode line.
2073          at the bottom.  */
2074       if (to_y + run->height > bottom_y)
2075         height = bottom_y - to_y;
2076       else
2077         height = run->height;
2078     }
2079   /* end copy from other terms */
2081   if (height == 0)
2082       return;
2084   block_input ();
2086   x_clear_cursor (w);
2088   {
2089     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2090     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2091     NSPoint dstOrigin = NSMakePoint (x, to_y);
2093     ns_focus (f, &dstRect, 1);
2094     NSCopyBits (0, srcRect , dstOrigin);
2095     ns_unfocus (f);
2096   }
2098   unblock_input ();
2102 static void
2103 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2104 /* --------------------------------------------------------------------------
2105     External (RIF): preparatory to fringe update after text was updated
2106    -------------------------------------------------------------------------- */
2108   struct frame *f;
2109   int width, height;
2111   NSTRACE (ns_after_update_window_line);
2113   /* begin copy from other terms */
2114   eassert (w);
2116   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2117     desired_row->redraw_fringe_bitmaps_p = 1;
2119   /* When a window has disappeared, make sure that no rest of
2120      full-width rows stays visible in the internal border.  */
2121   if (windows_or_buffers_changed
2122       && desired_row->full_width_p
2123       && (f = XFRAME (w->frame),
2124           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2125           width != 0)
2126       && (height = desired_row->visible_height,
2127           height > 0))
2128     {
2129       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2131       block_input ();
2132       ns_clear_frame_area (f, 0, y, width, height);
2133       ns_clear_frame_area (f,
2134                            FRAME_PIXEL_WIDTH (f) - width,
2135                            y, width, height);
2136       unblock_input ();
2137     }
2141 static void
2142 ns_shift_glyphs_for_insert (struct frame *f,
2143                            int x, int y, int width, int height,
2144                            int shift_by)
2145 /* --------------------------------------------------------------------------
2146     External (RIF): copy an area horizontally, don't worry about clearing src
2147    -------------------------------------------------------------------------- */
2149   NSRect srcRect = NSMakeRect (x, y, width, height);
2150   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2151   NSPoint dstOrigin = dstRect.origin;
2153   NSTRACE (ns_shift_glyphs_for_insert);
2155   ns_focus (f, &dstRect, 1);
2156   NSCopyBits (0, srcRect, dstOrigin);
2157   ns_unfocus (f);
2162 /* ==========================================================================
2164     Character encoding and metrics
2166    ========================================================================== */
2169 static void
2170 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2171 /* --------------------------------------------------------------------------
2172      External (RIF); compute left/right overhang of whole string and set in s
2173    -------------------------------------------------------------------------- */
2175   struct font *font = s->font;
2177   if (s->char2b)
2178     {
2179       struct font_metrics metrics;
2180       unsigned int codes[2];
2181       codes[0] = *(s->char2b);
2182       codes[1] = *(s->char2b + s->nchars - 1);
2184       font->driver->text_extents (font, codes, 2, &metrics);
2185       s->left_overhang = -metrics.lbearing;
2186       s->right_overhang
2187         = metrics.rbearing > metrics.width
2188         ? metrics.rbearing - metrics.width : 0;
2189     }
2190   else
2191     {
2192       s->left_overhang = 0;
2193       if (EQ (font->driver->type, Qns))
2194         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2195           FONT_HEIGHT (font) * 0.2 : 0;
2196       else
2197         s->right_overhang = 0;
2198     }
2203 /* ==========================================================================
2205     Fringe and cursor drawing
2207    ========================================================================== */
2210 extern int max_used_fringe_bitmap;
2211 static void
2212 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2213                       struct draw_fringe_bitmap_params *p)
2214 /* --------------------------------------------------------------------------
2215     External (RIF); fringe-related
2216    -------------------------------------------------------------------------- */
2218   struct frame *f = XFRAME (WINDOW_FRAME (w));
2219   struct face *face = p->face;
2220   static EmacsImage **bimgs = NULL;
2221   static int nBimgs = 0;
2223   /* grow bimgs if needed */
2224   if (nBimgs < max_used_fringe_bitmap)
2225     {
2226       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2227       memset (bimgs + nBimgs, 0,
2228               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2229       nBimgs = max_used_fringe_bitmap;
2230     }
2232   /* Must clip because of partially visible lines.  */
2233   ns_clip_to_row (w, row, ANY_AREA, YES);
2235   if (!p->overlay_p)
2236     {
2237       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2239       /* If the fringe is adjacent to the left (right) scroll bar of a
2240          leftmost (rightmost, respectively) window, then extend its
2241          background to the gap between the fringe and the bar.  */
2242       if ((WINDOW_LEFTMOST_P (w)
2243            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2244           || (WINDOW_RIGHTMOST_P (w)
2245               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2246         {
2247           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2249           if (sb_width > 0)
2250             {
2251               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2252               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2253                                     * FRAME_COLUMN_WIDTH (f));
2255               if (bx < 0)
2256                 {
2257                   /* Bitmap fills the fringe.  */
2258                   if (bar_area_x + bar_area_width == p->x)
2259                     bx = bar_area_x + sb_width;
2260                   else if (p->x + p->wd == bar_area_x)
2261                     bx = bar_area_x;
2262                   if (bx >= 0)
2263                     {
2264                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2266                       nx = bar_area_width - sb_width;
2267                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2268                                                             row->y));
2269                       ny = row->visible_height;
2270                     }
2271                 }
2272               else
2273                 {
2274                   if (bar_area_x + bar_area_width == bx)
2275                     {
2276                       bx = bar_area_x + sb_width;
2277                       nx += bar_area_width - sb_width;
2278                     }
2279                   else if (bx + nx == bar_area_x)
2280                     nx += bar_area_width - sb_width;
2281                 }
2282             }
2283         }
2285       if (bx >= 0 && nx > 0)
2286         {
2287           NSRect r = NSMakeRect (bx, by, nx, ny);
2288           NSRectClip (r);
2289           [ns_lookup_indexed_color (face->background, f) set];
2290           NSRectFill (r);
2291         }
2292     }
2294   if (p->which)
2295     {
2296       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2297       EmacsImage *img = bimgs[p->which - 1];
2299       if (!img)
2300         {
2301           unsigned short *bits = p->bits + p->dh;
2302           int len = p->h;
2303           int i;
2304           unsigned char *cbits = xmalloc (len);
2306           for (i = 0; i < len; i++)
2307             cbits[i] = ~(bits[i] & 0xff);
2308           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2309                                            flip: NO];
2310           bimgs[p->which - 1] = img;
2311           xfree (cbits);
2312         }
2314       NSRectClip (r);
2315       /* Since we composite the bitmap instead of just blitting it, we need
2316          to erase the whole background. */
2317       [ns_lookup_indexed_color(face->background, f) set];
2318       NSRectFill (r);
2319       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2320 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2321       [img drawInRect: r
2322               fromRect: NSZeroRect
2323              operation: NSCompositeSourceOver
2324               fraction: 1.0
2325            respectFlipped: YES
2326                 hints: nil];
2327 #else
2328       {
2329         NSPoint pt = r.origin;
2330         pt.y += p->h;
2331         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2332       }
2333 #endif
2334     }
2335   ns_unfocus (f);
2339 static void
2340 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2341                        int x, int y, enum text_cursor_kinds cursor_type,
2342                        int cursor_width, bool on_p, bool active_p)
2343 /* --------------------------------------------------------------------------
2344      External call (RIF): draw cursor.
2345      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2346    -------------------------------------------------------------------------- */
2348   NSRect r, s;
2349   int fx, fy, h, cursor_height;
2350   struct frame *f = WINDOW_XFRAME (w);
2351   struct glyph *phys_cursor_glyph;
2352   struct glyph *cursor_glyph;
2353   struct face *face;
2354   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2356   /* If cursor is out of bounds, don't draw garbage.  This can happen
2357      in mini-buffer windows when switching between echo area glyphs
2358      and mini-buffer.  */
2360   NSTRACE (dumpcursor);
2362   if (!on_p)
2363     return;
2365   w->phys_cursor_type = cursor_type;
2366   w->phys_cursor_on_p = on_p;
2368   if (cursor_type == NO_CURSOR)
2369     {
2370       w->phys_cursor_width = 0;
2371       return;
2372     }
2374   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2375     {
2376       if (glyph_row->exact_window_width_line_p
2377           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2378         {
2379           glyph_row->cursor_in_fringe_p = 1;
2380           draw_fringe_bitmap (w, glyph_row, 0);
2381         }
2382       return;
2383     }
2385   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2386      (other terminals do it the other way round).  We must set
2387      w->phys_cursor_width to the cursor width.  For bar cursors, that
2388      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2389   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2391   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2392      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2393   if (cursor_type == BAR_CURSOR)
2394     {
2395       if (cursor_width < 1)
2396         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2397       w->phys_cursor_width = cursor_width;
2398     }
2399   /* If we have an HBAR, "cursor_width" MAY specify height. */
2400   else if (cursor_type == HBAR_CURSOR)
2401     {
2402       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2403       fy += h - cursor_height;
2404       h = cursor_height;
2405     }
2407   r.origin.x = fx, r.origin.y = fy;
2408   r.size.height = h;
2409   r.size.width = w->phys_cursor_width;
2411   /* TODO: only needed in rare cases with last-resort font in HELLO..
2412      should we do this more efficiently? */
2413   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2416   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2417   if (face && NS_FACE_BACKGROUND (face)
2418       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2419     {
2420       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2421       hollow_color = FRAME_CURSOR_COLOR (f);
2422     }
2423   else
2424     [FRAME_CURSOR_COLOR (f) set];
2426 #ifdef NS_IMPL_COCOA
2427   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2428            atomic.  Cleaner ways of doing this should be investigated.
2429            One way would be to set a global variable DRAWING_CURSOR
2430            when making the call to draw_phys..(), don't focus in that
2431            case, then move the ns_unfocus() here after that call. */
2432   NSDisableScreenUpdates ();
2433 #endif
2435   switch (cursor_type)
2436     {
2437     case NO_CURSOR:
2438       break;
2439     case FILLED_BOX_CURSOR:
2440       NSRectFill (r);
2441       break;
2442     case HOLLOW_BOX_CURSOR:
2443       NSRectFill (r);
2444       [hollow_color set];
2445       NSRectFill (NSInsetRect (r, 1, 1));
2446       [FRAME_CURSOR_COLOR (f) set];
2447       break;
2448     case HBAR_CURSOR:
2449       NSRectFill (r);
2450       break;
2451     case BAR_CURSOR:
2452       s = r;
2453       /* If the character under cursor is R2L, draw the bar cursor
2454          on the right of its glyph, rather than on the left.  */
2455       cursor_glyph = get_phys_cursor_glyph (w);
2456       if ((cursor_glyph->resolved_level & 1) != 0)
2457         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2459       NSRectFill (s);
2460       break;
2461     }
2462   ns_unfocus (f);
2464   /* draw the character under the cursor */
2465   if (cursor_type != NO_CURSOR)
2466     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2468 #ifdef NS_IMPL_COCOA
2469   NSEnableScreenUpdates ();
2470 #endif
2475 static void
2476 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2477 /* --------------------------------------------------------------------------
2478      External (RIF): Draw a vertical line.
2479    -------------------------------------------------------------------------- */
2481   struct frame *f = XFRAME (WINDOW_FRAME (w));
2482   struct face *face;
2483   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2485   NSTRACE (ns_draw_vertical_window_border);
2487   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2488   if (face)
2489       [ns_lookup_indexed_color(face->foreground, f) set];
2491   ns_focus (f, &r, 1);
2492   NSRectFill(r);
2493   ns_unfocus (f);
2497 void
2498 show_hourglass (struct atimer *timer)
2500   if (hourglass_shown_p)
2501     return;
2503   block_input ();
2505   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2507   hourglass_shown_p = 1;
2508   unblock_input ();
2512 void
2513 hide_hourglass (void)
2515   if (!hourglass_shown_p)
2516     return;
2518   block_input ();
2520   /* TODO: remove NSProgressIndicator from all frames */
2522   hourglass_shown_p = 0;
2523   unblock_input ();
2528 /* ==========================================================================
2530     Glyph drawing operations
2532    ========================================================================== */
2534 static int
2535 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2536 /* --------------------------------------------------------------------------
2537     Wrapper utility to account for internal border width on full-width lines,
2538     and allow top full-width rows to hit the frame top.  nr should be pointer
2539     to two successive NSRects.  Number of rects actually used is returned.
2540    -------------------------------------------------------------------------- */
2542   int n = get_glyph_string_clip_rects (s, nr, 2);
2543   return n;
2546 /* --------------------------------------------------------------------
2547    Draw a wavy line under glyph string s. The wave fills wave_height
2548    pixels from y.
2550                     x          wave_length = 2
2551                                  --
2552                 y    *   *   *   *   *
2553                      |* * * * * * * * *
2554     wave_height = 3  | *   *   *   *
2555   --------------------------------------------------------------------- */
2557 static void
2558 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2560   int wave_height = 3, wave_length = 2;
2561   int y, dx, dy, odd, xmax;
2562   NSPoint a, b;
2563   NSRect waveClip;
2565   dx = wave_length;
2566   dy = wave_height - 1;
2567   y =  s->ybase - wave_height + 3;
2568   xmax = x + width;
2570   /* Find and set clipping rectangle */
2571   waveClip = NSMakeRect (x, y, width, wave_height);
2572   [[NSGraphicsContext currentContext] saveGraphicsState];
2573   NSRectClip (waveClip);
2575   /* Draw the waves */
2576   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2577   b.x = a.x + dx;
2578   odd = (int)(a.x/dx) % 2;
2579   a.y = b.y = y + 0.5;
2581   if (odd)
2582     a.y += dy;
2583   else
2584     b.y += dy;
2586   while (a.x <= xmax)
2587     {
2588       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2589       a.x = b.x, a.y = b.y;
2590       b.x += dx, b.y = y + 0.5 + odd*dy;
2591       odd = !odd;
2592     }
2594   /* Restore previous clipping rectangle(s) */
2595   [[NSGraphicsContext currentContext] restoreGraphicsState];
2600 void
2601 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2602                          NSColor *defaultCol, CGFloat width, CGFloat x)
2603 /* --------------------------------------------------------------------------
2604    Draw underline, overline, and strike-through on glyph string s.
2605    -------------------------------------------------------------------------- */
2607   if (s->for_overlaps)
2608     return;
2610   /* Do underline. */
2611   if (face->underline_p)
2612     {
2613       if (s->face->underline_type == FACE_UNDER_WAVE)
2614         {
2615           if (face->underline_defaulted_p)
2616             [defaultCol set];
2617           else
2618             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2620           ns_draw_underwave (s, width, x);
2621         }
2622       else if (s->face->underline_type == FACE_UNDER_LINE)
2623         {
2625           NSRect r;
2626           unsigned long thickness, position;
2628           /* If the prev was underlined, match its appearance. */
2629           if (s->prev && s->prev->face->underline_p
2630               && s->prev->face->underline_type == FACE_UNDER_LINE
2631               && s->prev->underline_thickness > 0)
2632             {
2633               thickness = s->prev->underline_thickness;
2634               position = s->prev->underline_position;
2635             }
2636           else
2637             {
2638               struct font *font;
2639               unsigned long descent;
2641               font=s->font;
2642               descent = s->y + s->height - s->ybase;
2644               /* Use underline thickness of font, defaulting to 1. */
2645               thickness = (font && font->underline_thickness > 0)
2646                 ? font->underline_thickness : 1;
2648               /* Determine the offset of underlining from the baseline. */
2649               if (x_underline_at_descent_line)
2650                 position = descent - thickness;
2651               else if (x_use_underline_position_properties
2652                        && font && font->underline_position >= 0)
2653                 position = font->underline_position;
2654               else if (font)
2655                 position = lround (font->descent / 2);
2656               else
2657                 position = underline_minimum_offset;
2659               position = max (position, underline_minimum_offset);
2661               /* Ensure underlining is not cropped. */
2662               if (descent <= position)
2663                 {
2664                   position = descent - 1;
2665                   thickness = 1;
2666                 }
2667               else if (descent < position + thickness)
2668                 thickness = 1;
2669             }
2671           s->underline_thickness = thickness;
2672           s->underline_position = position;
2674           r = NSMakeRect (x, s->ybase + position, width, thickness);
2676           if (face->underline_defaulted_p)
2677             [defaultCol set];
2678           else
2679             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2680           NSRectFill (r);
2681         }
2682     }
2683   /* Do overline. We follow other terms in using a thickness of 1
2684      and ignoring overline_margin. */
2685   if (face->overline_p)
2686     {
2687       NSRect r;
2688       r = NSMakeRect (x, s->y, width, 1);
2690       if (face->overline_color_defaulted_p)
2691         [defaultCol set];
2692       else
2693         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2694       NSRectFill (r);
2695     }
2697   /* Do strike-through.  We follow other terms for thickness and
2698      vertical position.*/
2699   if (face->strike_through_p)
2700     {
2701       NSRect r;
2702       unsigned long dy;
2704       dy = lrint ((s->height - 1) / 2);
2705       r = NSMakeRect (x, s->y + dy, width, 1);
2707       if (face->strike_through_color_defaulted_p)
2708         [defaultCol set];
2709       else
2710         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2711       NSRectFill (r);
2712     }
2715 static void
2716 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2717              char left_p, char right_p)
2718 /* --------------------------------------------------------------------------
2719     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2720     Note we can't just use an NSDrawRect command, because of the possibility
2721     of some sides not being drawn, and because the rect will be filled.
2722    -------------------------------------------------------------------------- */
2724   NSRect s = r;
2725   [col set];
2727   /* top, bottom */
2728   s.size.height = thickness;
2729   NSRectFill (s);
2730   s.origin.y += r.size.height - thickness;
2731   NSRectFill (s);
2733   s.size.height = r.size.height;
2734   s.origin.y = r.origin.y;
2736   /* left, right (optional) */
2737   s.size.width = thickness;
2738   if (left_p)
2739     NSRectFill (s);
2740   if (right_p)
2741     {
2742       s.origin.x += r.size.width - thickness;
2743       NSRectFill (s);
2744     }
2748 static void
2749 ns_draw_relief (NSRect r, int thickness, char raised_p,
2750                char top_p, char bottom_p, char left_p, char right_p,
2751                struct glyph_string *s)
2752 /* --------------------------------------------------------------------------
2753     Draw a relief rect inside r, optionally leaving some sides open.
2754     Note we can't just use an NSDrawBezel command, because of the possibility
2755     of some sides not being drawn, and because the rect will be filled.
2756    -------------------------------------------------------------------------- */
2758   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2759   NSColor *newBaseCol = nil;
2760   NSRect sr = r;
2762   NSTRACE (ns_draw_relief);
2764   /* set up colors */
2766   if (s->face->use_box_color_for_shadows_p)
2767     {
2768       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2769     }
2770 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2771            && s->img->pixmap
2772            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2773        {
2774          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2775        } */
2776   else
2777     {
2778       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2779     }
2781   if (newBaseCol == nil)
2782     newBaseCol = [NSColor grayColor];
2784   if (newBaseCol != baseCol)  /* TODO: better check */
2785     {
2786       [baseCol release];
2787       baseCol = [newBaseCol retain];
2788       [lightCol release];
2789       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2790       [darkCol release];
2791       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2792     }
2794   [(raised_p ? lightCol : darkCol) set];
2796   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2798   /* top */
2799   sr.size.height = thickness;
2800   if (top_p) NSRectFill (sr);
2802   /* left */
2803   sr.size.height = r.size.height;
2804   sr.size.width = thickness;
2805   if (left_p) NSRectFill (sr);
2807   [(raised_p ? darkCol : lightCol) set];
2809   /* bottom */
2810   sr.size.width = r.size.width;
2811   sr.size.height = thickness;
2812   sr.origin.y += r.size.height - thickness;
2813   if (bottom_p) NSRectFill (sr);
2815   /* right */
2816   sr.size.height = r.size.height;
2817   sr.origin.y = r.origin.y;
2818   sr.size.width = thickness;
2819   sr.origin.x += r.size.width - thickness;
2820   if (right_p) NSRectFill (sr);
2824 static void
2825 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2826 /* --------------------------------------------------------------------------
2827       Function modeled after x_draw_glyph_string_box ().
2828       Sets up parameters for drawing.
2829    -------------------------------------------------------------------------- */
2831   int right_x, last_x;
2832   char left_p, right_p;
2833   struct glyph *last_glyph;
2834   NSRect r;
2835   int thickness;
2836   struct face *face;
2838   if (s->hl == DRAW_MOUSE_FACE)
2839     {
2840       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2841       if (!face)
2842         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2843     }
2844   else
2845     face = s->face;
2847   thickness = face->box_line_width;
2849   NSTRACE (ns_dumpglyphs_box_or_relief);
2851   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2852             ? WINDOW_RIGHT_EDGE_X (s->w)
2853             : window_box_right (s->w, s->area));
2854   last_glyph = (s->cmp || s->img
2855                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2857   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2858               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2860   left_p = (s->first_glyph->left_box_line_p
2861             || (s->hl == DRAW_MOUSE_FACE
2862                 && (s->prev == NULL || s->prev->hl != s->hl)));
2863   right_p = (last_glyph->right_box_line_p
2864              || (s->hl == DRAW_MOUSE_FACE
2865                  && (s->next == NULL || s->next->hl != s->hl)));
2867   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2869   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2870   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2871     {
2872       ns_draw_box (r, abs (thickness),
2873                    ns_lookup_indexed_color (face->box_color, s->f),
2874                   left_p, right_p);
2875     }
2876   else
2877     {
2878       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2879                      1, 1, left_p, right_p, s);
2880     }
2884 static void
2885 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2886 /* --------------------------------------------------------------------------
2887       Modeled after x_draw_glyph_string_background, which draws BG in
2888       certain cases.  Others are left to the text rendering routine.
2889    -------------------------------------------------------------------------- */
2891   NSTRACE (ns_maybe_dumpglyphs_background);
2893   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2894     {
2895       int box_line_width = max (s->face->box_line_width, 0);
2896       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2897           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2898         {
2899           struct face *face;
2900           if (s->hl == DRAW_MOUSE_FACE)
2901             {
2902               face = FACE_FROM_ID (s->f,
2903                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2904               if (!face)
2905                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2906             }
2907           else
2908             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2909           if (!face->stipple)
2910             [(NS_FACE_BACKGROUND (face) != 0
2911               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2912               : FRAME_BACKGROUND_COLOR (s->f)) set];
2913           else
2914             {
2915               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2916               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2917             }
2919           if (s->hl != DRAW_CURSOR)
2920             {
2921               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2922                                     s->background_width,
2923                                     s->height-2*box_line_width);
2924               NSRectFill (r);
2925             }
2927           s->background_filled_p = 1;
2928         }
2929     }
2933 static void
2934 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2935 /* --------------------------------------------------------------------------
2936       Renders an image and associated borders.
2937    -------------------------------------------------------------------------- */
2939   EmacsImage *img = s->img->pixmap;
2940   int box_line_vwidth = max (s->face->box_line_width, 0);
2941   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2942   int bg_x, bg_y, bg_height;
2943   int th;
2944   char raised_p;
2945   NSRect br;
2946   struct face *face;
2947   NSColor *tdCol;
2949   NSTRACE (ns_dumpglyphs_image);
2951   if (s->face->box != FACE_NO_BOX
2952       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2953     x += abs (s->face->box_line_width);
2955   bg_x = x;
2956   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2957   bg_height = s->height;
2958   /* other terms have this, but was causing problems w/tabbar mode */
2959   /* - 2 * box_line_vwidth; */
2961   if (s->slice.x == 0) x += s->img->hmargin;
2962   if (s->slice.y == 0) y += s->img->vmargin;
2964   /* Draw BG: if we need larger area than image itself cleared, do that,
2965      otherwise, since we composite the image under NS (instead of mucking
2966      with its background color), we must clear just the image area. */
2967   if (s->hl == DRAW_MOUSE_FACE)
2968     {
2969       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2970       if (!face)
2971        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2972     }
2973   else
2974     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2976   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2978   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2979       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2980     {
2981       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2982       s->background_filled_p = 1;
2983     }
2984   else
2985     {
2986       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2987     }
2989   NSRectFill (br);
2991   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2992   if (img != nil)
2993     {
2994 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2995       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2996       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2997                               s->slice.width, s->slice.height);
2998       [img drawInRect: dr
2999              fromRect: ir
3000              operation: NSCompositeSourceOver
3001               fraction: 1.0
3002            respectFlipped: YES
3003                 hints: nil];
3004 #else
3005       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3006                   operation: NSCompositeSourceOver];
3007 #endif
3008     }
3010   if (s->hl == DRAW_CURSOR)
3011     {
3012     [FRAME_CURSOR_COLOR (s->f) set];
3013     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3014       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3015     else
3016       /* Currently on NS img->mask is always 0. Since
3017          get_window_cursor_type specifies a hollow box cursor when on
3018          a non-masked image we never reach this clause. But we put it
3019          in in anticipation of better support for image masks on
3020          NS. */
3021       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3022     }
3023   else
3024     {
3025       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3026     }
3028   /* Draw underline, overline, strike-through. */
3029   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3031   /* Draw relief, if requested */
3032   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3033     {
3034       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3035         {
3036           th = tool_bar_button_relief >= 0 ?
3037             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3038           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3039         }
3040       else
3041         {
3042           th = abs (s->img->relief);
3043           raised_p = (s->img->relief > 0);
3044         }
3046       r.origin.x = x - th;
3047       r.origin.y = y - th;
3048       r.size.width = s->slice.width + 2*th-1;
3049       r.size.height = s->slice.height + 2*th-1;
3050       ns_draw_relief (r, th, raised_p,
3051                       s->slice.y == 0,
3052                       s->slice.y + s->slice.height == s->img->height,
3053                       s->slice.x == 0,
3054                       s->slice.x + s->slice.width == s->img->width, s);
3055     }
3057   /* If there is no mask, the background won't be seen,
3058      so draw a rectangle on the image for the cursor.
3059      Do this for all images, getting transparency right is not reliable.  */
3060   if (s->hl == DRAW_CURSOR)
3061     {
3062       int thickness = abs (s->img->relief);
3063       if (thickness == 0) thickness = 1;
3064       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3065     }
3069 static void
3070 ns_dumpglyphs_stretch (struct glyph_string *s)
3072   NSRect r[2];
3073   int n, i;
3074   struct face *face;
3075   NSColor *fgCol, *bgCol;
3077   if (!s->background_filled_p)
3078     {
3079       n = ns_get_glyph_string_clip_rect (s, r);
3080       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3082       ns_focus (s->f, r, n);
3084       if (s->hl == DRAW_MOUSE_FACE)
3085        {
3086          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3087          if (!face)
3088            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3089        }
3090       else
3091        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3093       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3094       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3096       for (i = 0; i < n; ++i)
3097         {
3098           if (!s->row->full_width_p)
3099             {
3100               int overrun, leftoverrun;
3102               /* truncate to avoid overwriting fringe and/or scrollbar */
3103               overrun = max (0, (s->x + s->background_width)
3104                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3105                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3106               r[i].size.width -= overrun;
3108               /* truncate to avoid overwriting to left of the window box */
3109               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3110                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3112               if (leftoverrun > 0)
3113                 {
3114                   r[i].origin.x += leftoverrun;
3115                   r[i].size.width -= leftoverrun;
3116                 }
3118               /* XXX: Try to work between problem where a stretch glyph on
3119                  a partially-visible bottom row will clear part of the
3120                  modeline, and another where list-buffers headers and similar
3121                  rows erroneously have visible_height set to 0.  Not sure
3122                  where this is coming from as other terms seem not to show. */
3123               r[i].size.height = min (s->height, s->row->visible_height);
3124             }
3126           [bgCol set];
3128           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3129              overwriting cursor (usually when cursor on a tab) */
3130           if (s->hl == DRAW_CURSOR)
3131             {
3132               CGFloat x, width;
3134               x = r[i].origin.x;
3135               width = s->w->phys_cursor_width;
3136               r[i].size.width -= width;
3137               r[i].origin.x += width;
3139               NSRectFill (r[i]);
3141               /* Draw overlining, etc. on the cursor. */
3142               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3143                 ns_draw_text_decoration (s, face, bgCol, width, x);
3144               else
3145                 ns_draw_text_decoration (s, face, fgCol, width, x);
3146             }
3147           else
3148             {
3149               NSRectFill (r[i]);
3150             }
3152           /* Draw overlining, etc. on the stretch glyph (or the part
3153              of the stretch glyph after the cursor). */
3154           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3155                                    r[i].origin.x);
3156         }
3157       ns_unfocus (s->f);
3158       s->background_filled_p = 1;
3159     }
3163 static void
3164 ns_draw_glyph_string (struct glyph_string *s)
3165 /* --------------------------------------------------------------------------
3166       External (RIF): Main draw-text call.
3167    -------------------------------------------------------------------------- */
3169   /* TODO (optimize): focus for box and contents draw */
3170   NSRect r[2];
3171   int n, flags;
3172   char box_drawn_p = 0;
3173   struct font *font = s->face->font;
3174   if (! font) font = FRAME_FONT (s->f);
3176   NSTRACE (ns_draw_glyph_string);
3178   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3179     {
3180       int width;
3181       struct glyph_string *next;
3183       for (width = 0, next = s->next;
3184            next && width < s->right_overhang;
3185            width += next->width, next = next->next)
3186         if (next->first_glyph->type != IMAGE_GLYPH)
3187           {
3188             if (next->first_glyph->type != STRETCH_GLYPH)
3189               {
3190                 n = ns_get_glyph_string_clip_rect (s->next, r);
3191                 ns_focus (s->f, r, n);
3192                 ns_maybe_dumpglyphs_background (s->next, 1);
3193                 ns_unfocus (s->f);
3194               }
3195             else
3196               {
3197                 ns_dumpglyphs_stretch (s->next);
3198               }
3199             next->num_clips = 0;
3200           }
3201     }
3203   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3204         && (s->first_glyph->type == CHAR_GLYPH
3205             || s->first_glyph->type == COMPOSITE_GLYPH))
3206     {
3207       n = ns_get_glyph_string_clip_rect (s, r);
3208       ns_focus (s->f, r, n);
3209       ns_maybe_dumpglyphs_background (s, 1);
3210       ns_dumpglyphs_box_or_relief (s);
3211       ns_unfocus (s->f);
3212       box_drawn_p = 1;
3213     }
3215   switch (s->first_glyph->type)
3216     {
3218     case IMAGE_GLYPH:
3219       n = ns_get_glyph_string_clip_rect (s, r);
3220       ns_focus (s->f, r, n);
3221       ns_dumpglyphs_image (s, r[0]);
3222       ns_unfocus (s->f);
3223       break;
3225     case STRETCH_GLYPH:
3226       ns_dumpglyphs_stretch (s);
3227       break;
3229     case CHAR_GLYPH:
3230     case COMPOSITE_GLYPH:
3231       n = ns_get_glyph_string_clip_rect (s, r);
3232       ns_focus (s->f, r, n);
3234       if (s->for_overlaps || (s->cmp_from > 0
3235                               && ! s->first_glyph->u.cmp.automatic))
3236         s->background_filled_p = 1;
3237       else
3238         ns_maybe_dumpglyphs_background
3239           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3241       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3242         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3243          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3244           NS_DUMPGLYPH_NORMAL));
3246       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3247         {
3248           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3249           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3250           NS_FACE_FOREGROUND (s->face) = tmp;
3251         }
3253       font->driver->draw
3254         (s, 0, s->nchars, s->x, s->y,
3255          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3256          || flags == NS_DUMPGLYPH_MOUSEFACE);
3258       {
3259         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3260                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3261                                                    s->f)
3262                         : FRAME_FOREGROUND_COLOR (s->f));
3263         [col set];
3265         /* Draw underline, overline, strike-through. */
3266         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3267       }
3269       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3270         {
3271           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3272           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3273           NS_FACE_FOREGROUND (s->face) = tmp;
3274         }
3276       ns_unfocus (s->f);
3277       break;
3279     case GLYPHLESS_GLYPH:
3280       n = ns_get_glyph_string_clip_rect (s, r);
3281       ns_focus (s->f, r, n);
3283       if (s->for_overlaps || (s->cmp_from > 0
3284                               && ! s->first_glyph->u.cmp.automatic))
3285         s->background_filled_p = 1;
3286       else
3287         ns_maybe_dumpglyphs_background
3288           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3289       /* ... */
3290       /* Not yet implemented.  */
3291       /* ... */
3292       ns_unfocus (s->f);
3293       break;
3295     default:
3296       emacs_abort ();
3297     }
3299   /* Draw box if not done already. */
3300   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3301     {
3302       n = ns_get_glyph_string_clip_rect (s, r);
3303       ns_focus (s->f, r, n);
3304       ns_dumpglyphs_box_or_relief (s);
3305       ns_unfocus (s->f);
3306     }
3308   s->num_clips = 0;
3313 /* ==========================================================================
3315     Event loop
3317    ========================================================================== */
3320 static void
3321 ns_send_appdefined (int value)
3322 /* --------------------------------------------------------------------------
3323     Internal: post an appdefined event which EmacsApp-sendEvent will
3324               recognize and take as a command to halt the event loop.
3325    -------------------------------------------------------------------------- */
3327   /*NSTRACE (ns_send_appdefined); */
3329 #ifdef NS_IMPL_GNUSTEP
3330   // GNUStep needs postEvent to happen on the main thread.
3331   if (! [[NSThread currentThread] isMainThread])
3332     {
3333       EmacsApp *app = (EmacsApp *)NSApp;
3334       app->nextappdefined = value;
3335       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3336                             withObject:nil
3337                          waitUntilDone:YES];
3338       return;
3339     }
3340 #endif
3342   /* Only post this event if we haven't already posted one.  This will end
3343        the [NXApp run] main loop after having processed all events queued at
3344        this moment.  */
3345   if (send_appdefined)
3346     {
3347       NSEvent *nxev;
3349       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3350       send_appdefined = NO;
3352       /* Don't need wakeup timer any more */
3353       if (timed_entry)
3354         {
3355           [timed_entry invalidate];
3356           [timed_entry release];
3357           timed_entry = nil;
3358         }
3360       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3361                                 location: NSMakePoint (0, 0)
3362                            modifierFlags: 0
3363                                timestamp: 0
3364                             windowNumber: [[NSApp mainWindow] windowNumber]
3365                                  context: [NSApp context]
3366                                  subtype: 0
3367                                    data1: value
3368                                    data2: 0];
3370       /* Post an application defined event on the event queue.  When this is
3371          received the [NXApp run] will return, thus having processed all
3372          events which are currently queued.  */
3373       [NSApp postEvent: nxev atStart: NO];
3374     }
3377 #ifdef HAVE_NATIVE_FS
3378 static void
3379 check_native_fs ()
3381   Lisp_Object frame, tail;
3383   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3384     return;
3386   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3388   /* Clear the mouse-moved flag for every frame on this display.  */
3389   FOR_EACH_FRAME (tail, frame)
3390     {
3391       struct frame *f = XFRAME (frame);
3392       if (FRAME_NS_P (f))
3393         {
3394           EmacsView *view = FRAME_NS_VIEW (f);
3395           [view updateCollectionBehaviour];
3396         }
3397     }
3399 #endif
3401 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3402 #if defined (NS_IMPL_COCOA) && \
3403   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3404 /* Check if menu open should be cancelled or continued as normal.  */
3405 void
3406 ns_check_menu_open (NSMenu *menu)
3408   /* Click in menu bar? */
3409   NSArray *a = [[NSApp mainMenu] itemArray];
3410   int i;
3411   BOOL found = NO;
3413   if (menu == nil) // Menu tracking ended.
3414     {
3415       if (menu_will_open_state == MENU_OPENING)
3416         menu_will_open_state = MENU_NONE;
3417       return;
3418     }
3420   for (i = 0; ! found && i < [a count]; i++)
3421     found = menu == [[a objectAtIndex:i] submenu];
3422   if (found)
3423     {
3424       if (menu_will_open_state == MENU_NONE && emacs_event)
3425         {
3426           NSEvent *theEvent = [NSApp currentEvent];
3427           struct frame *emacsframe = SELECTED_FRAME ();
3429           [menu cancelTracking];
3430           menu_will_open_state = MENU_PENDING;
3431           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3432           EV_TRAILER (theEvent);
3434           CGEventRef ourEvent = CGEventCreate (NULL);
3435           menu_mouse_point = CGEventGetLocation (ourEvent);
3436           CFRelease (ourEvent);
3437         }
3438       else if (menu_will_open_state == MENU_OPENING)
3439         {
3440           menu_will_open_state = MENU_NONE;
3441         }
3442     }
3445 /* Redo saved menu click if state is MENU_PENDING.  */
3446 void
3447 ns_check_pending_open_menu ()
3449   if (menu_will_open_state == MENU_PENDING)
3450     {
3451       CGEventSourceRef source
3452         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3454       CGEventRef event = CGEventCreateMouseEvent (source,
3455                                                   kCGEventLeftMouseDown,
3456                                                   menu_mouse_point,
3457                                                   kCGMouseButtonLeft);
3458       CGEventSetType (event, kCGEventLeftMouseDown);
3459       CGEventPost (kCGHIDEventTap, event);
3460       CFRelease (event);
3461       CFRelease (source);
3463       menu_will_open_state = MENU_OPENING;
3464     }
3466 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3468 static int
3469 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3470 /* --------------------------------------------------------------------------
3471      External (hook): Post an event to ourself and keep reading events until
3472      we read it back again.  In effect process all events which were waiting.
3473      From 21+ we have to manage the event buffer ourselves.
3474    -------------------------------------------------------------------------- */
3476   struct input_event ev;
3477   int nevents;
3479 /* NSTRACE (ns_read_socket); */
3481 #ifdef HAVE_NATIVE_FS
3482   check_native_fs ();
3483 #endif
3485   if ([NSApp modalWindow] != nil)
3486     return -1;
3488   if (hold_event_q.nr > 0)
3489     {
3490       int i;
3491       for (i = 0; i < hold_event_q.nr; ++i)
3492         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3493       hold_event_q.nr = 0;
3494       return i;
3495     }
3497   block_input ();
3498   n_emacs_events_pending = 0;
3499   EVENT_INIT (ev);
3500   emacs_event = &ev;
3501   q_event_ptr = hold_quit;
3503   /* we manage autorelease pools by allocate/reallocate each time around
3504      the loop; strict nesting is occasionally violated but seems not to
3505      matter.. earlier methods using full nesting caused major memory leaks */
3506   [outerpool release];
3507   outerpool = [[NSAutoreleasePool alloc] init];
3509   /* If have pending open-file requests, attend to the next one of those. */
3510   if (ns_pending_files && [ns_pending_files count] != 0
3511       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3512     {
3513       [ns_pending_files removeObjectAtIndex: 0];
3514     }
3515   /* Deal with pending service requests. */
3516   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3517     && [(EmacsApp *)
3518          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3519                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3520     {
3521       [ns_pending_service_names removeObjectAtIndex: 0];
3522       [ns_pending_service_args removeObjectAtIndex: 0];
3523     }
3524   else
3525     {
3526       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3527          to ourself, otherwise [NXApp run] will never exit.  */
3528       send_appdefined = YES;
3529       ns_send_appdefined (-1);
3531       if (++apploopnr != 1)
3532         {
3533           emacs_abort ();
3534         }
3535       [NSApp run];
3536       --apploopnr;
3537     }
3539   nevents = n_emacs_events_pending;
3540   n_emacs_events_pending = 0;
3541   emacs_event = q_event_ptr = NULL;
3542   unblock_input ();
3544   return nevents;
3549 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3550            fd_set *exceptfds, struct timespec const *timeout,
3551            sigset_t const *sigmask)
3552 /* --------------------------------------------------------------------------
3553      Replacement for select, checking for events
3554    -------------------------------------------------------------------------- */
3556   int result;
3557   int t, k, nr = 0;
3558   struct input_event event;
3559   char c;
3561 /*  NSTRACE (ns_select); */
3563 #ifdef HAVE_NATIVE_FS
3564   check_native_fs ();
3565 #endif
3567   if (hold_event_q.nr > 0)
3568     {
3569       /* We already have events pending. */
3570       raise (SIGIO);
3571       errno = EINTR;
3572       return -1;
3573     }
3575   for (k = 0; k < nfds+1; k++)
3576     {
3577       if (readfds && FD_ISSET(k, readfds)) ++nr;
3578       if (writefds && FD_ISSET(k, writefds)) ++nr;
3579     }
3581   if (NSApp == nil
3582       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3583     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3585   [outerpool release];
3586   outerpool = [[NSAutoreleasePool alloc] init];
3589   send_appdefined = YES;
3590   if (nr > 0)
3591     {
3592       pthread_mutex_lock (&select_mutex);
3593       select_nfds = nfds;
3594       select_valid = 0;
3595       if (readfds)
3596         {
3597           select_readfds = *readfds;
3598           select_valid += SELECT_HAVE_READ;
3599         }
3600       if (writefds)
3601         {
3602           select_writefds = *writefds;
3603           select_valid += SELECT_HAVE_WRITE;
3604         }
3606       if (timeout)
3607         {
3608           select_timeout = *timeout;
3609           select_valid += SELECT_HAVE_TMO;
3610         }
3612       pthread_mutex_unlock (&select_mutex);
3614       /* Inform fd_handler that select should be called */
3615       c = 'g';
3616       emacs_write_sig (selfds[1], &c, 1);
3617     }
3618   else if (nr == 0 && timeout)
3619     {
3620       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3621       double time = timespectod (*timeout);
3622       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3623                                                       target: NSApp
3624                                                     selector:
3625                                   @selector (timeout_handler:)
3626                                                     userInfo: 0
3627                                                      repeats: NO]
3628                       retain];
3629     }
3630   else /* No timeout and no file descriptors, can this happen?  */
3631     {
3632       /* Send appdefined so we exit from the loop */
3633       ns_send_appdefined (-1);
3634     }
3636   EVENT_INIT (event);
3637   block_input ();
3638   emacs_event = &event;
3639   if (++apploopnr != 1)
3640     {
3641       emacs_abort ();
3642     }
3643   [NSApp run];
3644   --apploopnr;
3645   emacs_event = NULL;
3646   if (nr > 0 && readfds)
3647     {
3648       c = 's';
3649       emacs_write_sig (selfds[1], &c, 1);
3650     }
3651   unblock_input ();
3653   t = last_appdefined_event_data;
3655   if (t != NO_APPDEFINED_DATA)
3656     {
3657       last_appdefined_event_data = NO_APPDEFINED_DATA;
3659       if (t == -2)
3660         {
3661           /* The NX_APPDEFINED event we received was a timeout. */
3662           result = 0;
3663         }
3664       else if (t == -1)
3665         {
3666           /* The NX_APPDEFINED event we received was the result of
3667              at least one real input event arriving.  */
3668           errno = EINTR;
3669           result = -1;
3670         }
3671       else
3672         {
3673           /* Received back from select () in fd_handler; copy the results */
3674           pthread_mutex_lock (&select_mutex);
3675           if (readfds) *readfds = select_readfds;
3676           if (writefds) *writefds = select_writefds;
3677           pthread_mutex_unlock (&select_mutex);
3678           result = t;
3679         }
3680     }
3681   else
3682     {
3683       errno = EINTR;
3684       result = -1;
3685     }
3687   return result;
3692 /* ==========================================================================
3694     Scrollbar handling
3696    ========================================================================== */
3699 static void
3700 ns_set_vertical_scroll_bar (struct window *window,
3701                            int portion, int whole, int position)
3702 /* --------------------------------------------------------------------------
3703       External (hook): Update or add scrollbar
3704    -------------------------------------------------------------------------- */
3706   Lisp_Object win;
3707   NSRect r, v;
3708   struct frame *f = XFRAME (WINDOW_FRAME (window));
3709   EmacsView *view = FRAME_NS_VIEW (f);
3710   int window_y, window_height;
3711   int top, left, height, width, sb_width, sb_left;
3712   EmacsScroller *bar;
3713   BOOL fringe_extended_p;
3715   /* optimization; display engine sends WAY too many of these.. */
3716   if (!NILP (window->vertical_scroll_bar))
3717     {
3718       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3719       if ([bar checkSamePosition: position portion: portion whole: whole])
3720         {
3721           if (view->scrollbarsNeedingUpdate == 0)
3722             {
3723               if (!windows_or_buffers_changed)
3724                   return;
3725             }
3726           else
3727             view->scrollbarsNeedingUpdate--;
3728         }
3729     }
3731   NSTRACE (ns_set_vertical_scroll_bar);
3733   /* Get dimensions.  */
3734   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3735   top = window_y;
3736   height = window_height;
3737   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3738   left = WINDOW_SCROLL_BAR_AREA_X (window);
3740   /* allow for displaying a skinnier scrollbar than char area allotted */
3741   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3742     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3743   sb_left = left;
3745   r = NSMakeRect (sb_left, top, sb_width, height);
3746   /* the parent view is flipped, so we need to flip y value */
3747   v = [view frame];
3748   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3750   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3752   XSETWINDOW (win, window);
3753   block_input ();
3755   /* we want at least 5 lines to display a scrollbar */
3756   if (WINDOW_TOTAL_LINES (window) < 5)
3757     {
3758       if (!NILP (window->vertical_scroll_bar))
3759         {
3760           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3761           [bar removeFromSuperview];
3762           wset_vertical_scroll_bar (window, Qnil);
3763         }
3764       ns_clear_frame_area (f, sb_left, top, width, height);
3765       unblock_input ();
3766       return;
3767     }
3769   if (NILP (window->vertical_scroll_bar))
3770     {
3771       if (width > 0 && height > 0)
3772         {
3773           if (fringe_extended_p)
3774             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3775           else
3776             ns_clear_frame_area (f, left, top, width, height);
3777         }
3779       bar = [[EmacsScroller alloc] initFrame: r window: win];
3780       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3781     }
3782   else
3783     {
3784       NSRect oldRect;
3785       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3786       oldRect = [bar frame];
3787       r.size.width = oldRect.size.width;
3788       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3789         {
3790           if (oldRect.origin.x != r.origin.x)
3791               ns_clear_frame_area (f, sb_left, top, width, height);
3792           [bar setFrame: r];
3793         }
3794     }
3796   [bar setPosition: position portion: portion whole: whole];
3797   unblock_input ();
3801 static void
3802 ns_condemn_scroll_bars (struct frame *f)
3803 /* --------------------------------------------------------------------------
3804      External (hook): arrange for all frame's scrollbars to be removed
3805      at next call to judge_scroll_bars, except for those redeemed.
3806    -------------------------------------------------------------------------- */
3808   int i;
3809   id view;
3810   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3812   NSTRACE (ns_condemn_scroll_bars);
3814   for (i =[subviews count]-1; i >= 0; i--)
3815     {
3816       view = [subviews objectAtIndex: i];
3817       if ([view isKindOfClass: [EmacsScroller class]])
3818         [view condemn];
3819     }
3823 static void
3824 ns_redeem_scroll_bar (struct window *window)
3825 /* --------------------------------------------------------------------------
3826      External (hook): arrange to spare this window's scrollbar
3827      at next call to judge_scroll_bars.
3828    -------------------------------------------------------------------------- */
3830   id bar;
3831   NSTRACE (ns_redeem_scroll_bar);
3832   if (!NILP (window->vertical_scroll_bar))
3833     {
3834       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3835       [bar reprieve];
3836     }
3840 static void
3841 ns_judge_scroll_bars (struct frame *f)
3842 /* --------------------------------------------------------------------------
3843      External (hook): destroy all scrollbars on frame that weren't
3844      redeemed after call to condemn_scroll_bars.
3845    -------------------------------------------------------------------------- */
3847   int i;
3848   id view;
3849   EmacsView *eview = FRAME_NS_VIEW (f);
3850   NSArray *subviews = [[eview superview] subviews];
3851   BOOL removed = NO;
3853   NSTRACE (ns_judge_scroll_bars);
3854   for (i = [subviews count]-1; i >= 0; --i)
3855     {
3856       view = [subviews objectAtIndex: i];
3857       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3858       [view judge];
3859       removed = YES;
3860     }
3862   if (removed)
3863     [eview updateFrameSize: NO];
3866 /* ==========================================================================
3868     Initialization
3870    ========================================================================== */
3873 x_display_pixel_height (struct ns_display_info *dpyinfo)
3875   NSArray *screens = [NSScreen screens];
3876   NSEnumerator *enumerator = [screens objectEnumerator];
3877   NSScreen *screen;
3878   NSRect frame;
3880   frame = NSZeroRect;
3881   while ((screen = [enumerator nextObject]) != nil)
3882     frame = NSUnionRect (frame, [screen frame]);
3884   return NSHeight (frame);
3888 x_display_pixel_width (struct ns_display_info *dpyinfo)
3890   NSArray *screens = [NSScreen screens];
3891   NSEnumerator *enumerator = [screens objectEnumerator];
3892   NSScreen *screen;
3893   NSRect frame;
3895   frame = NSZeroRect;
3896   while ((screen = [enumerator nextObject]) != nil)
3897     frame = NSUnionRect (frame, [screen frame]);
3899   return NSWidth (frame);
3903 static Lisp_Object ns_string_to_lispmod (const char *s)
3904 /* --------------------------------------------------------------------------
3905      Convert modifier name to lisp symbol
3906    -------------------------------------------------------------------------- */
3908   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3909     return Qmeta;
3910   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3911     return Qsuper;
3912   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3913     return Qcontrol;
3914   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3915     return Qalt;
3916   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3917     return Qhyper;
3918   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3919     return Qnone;
3920   else
3921     return Qnil;
3925 static void
3926 ns_default (const char *parameter, Lisp_Object *result,
3927            Lisp_Object yesval, Lisp_Object noval,
3928            BOOL is_float, BOOL is_modstring)
3929 /* --------------------------------------------------------------------------
3930       Check a parameter value in user's preferences
3931    -------------------------------------------------------------------------- */
3933   const char *value = ns_get_defaults_value (parameter);
3935   if (value)
3936     {
3937       double f;
3938       char *pos;
3939       if (c_strcasecmp (value, "YES") == 0)
3940         *result = yesval;
3941       else if (c_strcasecmp (value, "NO") == 0)
3942         *result = noval;
3943       else if (is_float && (f = strtod (value, &pos), pos != value))
3944         *result = make_float (f);
3945       else if (is_modstring && value)
3946         *result = ns_string_to_lispmod (value);
3947       else fprintf (stderr,
3948                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3949     }
3953 static void
3954 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3955 /* --------------------------------------------------------------------------
3956       Initialize global info and storage for display.
3957    -------------------------------------------------------------------------- */
3959     NSScreen *screen = [NSScreen mainScreen];
3960     NSWindowDepth depth = [screen depth];
3962     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3963     dpyinfo->resy = 72.27;
3964     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3965                                                   NSColorSpaceFromDepth (depth)]
3966                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3967                                                  NSColorSpaceFromDepth (depth)];
3968     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3969     dpyinfo->image_cache = make_image_cache ();
3970     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3971     dpyinfo->color_table->colors = NULL;
3972     dpyinfo->root_window = 42; /* a placeholder.. */
3973     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3974     dpyinfo->n_fonts = 0;
3975     dpyinfo->smallest_font_height = 1;
3976     dpyinfo->smallest_char_width = 1;
3978     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3982 /* This and next define (many of the) public functions in this file. */
3983 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3984          with using despite presence in the "system dependent" redisplay
3985          interface.  In addition, many of the ns_ methods have code that is
3986          shared with all terms, indicating need for further refactoring. */
3987 extern frame_parm_handler ns_frame_parm_handlers[];
3988 static struct redisplay_interface ns_redisplay_interface =
3990   ns_frame_parm_handlers,
3991   x_produce_glyphs,
3992   x_write_glyphs,
3993   x_insert_glyphs,
3994   x_clear_end_of_line,
3995   ns_scroll_run,
3996   ns_after_update_window_line,
3997   ns_update_window_begin,
3998   ns_update_window_end,
3999   0, /* flush_display */
4000   x_clear_window_mouse_face,
4001   x_get_glyph_overhangs,
4002   x_fix_overlapping_area,
4003   ns_draw_fringe_bitmap,
4004   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4005   0, /* destroy_fringe_bitmap */
4006   ns_compute_glyph_string_overhangs,
4007   ns_draw_glyph_string,
4008   ns_define_frame_cursor,
4009   ns_clear_frame_area,
4010   ns_draw_window_cursor,
4011   ns_draw_vertical_window_border,
4012   ns_shift_glyphs_for_insert
4016 static void
4017 ns_delete_display (struct ns_display_info *dpyinfo)
4019   /* TODO... */
4023 /* This function is called when the last frame on a display is deleted. */
4024 static void
4025 ns_delete_terminal (struct terminal *terminal)
4027   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4029   /* Protect against recursive calls.  delete_frame in
4030      delete_terminal calls us back when it deletes our last frame.  */
4031   if (!terminal->name)
4032     return;
4034   block_input ();
4036   x_destroy_all_bitmaps (dpyinfo);
4037   ns_delete_display (dpyinfo);
4038   unblock_input ();
4042 static struct terminal *
4043 ns_create_terminal (struct ns_display_info *dpyinfo)
4044 /* --------------------------------------------------------------------------
4045       Set up use of NS before we make the first connection.
4046    -------------------------------------------------------------------------- */
4048   struct terminal *terminal;
4050   NSTRACE (ns_create_terminal);
4052   terminal = create_terminal ();
4054   terminal->type = output_ns;
4055   terminal->display_info.ns = dpyinfo;
4056   dpyinfo->terminal = terminal;
4058   terminal->rif = &ns_redisplay_interface;
4060   terminal->clear_frame_hook = ns_clear_frame;
4061   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4062   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4063   terminal->ring_bell_hook = ns_ring_bell;
4064   terminal->reset_terminal_modes_hook = NULL;
4065   terminal->set_terminal_modes_hook = NULL;
4066   terminal->update_begin_hook = ns_update_begin;
4067   terminal->update_end_hook = ns_update_end;
4068   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4069   terminal->read_socket_hook = ns_read_socket;
4070   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4071   terminal->mouse_position_hook = ns_mouse_position;
4072   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4073   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4075   terminal->fullscreen_hook = ns_fullscreen_hook;
4077   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4078   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4079   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4080   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4082   terminal->delete_frame_hook = x_destroy_window;
4083   terminal->delete_terminal_hook = ns_delete_terminal;
4085   terminal->scroll_region_ok = 1;
4086   terminal->char_ins_del_ok = 1;
4087   terminal->line_ins_del_ok = 1;
4088   terminal->fast_clear_end_of_line = 1;
4089   terminal->memory_below_frame = 0;
4091   return terminal;
4095 struct ns_display_info *
4096 ns_term_init (Lisp_Object display_name)
4097 /* --------------------------------------------------------------------------
4098      Start the Application and get things rolling.
4099    -------------------------------------------------------------------------- */
4101   struct terminal *terminal;
4102   struct ns_display_info *dpyinfo;
4103   static int ns_initialized = 0;
4104   Lisp_Object tmp;
4106   if (ns_initialized) return x_display_list;
4107   ns_initialized = 1;
4109   NSTRACE (ns_term_init);
4111   [outerpool release];
4112   outerpool = [[NSAutoreleasePool alloc] init];
4114   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4115   /*GSDebugAllocationActive (YES); */
4116   block_input ();
4118   baud_rate = 38400;
4119   Fset_input_interrupt_mode (Qnil);
4121   if (selfds[0] == -1)
4122     {
4123       if (emacs_pipe (selfds) != 0)
4124         {
4125           fprintf (stderr, "Failed to create pipe: %s\n",
4126                    emacs_strerror (errno));
4127           emacs_abort ();
4128         }
4130       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4131       FD_ZERO (&select_readfds);
4132       FD_ZERO (&select_writefds);
4133       pthread_mutex_init (&select_mutex, NULL);
4134     }
4136   ns_pending_files = [[NSMutableArray alloc] init];
4137   ns_pending_service_names = [[NSMutableArray alloc] init];
4138   ns_pending_service_args = [[NSMutableArray alloc] init];
4140 /* Start app and create the main menu, window, view.
4141      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4142      The view will then ask the NSApp to stop and return to Emacs. */
4143   [EmacsApp sharedApplication];
4144   if (NSApp == nil)
4145     return NULL;
4146   [NSApp setDelegate: NSApp];
4148   /* Start the select thread.  */
4149   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4150                            toTarget:NSApp
4151                          withObject:nil];
4153   /* debugging: log all notifications */
4154   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4155                                          selector: @selector (logNotification:)
4156                                              name: nil object: nil]; */
4158   dpyinfo = xzalloc (sizeof *dpyinfo);
4160   ns_initialize_display_info (dpyinfo);
4161   terminal = ns_create_terminal (dpyinfo);
4163   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4164   init_kboard (terminal->kboard);
4165   kset_window_system (terminal->kboard, Qns);
4166   terminal->kboard->next_kboard = all_kboards;
4167   all_kboards = terminal->kboard;
4168   /* Don't let the initial kboard remain current longer than necessary.
4169      That would cause problems if a file loaded on startup tries to
4170      prompt in the mini-buffer.  */
4171   if (current_kboard == initial_kboard)
4172     current_kboard = terminal->kboard;
4173   terminal->kboard->reference_count++;
4175   dpyinfo->next = x_display_list;
4176   x_display_list = dpyinfo;
4178   /* Put it on ns_display_name_list */
4179   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4180                                 ns_display_name_list);
4181   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4183   terminal->name = xstrdup (SSDATA (display_name));
4185   unblock_input ();
4187   if (!inhibit_x_resources)
4188     {
4189       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4190                  Qt, Qnil, NO, NO);
4191       tmp = Qnil;
4192       /* this is a standard variable */
4193       ns_default ("AppleAntiAliasingThreshold", &tmp,
4194                  make_float (10.0), make_float (6.0), YES, NO);
4195       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4196     }
4198   {
4199     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4201     if ( cl == nil )
4202       {
4203         Lisp_Object color_file, color_map, color;
4204         unsigned long c;
4205         char *name;
4207         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4208                          Fsymbol_value (intern ("data-directory")));
4210         color_map = Fx_load_color_file (color_file);
4211         if (NILP (color_map))
4212           fatal ("Could not read %s.\n", SDATA (color_file));
4214         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4215         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4216           {
4217             color = XCAR (color_map);
4218             name = SSDATA (XCAR (color));
4219             c = XINT (XCDR (color));
4220             [cl setColor:
4221                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4222                                             green: GREEN_FROM_ULONG (c) / 255.0
4223                                              blue: BLUE_FROM_ULONG (c) / 255.0
4224                                             alpha: 1.0]
4225                   forKey: [NSString stringWithUTF8String: name]];
4226           }
4227         [cl writeToFile: nil];
4228       }
4229   }
4231   {
4232 #ifdef NS_IMPL_GNUSTEP
4233     Vwindow_system_version = build_string (gnustep_base_version);
4234 #else
4235     /*PSnextrelease (128, c); */
4236     char c[DBL_BUFSIZE_BOUND];
4237     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4238     Vwindow_system_version = make_unibyte_string (c, len);
4239 #endif
4240   }
4242   delete_keyboard_wait_descriptor (0);
4244   ns_app_name = [[NSProcessInfo processInfo] processName];
4246 /* Set up OS X app menu */
4247 #ifdef NS_IMPL_COCOA
4248   {
4249     NSMenu *appMenu;
4250     NSMenuItem *item;
4251     /* set up the application menu */
4252     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4253     [svcsMenu setAutoenablesItems: NO];
4254     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4255     [appMenu setAutoenablesItems: NO];
4256     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4257     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4259     [appMenu insertItemWithTitle: @"About Emacs"
4260                           action: @selector (orderFrontStandardAboutPanel:)
4261                    keyEquivalent: @""
4262                          atIndex: 0];
4263     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4264     [appMenu insertItemWithTitle: @"Preferences..."
4265                           action: @selector (showPreferencesWindow:)
4266                    keyEquivalent: @","
4267                          atIndex: 2];
4268     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4269     item = [appMenu insertItemWithTitle: @"Services"
4270                                  action: @selector (menuDown:)
4271                           keyEquivalent: @""
4272                                 atIndex: 4];
4273     [appMenu setSubmenu: svcsMenu forItem: item];
4274     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4275     [appMenu insertItemWithTitle: @"Hide Emacs"
4276                           action: @selector (hide:)
4277                    keyEquivalent: @"h"
4278                          atIndex: 6];
4279     item =  [appMenu insertItemWithTitle: @"Hide Others"
4280                           action: @selector (hideOtherApplications:)
4281                    keyEquivalent: @"h"
4282                          atIndex: 7];
4283     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4284     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4285     [appMenu insertItemWithTitle: @"Quit Emacs"
4286                           action: @selector (terminate:)
4287                    keyEquivalent: @"q"
4288                          atIndex: 9];
4290     item = [mainMenu insertItemWithTitle: ns_app_name
4291                                   action: @selector (menuDown:)
4292                            keyEquivalent: @""
4293                                  atIndex: 0];
4294     [mainMenu setSubmenu: appMenu forItem: item];
4295     [dockMenu insertItemWithTitle: @"New Frame"
4296                            action: @selector (newFrame:)
4297                     keyEquivalent: @""
4298                           atIndex: 0];
4300     [NSApp setMainMenu: mainMenu];
4301     [NSApp setAppleMenu: appMenu];
4302     [NSApp setServicesMenu: svcsMenu];
4303     /* Needed at least on Cocoa, to get dock menu to show windows */
4304     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4306     [[NSNotificationCenter defaultCenter]
4307       addObserver: mainMenu
4308          selector: @selector (trackingNotification:)
4309              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4310     [[NSNotificationCenter defaultCenter]
4311       addObserver: mainMenu
4312          selector: @selector (trackingNotification:)
4313              name: NSMenuDidEndTrackingNotification object: mainMenu];
4314   }
4315 #endif /* MAC OS X menu setup */
4317   /* Register our external input/output types, used for determining
4318      applicable services and also drag/drop eligibility. */
4319   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4320   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4321                       retain];
4322   ns_drag_types = [[NSArray arrayWithObjects:
4323                             NSStringPboardType,
4324                             NSTabularTextPboardType,
4325                             NSFilenamesPboardType,
4326                             NSURLPboardType,
4327                             NSColorPboardType,
4328                             NSFontPboardType, nil] retain];
4330   /* If fullscreen is in init/default-frame-alist, focus isn't set
4331      right for fullscreen windows, so set this.  */
4332   [NSApp activateIgnoringOtherApps:YES];
4334   [NSApp run];
4335   ns_do_open_file = YES;
4337 #ifdef NS_IMPL_GNUSTEP
4338   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4339      We must re-catch it so subprocess works.  */
4340   catch_child_signal ();
4341 #endif
4342   return dpyinfo;
4346 void
4347 ns_term_shutdown (int sig)
4349   [[NSUserDefaults standardUserDefaults] synchronize];
4351   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4352   if (STRINGP (Vauto_save_list_file_name))
4353     unlink (SSDATA (Vauto_save_list_file_name));
4355   if (sig == 0 || sig == SIGTERM)
4356     {
4357       [NSApp terminate: NSApp];
4358     }
4359   else // force a stack trace to happen
4360     {
4361       emacs_abort ();
4362     }
4366 /* ==========================================================================
4368     EmacsApp implementation
4370    ========================================================================== */
4373 @implementation EmacsApp
4375 - (void)logNotification: (NSNotification *)notification
4377   const char *name = [[notification name] UTF8String];
4378   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4379       && !strstr (name, "WindowNumber"))
4380     NSLog (@"notification: '%@'", [notification name]);
4384 - (void)sendEvent: (NSEvent *)theEvent
4385 /* --------------------------------------------------------------------------
4386      Called when NSApp is running for each event received.  Used to stop
4387      the loop when we choose, since there's no way to just run one iteration.
4388    -------------------------------------------------------------------------- */
4390   int type = [theEvent type];
4391   NSWindow *window = [theEvent window];
4393 /*  NSTRACE (sendEvent); */
4394 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4396 #ifdef NS_IMPL_GNUSTEP
4397   // Keyboard events aren't propagated to file dialogs for some reason.
4398   if ([NSApp modalWindow] != nil &&
4399       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4400     {
4401       [[NSApp modalWindow] sendEvent: theEvent];
4402       return;
4403     }
4404 #endif
4406   if (type == NSApplicationDefined)
4407     {
4408       switch ([theEvent data2])
4409         {
4410 #ifdef NS_IMPL_COCOA
4411         case NSAPP_DATA2_RUNASSCRIPT:
4412           ns_run_ascript ();
4413           [self stop: self];
4414           return;
4415 #endif
4416         case NSAPP_DATA2_RUNFILEDIALOG:
4417           ns_run_file_dialog ();
4418           [self stop: self];
4419           return;
4420         }
4421     }
4423   if (type == NSCursorUpdate && window == nil)
4424     {
4425       fprintf (stderr, "Dropping external cursor update event.\n");
4426       return;
4427     }
4429   if (type == NSApplicationDefined)
4430     {
4431       /* Events posted by ns_send_appdefined interrupt the run loop here.
4432          But, if a modal window is up, an appdefined can still come through,
4433          (e.g., from a makeKeyWindow event) but stopping self also stops the
4434          modal loop. Just defer it until later. */
4435       if ([NSApp modalWindow] == nil)
4436         {
4437           last_appdefined_event_data = [theEvent data1];
4438           [self stop: self];
4439         }
4440       else
4441         {
4442           send_appdefined = YES;
4443         }
4444     }
4447 #ifdef NS_IMPL_COCOA
4448   /* If no dialog and none of our frames have focus and it is a move, skip it.
4449      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4450      such as Wifi, sound, date or similar.
4451      This prevents "spooky" highlighting in the frame under the menu.  */
4452   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4453     {
4454       struct ns_display_info *di;
4455       BOOL has_focus = NO;
4456       for (di = x_display_list; ! has_focus && di; di = di->next)
4457         has_focus = di->x_focus_frame != 0;
4458       if (! has_focus)
4459         return;
4460     }
4461 #endif
4463   [super sendEvent: theEvent];
4467 - (void)showPreferencesWindow: (id)sender
4469   struct frame *emacsframe = SELECTED_FRAME ();
4470   NSEvent *theEvent = [NSApp currentEvent];
4472   if (!emacs_event)
4473     return;
4474   emacs_event->kind = NS_NONKEY_EVENT;
4475   emacs_event->code = KEY_NS_SHOW_PREFS;
4476   emacs_event->modifiers = 0;
4477   EV_TRAILER (theEvent);
4481 - (void)newFrame: (id)sender
4483   struct frame *emacsframe = SELECTED_FRAME ();
4484   NSEvent *theEvent = [NSApp currentEvent];
4486   if (!emacs_event)
4487     return;
4488   emacs_event->kind = NS_NONKEY_EVENT;
4489   emacs_event->code = KEY_NS_NEW_FRAME;
4490   emacs_event->modifiers = 0;
4491   EV_TRAILER (theEvent);
4495 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4496 - (BOOL) openFile: (NSString *)fileName
4498   struct frame *emacsframe = SELECTED_FRAME ();
4499   NSEvent *theEvent = [NSApp currentEvent];
4501   if (!emacs_event)
4502     return NO;
4504   emacs_event->kind = NS_NONKEY_EVENT;
4505   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4506   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4507   ns_input_line = Qnil; /* can be start or cons start,end */
4508   emacs_event->modifiers =0;
4509   EV_TRAILER (theEvent);
4511   return YES;
4515 /* **************************************************************************
4517       EmacsApp delegate implementation
4519    ************************************************************************** */
4521 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4522 /* --------------------------------------------------------------------------
4523      When application is loaded, terminate event loop in ns_term_init
4524    -------------------------------------------------------------------------- */
4526   NSTRACE (applicationDidFinishLaunching);
4527   [NSApp setServicesProvider: NSApp];
4528   ns_send_appdefined (-2);
4532 /* Termination sequences:
4533     C-x C-c:
4534     Cmd-Q:
4535     MenuBar | File | Exit:
4536     Select Quit from App menubar:
4537         -terminate
4538         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4539         ns_term_shutdown()
4541     Select Quit from Dock menu:
4542     Logout attempt:
4543         -appShouldTerminate
4544           Cancel -> Nothing else
4545           Accept ->
4547           -terminate
4548           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4549           ns_term_shutdown()
4553 - (void) terminate: (id)sender
4555   struct frame *emacsframe = SELECTED_FRAME ();
4557   if (!emacs_event)
4558     return;
4560   emacs_event->kind = NS_NONKEY_EVENT;
4561   emacs_event->code = KEY_NS_POWER_OFF;
4562   emacs_event->arg = Qt; /* mark as non-key event */
4563   EV_TRAILER ((id)nil);
4567 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4569   int ret;
4571   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4572     return NSTerminateNow;
4574     ret = NSRunAlertPanel(ns_app_name,
4575                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4576                           @"Save Buffers and Exit", @"Cancel", nil);
4578     if (ret == NSAlertDefaultReturn)
4579         return NSTerminateNow;
4580     else if (ret == NSAlertAlternateReturn)
4581         return NSTerminateCancel;
4582     return NSTerminateNow;  /* just in case */
4585 static int
4586 not_in_argv (NSString *arg)
4588   int k;
4589   const char *a = [arg UTF8String];
4590   for (k = 1; k < initial_argc; ++k)
4591     if (strcmp (a, initial_argv[k]) == 0) return 0;
4592   return 1;
4595 /*   Notification from the Workspace to open a file */
4596 - (BOOL)application: sender openFile: (NSString *)file
4598   if (ns_do_open_file || not_in_argv (file))
4599     [ns_pending_files addObject: file];
4600   return YES;
4604 /*   Open a file as a temporary file */
4605 - (BOOL)application: sender openTempFile: (NSString *)file
4607   if (ns_do_open_file || not_in_argv (file))
4608     [ns_pending_files addObject: file];
4609   return YES;
4613 /*   Notification from the Workspace to open a file noninteractively (?) */
4614 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4616   if (ns_do_open_file || not_in_argv (file))
4617     [ns_pending_files addObject: file];
4618   return YES;
4621 /*   Notification from the Workspace to open multiple files */
4622 - (void)application: sender openFiles: (NSArray *)fileList
4624   NSEnumerator *files = [fileList objectEnumerator];
4625   NSString *file;
4626   /* Don't open files from the command line unconditionally,
4627      Cocoa parses the command line wrong, --option value tries to open value
4628      if --option is the last option.  */
4629   while ((file = [files nextObject]) != nil)
4630     if (ns_do_open_file || not_in_argv (file))
4631       [ns_pending_files addObject: file];
4633   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4638 /* Handle dock menu requests.  */
4639 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4641   return dockMenu;
4645 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4646 - (void)applicationWillBecomeActive: (NSNotification *)notification
4648   //ns_app_active=YES;
4650 - (void)applicationDidBecomeActive: (NSNotification *)notification
4652   NSTRACE (applicationDidBecomeActive);
4654   //ns_app_active=YES;
4656   ns_update_auto_hide_menu_bar ();
4657   // No constraining takes place when the application is not active.
4658   ns_constrain_all_frames ();
4660 - (void)applicationDidResignActive: (NSNotification *)notification
4662   //ns_app_active=NO;
4663   ns_send_appdefined (-1);
4668 /* ==========================================================================
4670     EmacsApp aux handlers for managing event loop
4672    ========================================================================== */
4675 - (void)timeout_handler: (NSTimer *)timedEntry
4676 /* --------------------------------------------------------------------------
4677      The timeout specified to ns_select has passed.
4678    -------------------------------------------------------------------------- */
4680   /*NSTRACE (timeout_handler); */
4681   ns_send_appdefined (-2);
4684 #ifdef NS_IMPL_GNUSTEP
4685 - (void)sendFromMainThread:(id)unused
4687   ns_send_appdefined (nextappdefined);
4689 #endif
4691 - (void)fd_handler:(id)unused
4692 /* --------------------------------------------------------------------------
4693      Check data waiting on file descriptors and terminate if so
4694    -------------------------------------------------------------------------- */
4696   int result;
4697   int waiting = 1, nfds;
4698   char c;
4700   fd_set readfds, writefds, *wfds;
4701   struct timespec timeout, *tmo;
4702   NSAutoreleasePool *pool = nil;
4704   /* NSTRACE (fd_handler); */
4706   for (;;)
4707     {
4708       [pool release];
4709       pool = [[NSAutoreleasePool alloc] init];
4711       if (waiting)
4712         {
4713           fd_set fds;
4714           FD_ZERO (&fds);
4715           FD_SET (selfds[0], &fds);
4716           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4717           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4718             waiting = 0;
4719         }
4720       else
4721         {
4722           pthread_mutex_lock (&select_mutex);
4723           nfds = select_nfds;
4725           if (select_valid & SELECT_HAVE_READ)
4726             readfds = select_readfds;
4727           else
4728             FD_ZERO (&readfds);
4730           if (select_valid & SELECT_HAVE_WRITE)
4731             {
4732               writefds = select_writefds;
4733               wfds = &writefds;
4734             }
4735           else
4736             wfds = NULL;
4737           if (select_valid & SELECT_HAVE_TMO)
4738             {
4739               timeout = select_timeout;
4740               tmo = &timeout;
4741             }
4742           else
4743             tmo = NULL;
4745           pthread_mutex_unlock (&select_mutex);
4747           FD_SET (selfds[0], &readfds);
4748           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4750           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4752           if (result == 0)
4753             ns_send_appdefined (-2);
4754           else if (result > 0)
4755             {
4756               if (FD_ISSET (selfds[0], &readfds))
4757                 {
4758                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4759                     waiting = 1;
4760                 }
4761               else
4762                 {
4763                   pthread_mutex_lock (&select_mutex);
4764                   if (select_valid & SELECT_HAVE_READ)
4765                     select_readfds = readfds;
4766                   if (select_valid & SELECT_HAVE_WRITE)
4767                     select_writefds = writefds;
4768                   if (select_valid & SELECT_HAVE_TMO)
4769                     select_timeout = timeout;
4770                   pthread_mutex_unlock (&select_mutex);
4772                   ns_send_appdefined (result);
4773                 }
4774             }
4775           waiting = 1;
4776         }
4777     }
4782 /* ==========================================================================
4784     Service provision
4786    ========================================================================== */
4788 /* called from system: queue for next pass through event loop */
4789 - (void)requestService: (NSPasteboard *)pboard
4790               userData: (NSString *)userData
4791                  error: (NSString **)error
4793   [ns_pending_service_names addObject: userData];
4794   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4795       SSDATA (ns_string_from_pasteboard (pboard))]];
4799 /* called from ns_read_socket to clear queue */
4800 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4802   struct frame *emacsframe = SELECTED_FRAME ();
4803   NSEvent *theEvent = [NSApp currentEvent];
4805   if (!emacs_event)
4806     return NO;
4808   emacs_event->kind = NS_NONKEY_EVENT;
4809   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4810   ns_input_spi_name = build_string ([name UTF8String]);
4811   ns_input_spi_arg = build_string ([arg UTF8String]);
4812   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4813   EV_TRAILER (theEvent);
4815   return YES;
4819 @end  /* EmacsApp */
4823 /* ==========================================================================
4825     EmacsView implementation
4827    ========================================================================== */
4830 @implementation EmacsView
4832 /* needed to inform when window closed from LISP */
4833 - (void) setWindowClosing: (BOOL)closing
4835   windowClosing = closing;
4839 - (void)dealloc
4841   NSTRACE (EmacsView_dealloc);
4842   [toolbar release];
4843   if (fs_state == FULLSCREEN_BOTH)
4844     [nonfs_window release];
4845   [super dealloc];
4849 /* called on font panel selection */
4850 - (void)changeFont: (id)sender
4852   NSEvent *e = [[self window] currentEvent];
4853   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4854   struct font *font = face->font;
4855   id newFont;
4856   CGFloat size;
4857   NSFont *nsfont;
4859   NSTRACE (changeFont);
4861   if (!emacs_event)
4862     return;
4864   if (EQ (font->driver->type, Qns))
4865     nsfont = ((struct nsfont_info *)font)->nsfont;
4866 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4867   else
4868     nsfont = (NSFont *) macfont_get_nsctfont (font);
4869 #endif
4871   if ((newFont = [sender convertFont: nsfont]))
4872     {
4873       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4875       emacs_event->kind = NS_NONKEY_EVENT;
4876       emacs_event->modifiers = 0;
4877       emacs_event->code = KEY_NS_CHANGE_FONT;
4879       size = [newFont pointSize];
4880       ns_input_fontsize = make_number (lrint (size));
4881       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4882       EV_TRAILER (e);
4883     }
4887 - (BOOL)acceptsFirstResponder
4889   NSTRACE (acceptsFirstResponder);
4890   return YES;
4894 - (void)resetCursorRects
4896   NSRect visible = [self visibleRect];
4897   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4898   NSTRACE (resetCursorRects);
4900   if (currentCursor == nil)
4901     currentCursor = [NSCursor arrowCursor];
4903   if (!NSIsEmptyRect (visible))
4904     [self addCursorRect: visible cursor: currentCursor];
4905   [currentCursor setOnMouseEntered: YES];
4910 /*****************************************************************************/
4911 /* Keyboard handling. */
4912 #define NS_KEYLOG 0
4914 - (void)keyDown: (NSEvent *)theEvent
4916   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4917   int code;
4918   unsigned fnKeysym = 0;
4919   static NSMutableArray *nsEvArray;
4920 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4921   static BOOL firstTime = YES;
4922 #endif
4923   int left_is_none;
4924   unsigned int flags = [theEvent modifierFlags];
4926   NSTRACE (keyDown);
4928   /* Rhapsody and OS X give up and down events for the arrow keys */
4929   if (ns_fake_keydown == YES)
4930     ns_fake_keydown = NO;
4931   else if ([theEvent type] != NSKeyDown)
4932     return;
4934   if (!emacs_event)
4935     return;
4937  if (![[self window] isKeyWindow]
4938      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4939      /* we must avoid an infinite loop here. */
4940      && (EmacsView *)[[theEvent window] delegate] != self)
4941    {
4942      /* XXX: There is an occasional condition in which, when Emacs display
4943          updates a different frame from the current one, and temporarily
4944          selects it, then processes some interrupt-driven input
4945          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4946          for some reason that window has its first responder set to the NSView
4947          most recently updated (I guess), which is not the correct one. */
4948      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4949      return;
4950    }
4952   if (nsEvArray == nil)
4953     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4955   [NSCursor setHiddenUntilMouseMoves: YES];
4957   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4958     {
4959       clear_mouse_face (hlinfo);
4960       hlinfo->mouse_face_hidden = 1;
4961     }
4963   if (!processingCompose)
4964     {
4965       /* When using screen sharing, no left or right information is sent,
4966          so use Left key in those cases.  */
4967       int is_left_key, is_right_key;
4969       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4970         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4972       /* (Carbon way: [theEvent keyCode]) */
4974       /* is it a "function key"? */
4975       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4976         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4977         : ns_convert_key (code);
4979       if (fnKeysym)
4980         {
4981           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4982              because Emacs treats Delete and KP-Delete same (in simple.el). */
4983           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4984 #ifdef NS_IMPL_GNUSTEP
4985               /*  GNUstep uses incompatible keycodes, even for those that are
4986                   supposed to be hardware independent.  Just check for delete.
4987                   Keypad delete does not have keysym 0xFFFF.
4988                   See http://savannah.gnu.org/bugs/?25395
4989               */
4990               || (fnKeysym == 0xFFFF && code == 127)
4991 #endif
4992             )
4993             code = 0xFF08; /* backspace */
4994           else
4995             code = fnKeysym;
4996         }
4998       /* are there modifiers? */
4999       emacs_event->modifiers = 0;
5001       if (flags & NSHelpKeyMask)
5002           emacs_event->modifiers |= hyper_modifier;
5004       if (flags & NSShiftKeyMask)
5005         emacs_event->modifiers |= shift_modifier;
5007       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5008       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5009         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5011       if (is_right_key)
5012         emacs_event->modifiers |= parse_solitary_modifier
5013           (EQ (ns_right_command_modifier, Qleft)
5014            ? ns_command_modifier
5015            : ns_right_command_modifier);
5017       if (is_left_key)
5018         {
5019           emacs_event->modifiers |= parse_solitary_modifier
5020             (ns_command_modifier);
5022           /* if super (default), take input manager's word so things like
5023              dvorak / qwerty layout work */
5024           if (EQ (ns_command_modifier, Qsuper)
5025               && !fnKeysym
5026               && [[theEvent characters] length] != 0)
5027             {
5028               /* XXX: the code we get will be unshifted, so if we have
5029                  a shift modifier, must convert ourselves */
5030               if (!(flags & NSShiftKeyMask))
5031                 code = [[theEvent characters] characterAtIndex: 0];
5032 #if 0
5033               /* this is ugly and also requires linking w/Carbon framework
5034                  (for LMGetKbdType) so for now leave this rare (?) case
5035                  undealt with.. in future look into CGEvent methods */
5036               else
5037                 {
5038                   long smv = GetScriptManagerVariable (smKeyScript);
5039                   Handle uchrHandle = GetResource
5040                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5041                   UInt32 dummy = 0;
5042                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5043                                  [[theEvent characters] characterAtIndex: 0],
5044                                  kUCKeyActionDisplay,
5045                                  (flags & ~NSCommandKeyMask) >> 8,
5046                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5047                                  &dummy, 1, &dummy, &code);
5048                   code &= 0xFF;
5049                 }
5050 #endif
5051             }
5052         }
5054       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5055       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5056         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5058       if (is_right_key)
5059           emacs_event->modifiers |= parse_solitary_modifier
5060               (EQ (ns_right_control_modifier, Qleft)
5061                ? ns_control_modifier
5062                : ns_right_control_modifier);
5064       if (is_left_key)
5065         emacs_event->modifiers |= parse_solitary_modifier
5066           (ns_control_modifier);
5068       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5069           emacs_event->modifiers |=
5070             parse_solitary_modifier (ns_function_modifier);
5072       left_is_none = NILP (ns_alternate_modifier)
5073         || EQ (ns_alternate_modifier, Qnone);
5075       is_right_key = (flags & NSRightAlternateKeyMask)
5076         == NSRightAlternateKeyMask;
5077       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5078         || (! is_right_key
5079             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5081       if (is_right_key)
5082         {
5083           if ((NILP (ns_right_alternate_modifier)
5084                || EQ (ns_right_alternate_modifier, Qnone)
5085                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5086               && !fnKeysym)
5087             {   /* accept pre-interp alt comb */
5088               if ([[theEvent characters] length] > 0)
5089                 code = [[theEvent characters] characterAtIndex: 0];
5090               /*HACK: clear lone shift modifier to stop next if from firing */
5091               if (emacs_event->modifiers == shift_modifier)
5092                 emacs_event->modifiers = 0;
5093             }
5094           else
5095             emacs_event->modifiers |= parse_solitary_modifier
5096               (EQ (ns_right_alternate_modifier, Qleft)
5097                ? ns_alternate_modifier
5098                : ns_right_alternate_modifier);
5099         }
5101       if (is_left_key) /* default = meta */
5102         {
5103           if (left_is_none && !fnKeysym)
5104             {   /* accept pre-interp alt comb */
5105               if ([[theEvent characters] length] > 0)
5106                 code = [[theEvent characters] characterAtIndex: 0];
5107               /*HACK: clear lone shift modifier to stop next if from firing */
5108               if (emacs_event->modifiers == shift_modifier)
5109                 emacs_event->modifiers = 0;
5110             }
5111           else
5112               emacs_event->modifiers |=
5113                 parse_solitary_modifier (ns_alternate_modifier);
5114         }
5116   if (NS_KEYLOG)
5117     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5118              code, fnKeysym, flags, emacs_event->modifiers);
5120       /* if it was a function key or had modifiers, pass it directly to emacs */
5121       if (fnKeysym || (emacs_event->modifiers
5122                        && (emacs_event->modifiers != shift_modifier)
5123                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5124 /*[[theEvent characters] length] */
5125         {
5126           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5127           if (code < 0x20)
5128             code |= (1<<28)|(3<<16);
5129           else if (code == 0x7f)
5130             code |= (1<<28)|(3<<16);
5131           else if (!fnKeysym)
5132             emacs_event->kind = code > 0xFF
5133               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5135           emacs_event->code = code;
5136           EV_TRAILER (theEvent);
5137           processingCompose = NO;
5138           return;
5139         }
5140     }
5143 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5144   /* if we get here we should send the key for input manager processing */
5145   /* Disable warning, there is nothing a user can do about it anyway, and
5146      it does not seem to matter.  */
5147 #if 0
5148   if (firstTime && [[NSInputManager currentInputManager]
5149                      wantsToDelayTextChangeNotifications] == NO)
5150     fprintf (stderr,
5151           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5152 #endif
5153   firstTime = NO;
5154 #endif
5155   if (NS_KEYLOG && !processingCompose)
5156     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5158   processingCompose = YES;
5159   [nsEvArray addObject: theEvent];
5160   [self interpretKeyEvents: nsEvArray];
5161   [nsEvArray removeObject: theEvent];
5165 #ifdef NS_IMPL_COCOA
5166 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5167    decided not to send key-down for.
5168    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5169    This only applies on Tiger and earlier.
5170    If it matches one of these, send it on to keyDown. */
5171 -(void)keyUp: (NSEvent *)theEvent
5173   int flags = [theEvent modifierFlags];
5174   int code = [theEvent keyCode];
5175   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5176       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5177     {
5178       if (NS_KEYLOG)
5179         fprintf (stderr, "keyUp: passed test");
5180       ns_fake_keydown = YES;
5181       [self keyDown: theEvent];
5182     }
5184 #endif
5187 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5190 /* <NSTextInput>: called when done composing;
5191    NOTE: also called when we delete over working text, followed immed.
5192          by doCommandBySelector: deleteBackward: */
5193 - (void)insertText: (id)aString
5195   int code;
5196   int len = [(NSString *)aString length];
5197   int i;
5199   if (NS_KEYLOG)
5200     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5201   processingCompose = NO;
5203   if (!emacs_event)
5204     return;
5206   /* first, clear any working text */
5207   if (workingText != nil)
5208     [self deleteWorkingText];
5210   /* now insert the string as keystrokes */
5211   for (i =0; i<len; i++)
5212     {
5213       code = [aString characterAtIndex: i];
5214       /* TODO: still need this? */
5215       if (code == 0x2DC)
5216         code = '~'; /* 0x7E */
5217       if (code != 32) /* Space */
5218         emacs_event->modifiers = 0;
5219       emacs_event->kind
5220         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5221       emacs_event->code = code;
5222       EV_TRAILER ((id)nil);
5223     }
5227 /* <NSTextInput>: inserts display of composing characters */
5228 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5230   NSString *str = [aString respondsToSelector: @selector (string)] ?
5231     [aString string] : aString;
5232   if (NS_KEYLOG)
5233     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5234            str, (unsigned long)[str length],
5235            (unsigned long)selRange.length,
5236            (unsigned long)selRange.location);
5238   if (workingText != nil)
5239     [self deleteWorkingText];
5240   if ([str length] == 0)
5241     return;
5243   if (!emacs_event)
5244     return;
5246   processingCompose = YES;
5247   workingText = [str copy];
5248   ns_working_text = build_string ([workingText UTF8String]);
5250   emacs_event->kind = NS_TEXT_EVENT;
5251   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5252   EV_TRAILER ((id)nil);
5256 /* delete display of composing characters [not in <NSTextInput>] */
5257 - (void)deleteWorkingText
5259   if (workingText == nil)
5260     return;
5261   if (NS_KEYLOG)
5262     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5263   [workingText release];
5264   workingText = nil;
5265   processingCompose = NO;
5267   if (!emacs_event)
5268     return;
5270   emacs_event->kind = NS_TEXT_EVENT;
5271   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5272   EV_TRAILER ((id)nil);
5276 - (BOOL)hasMarkedText
5278   return workingText != nil;
5282 - (NSRange)markedRange
5284   NSRange rng = workingText != nil
5285     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5286   if (NS_KEYLOG)
5287     NSLog (@"markedRange request");
5288   return rng;
5292 - (void)unmarkText
5294   if (NS_KEYLOG)
5295     NSLog (@"unmark (accept) text");
5296   [self deleteWorkingText];
5297   processingCompose = NO;
5301 /* used to position char selection windows, etc. */
5302 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5304   NSRect rect;
5305   NSPoint pt;
5306   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5307   if (NS_KEYLOG)
5308     NSLog (@"firstRectForCharRange request");
5310   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5311   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5312   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5313   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5314                                        +FRAME_LINE_HEIGHT (emacsframe));
5316   pt = [self convertPoint: pt toView: nil];
5317   pt = [[self window] convertBaseToScreen: pt];
5318   rect.origin = pt;
5319   return rect;
5323 - (NSInteger)conversationIdentifier
5325   return (NSInteger)self;
5329 - (void)doCommandBySelector: (SEL)aSelector
5331   if (NS_KEYLOG)
5332     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5334   processingCompose = NO;
5335   if (aSelector == @selector (deleteBackward:))
5336     {
5337       /* happens when user backspaces over an ongoing composition:
5338          throw a 'delete' into the event queue */
5339       if (!emacs_event)
5340         return;
5341       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5342       emacs_event->code = 0xFF08;
5343       EV_TRAILER ((id)nil);
5344     }
5347 - (NSArray *)validAttributesForMarkedText
5349   static NSArray *arr = nil;
5350   if (arr == nil) arr = [NSArray new];
5351  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5352   return arr;
5355 - (NSRange)selectedRange
5357   if (NS_KEYLOG)
5358     NSLog (@"selectedRange request");
5359   return NSMakeRange (NSNotFound, 0);
5362 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5363     GNUSTEP_GUI_MINOR_VERSION > 22
5364 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5365 #else
5366 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5367 #endif
5369   if (NS_KEYLOG)
5370     NSLog (@"characterIndexForPoint request");
5371   return 0;
5374 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5376   static NSAttributedString *str = nil;
5377   if (str == nil) str = [NSAttributedString new];
5378   if (NS_KEYLOG)
5379     NSLog (@"attributedSubstringFromRange request");
5380   return str;
5383 /* End <NSTextInput> impl. */
5384 /*****************************************************************************/
5387 /* This is what happens when the user presses a mouse button.  */
5388 - (void)mouseDown: (NSEvent *)theEvent
5390   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5391   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5393   NSTRACE (mouseDown);
5395   [self deleteWorkingText];
5397   if (!emacs_event)
5398     return;
5400   dpyinfo->last_mouse_frame = emacsframe;
5401   /* appears to be needed to prevent spurious movement events generated on
5402      button clicks */
5403   emacsframe->mouse_moved = 0;
5405   if ([theEvent type] == NSScrollWheel)
5406     {
5407       CGFloat delta = [theEvent deltaY];
5408       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5409       if (delta == 0)
5410         return;
5411       emacs_event->kind = WHEEL_EVENT;
5412       emacs_event->code = 0;
5413       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5414         ((delta > 0) ? up_modifier : down_modifier);
5415     }
5416   else
5417     {
5418       emacs_event->kind = MOUSE_CLICK_EVENT;
5419       emacs_event->code = EV_BUTTON (theEvent);
5420       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5421                              | EV_UDMODIFIERS (theEvent);
5422     }
5423   XSETINT (emacs_event->x, lrint (p.x));
5424   XSETINT (emacs_event->y, lrint (p.y));
5425   EV_TRAILER (theEvent);
5429 - (void)rightMouseDown: (NSEvent *)theEvent
5431   NSTRACE (rightMouseDown);
5432   [self mouseDown: theEvent];
5436 - (void)otherMouseDown: (NSEvent *)theEvent
5438   NSTRACE (otherMouseDown);
5439   [self mouseDown: theEvent];
5443 - (void)mouseUp: (NSEvent *)theEvent
5445   NSTRACE (mouseUp);
5446   [self mouseDown: theEvent];
5450 - (void)rightMouseUp: (NSEvent *)theEvent
5452   NSTRACE (rightMouseUp);
5453   [self mouseDown: theEvent];
5457 - (void)otherMouseUp: (NSEvent *)theEvent
5459   NSTRACE (otherMouseUp);
5460   [self mouseDown: theEvent];
5464 - (void) scrollWheel: (NSEvent *)theEvent
5466   NSTRACE (scrollWheel);
5467   [self mouseDown: theEvent];
5471 /* Tell emacs the mouse has moved. */
5472 - (void)mouseMoved: (NSEvent *)e
5474   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5475   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5476   Lisp_Object frame;
5477   NSPoint pt;
5479 //  NSTRACE (mouseMoved);
5481   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5482   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5483   dpyinfo->last_mouse_motion_x = pt.x;
5484   dpyinfo->last_mouse_motion_y = pt.y;
5486   /* update any mouse face */
5487   if (hlinfo->mouse_face_hidden)
5488     {
5489       hlinfo->mouse_face_hidden = 0;
5490       clear_mouse_face (hlinfo);
5491     }
5493   /* tooltip handling */
5494   previous_help_echo_string = help_echo_string;
5495   help_echo_string = Qnil;
5497   if (!NILP (Vmouse_autoselect_window))
5498     {
5499       NSTRACE (mouse_autoselect_window);
5500       static Lisp_Object last_mouse_window;
5501       Lisp_Object window
5502         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5504       if (WINDOWP (window)
5505           && !EQ (window, last_mouse_window)
5506           && !EQ (window, selected_window)
5507           && (focus_follows_mouse
5508               || (EQ (XWINDOW (window)->frame,
5509                       XWINDOW (selected_window)->frame))))
5510         {
5511           NSTRACE (in_window);
5512           emacs_event->kind = SELECT_WINDOW_EVENT;
5513           emacs_event->frame_or_window = window;
5514           EV_TRAILER2 (e);
5515         }
5516       /* Remember the last window where we saw the mouse.  */
5517       last_mouse_window = window;
5518     }
5520   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5521     help_echo_string = previous_help_echo_string;
5523   XSETFRAME (frame, emacsframe);
5524   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5525     {
5526       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5527          (note_mouse_highlight), which is called through the
5528          note_mouse_movement () call above */
5529       gen_help_event (help_echo_string, frame, help_echo_window,
5530                       help_echo_object, help_echo_pos);
5531     }
5532   else
5533     {
5534       help_echo_string = Qnil;
5535       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5536     }
5538   if (emacsframe->mouse_moved && send_appdefined)
5539     ns_send_appdefined (-1);
5543 - (void)mouseDragged: (NSEvent *)e
5545   NSTRACE (mouseDragged);
5546   [self mouseMoved: e];
5550 - (void)rightMouseDragged: (NSEvent *)e
5552   NSTRACE (rightMouseDragged);
5553   [self mouseMoved: e];
5557 - (void)otherMouseDragged: (NSEvent *)e
5559   NSTRACE (otherMouseDragged);
5560   [self mouseMoved: e];
5564 - (BOOL)windowShouldClose: (id)sender
5566   NSEvent *e =[[self window] currentEvent];
5568   NSTRACE (windowShouldClose);
5569   windowClosing = YES;
5570   if (!emacs_event)
5571     return NO;
5572   emacs_event->kind = DELETE_WINDOW_EVENT;
5573   emacs_event->modifiers = 0;
5574   emacs_event->code = 0;
5575   EV_TRAILER (e);
5576   /* Don't close this window, let this be done from lisp code.  */
5577   return NO;
5580 - (void) updateFrameSize: (BOOL) delay;
5582   NSWindow *window = [self window];
5583   NSRect wr = [window frame];
5584   int extra = 0;
5585   int gsextra = 0;
5586 #ifdef NS_IMPL_GNUSTEP
5587   gsextra = 3;
5588 #endif
5590   int oldc = cols, oldr = rows;
5591   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5592     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5593   int neww, newh;
5595   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5597   if (cols < MINWIDTH)
5598     cols = MINWIDTH;
5600   if (! [self isFullscreen])
5601     {
5602       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5603         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5604     }
5606   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5608   if (rows < MINHEIGHT)
5609     rows = MINHEIGHT;
5611   neww = (int)wr.size.width - emacsframe->border_width;
5612   newh = (int)wr.size.height - extra;
5614   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5615     {
5616       NSView *view = FRAME_NS_VIEW (emacsframe);
5617       NSWindow *win = [view window];
5618       NSSize sz = [win resizeIncrements];
5620       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5621       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5622       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5623       SET_FRAME_GARBAGED (emacsframe);
5624       cancel_mouse_face (emacsframe);
5626       // Did resize increments change because of a font change?
5627       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5628           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5629         {
5630           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5631           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5632           [win setResizeIncrements: sz];
5633         }
5635       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5636       [self windowDidMove:nil];   // Update top/left.
5637     }
5640 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5641 /* normalize frame to gridded text size */
5643   int extra = 0;
5644   int gsextra = 0;
5645 #ifdef NS_IMPL_GNUSTEP
5646   gsextra = 3;
5647 #endif
5649   NSTRACE (windowWillResize);
5650 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5652   if (fs_state == FULLSCREEN_MAXIMIZED
5653       && (maximized_width != (int)frameSize.width
5654           || maximized_height != (int)frameSize.height))
5655     [self setFSValue: FULLSCREEN_NONE];
5656   else if (fs_state == FULLSCREEN_WIDTH
5657            && maximized_width != (int)frameSize.width)
5658     [self setFSValue: FULLSCREEN_NONE];
5659   else if (fs_state == FULLSCREEN_HEIGHT
5660            && maximized_height != (int)frameSize.height)
5661     [self setFSValue: FULLSCREEN_NONE];
5662   if (fs_state == FULLSCREEN_NONE)
5663     maximized_width = maximized_height = -1;
5665   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5666                                          frameSize.width + gsextra);
5667   if (cols < MINWIDTH)
5668     cols = MINWIDTH;
5670   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5671                                            frameSize.height - extra);
5672   if (rows < MINHEIGHT)
5673     rows = MINHEIGHT;
5674 #ifdef NS_IMPL_COCOA
5675   {
5676     /* this sets window title to have size in it; the wm does this under GS */
5677     NSRect r = [[self window] frame];
5678     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5679       {
5680         if (old_title != 0)
5681           {
5682             xfree (old_title);
5683             old_title = 0;
5684           }
5685       }
5686     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5687       {
5688         char *size_title;
5689         NSWindow *window = [self window];
5690         if (old_title == 0)
5691           {
5692             char *t = strdup ([[[self window] title] UTF8String]);
5693             char *pos = strstr (t, "  â€”  ");
5694             if (pos)
5695               *pos = '\0';
5696             old_title = t;
5697           }
5698         size_title = xmalloc (strlen (old_title) + 40);
5699         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5700         [window setTitle: [NSString stringWithUTF8String: size_title]];
5701         [window display];
5702         xfree (size_title);
5703       }
5704   }
5705 #endif /* NS_IMPL_COCOA */
5706 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5708   return frameSize;
5712 - (void)windowDidResize: (NSNotification *)notification
5714   if (! [self fsIsNative])
5715     {
5716       NSWindow *theWindow = [notification object];
5717       /* We can get notification on the non-FS window when in
5718          fullscreen mode.  */
5719       if ([self window] != theWindow) return;
5720     }
5722 #ifdef NS_IMPL_GNUSTEP
5723   NSWindow *theWindow = [notification object];
5725    /* In GNUstep, at least currently, it's possible to get a didResize
5726       without getting a willResize.. therefore we need to act as if we got
5727       the willResize now */
5728   NSSize sz = [theWindow frame].size;
5729   sz = [self windowWillResize: theWindow toSize: sz];
5730 #endif /* NS_IMPL_GNUSTEP */
5732   NSTRACE (windowDidResize);
5733 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5735 if (cols > 0 && rows > 0)
5736     {
5737       [self updateFrameSize: YES];
5738     }
5740   ns_send_appdefined (-1);
5743 #ifdef NS_IMPL_COCOA
5744 - (void)viewDidEndLiveResize
5746   [super viewDidEndLiveResize];
5747   if (old_title != 0)
5748     {
5749       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5750       xfree (old_title);
5751       old_title = 0;
5752     }
5753   maximizing_resize = NO;
5755 #endif /* NS_IMPL_COCOA */
5758 - (void)windowDidBecomeKey: (NSNotification *)notification
5759 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5761   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5762   struct frame *old_focus = dpyinfo->x_focus_frame;
5764   NSTRACE (windowDidBecomeKey);
5766   if (emacsframe != old_focus)
5767     dpyinfo->x_focus_frame = emacsframe;
5769   ns_frame_rehighlight (emacsframe);
5771   if (emacs_event)
5772     {
5773       emacs_event->kind = FOCUS_IN_EVENT;
5774       EV_TRAILER ((id)nil);
5775     }
5779 - (void)windowDidResignKey: (NSNotification *)notification
5780 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5782   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5783   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5784   NSTRACE (windowDidResignKey);
5786   if (is_focus_frame)
5787     dpyinfo->x_focus_frame = 0;
5789   ns_frame_rehighlight (emacsframe);
5791   /* FIXME: for some reason needed on second and subsequent clicks away
5792             from sole-frame Emacs to get hollow box to show */
5793   if (!windowClosing && [[self window] isVisible] == YES)
5794     {
5795       x_update_cursor (emacsframe, 1);
5796       x_set_frame_alpha (emacsframe);
5797     }
5799   if (emacs_event && is_focus_frame)
5800     {
5801       [self deleteWorkingText];
5802       emacs_event->kind = FOCUS_OUT_EVENT;
5803       EV_TRAILER ((id)nil);
5804     }
5808 - (void)windowWillMiniaturize: sender
5810   NSTRACE (windowWillMiniaturize);
5814 - (BOOL)isFlipped
5816   return YES;
5820 - (BOOL)isOpaque
5822   return NO;
5826 - initFrameFromEmacs: (struct frame *)f
5828   NSRect r, wr;
5829   Lisp_Object tem;
5830   NSWindow *win;
5831   NSSize sz;
5832   NSColor *col;
5833   NSString *name;
5835   NSTRACE (initFrameFromEmacs);
5837   windowClosing = NO;
5838   processingCompose = NO;
5839   scrollbarsNeedingUpdate = 0;
5840   fs_state = FULLSCREEN_NONE;
5841   fs_before_fs = next_maximized = -1;
5842 #ifdef HAVE_NATIVE_FS
5843   fs_is_native = ns_use_native_fullscreen;
5844 #else
5845   fs_is_native = NO;
5846 #endif
5847   maximized_width = maximized_height = -1;
5848   nonfs_window = nil;
5850 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5852   ns_userRect = NSMakeRect (0, 0, 0, 0);
5853   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5854                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5855   [self initWithFrame: r];
5856   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5858   FRAME_NS_VIEW (f) = self;
5859   emacsframe = f;
5860 #ifdef NS_IMPL_COCOA
5861   old_title = 0;
5862   maximizing_resize = NO;
5863 #endif
5865   win = [[EmacsWindow alloc]
5866             initWithContentRect: r
5867                       styleMask: (NSResizableWindowMask |
5868 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5869                                   NSTitledWindowMask |
5870 #endif
5871                                   NSMiniaturizableWindowMask |
5872                                   NSClosableWindowMask)
5873                         backing: NSBackingStoreBuffered
5874                           defer: YES];
5876 #ifdef HAVE_NATIVE_FS
5877     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5878 #endif
5880   wr = [win frame];
5881   bwidth = f->border_width = wr.size.width - r.size.width;
5882   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5884   [win setAcceptsMouseMovedEvents: YES];
5885   [win setDelegate: self];
5886   [win useOptimizedDrawing: YES];
5888   sz.width = FRAME_COLUMN_WIDTH (f);
5889   sz.height = FRAME_LINE_HEIGHT (f);
5890   [win setResizeIncrements: sz];
5892   [[win contentView] addSubview: self];
5894   if (ns_drag_types)
5895     [self registerForDraggedTypes: ns_drag_types];
5897   tem = f->name;
5898   name = [NSString stringWithUTF8String:
5899                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5900   [win setTitle: name];
5902   /* toolbar support */
5903   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5904                          [NSString stringWithFormat: @"Emacs Frame %d",
5905                                    ns_window_num]];
5906   [win setToolbar: toolbar];
5907   [toolbar setVisible: NO];
5908 #ifdef NS_IMPL_COCOA
5909   {
5910     NSButton *toggleButton;
5911   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5912   [toggleButton setTarget: self];
5913   [toggleButton setAction: @selector (toggleToolbar: )];
5914   }
5915 #endif
5916   FRAME_TOOLBAR_HEIGHT (f) = 0;
5918   tem = f->icon_name;
5919   if (!NILP (tem))
5920     [win setMiniwindowTitle:
5921            [NSString stringWithUTF8String: SSDATA (tem)]];
5923   {
5924     NSScreen *screen = [win screen];
5926     if (screen != 0)
5927       [win setFrameTopLeftPoint: NSMakePoint
5928            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5929             IN_BOUND (-SCREENMAX,
5930                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5931   }
5933   [win makeFirstResponder: self];
5935   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5936                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5937   [win setBackgroundColor: col];
5938   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5939     [win setOpaque: NO];
5941   [self allocateGState];
5943   [NSApp registerServicesMenuSendTypes: ns_send_types
5944                            returnTypes: nil];
5946   ns_window_num++;
5947   return self;
5951 - (void)windowDidMove: sender
5953   NSWindow *win = [self window];
5954   NSRect r = [win frame];
5955   NSArray *screens = [NSScreen screens];
5956   NSScreen *screen = [screens objectAtIndex: 0];
5958   NSTRACE (windowDidMove);
5960   if (!emacsframe->output_data.ns)
5961     return;
5962   if (screen != nil)
5963     {
5964       emacsframe->left_pos = r.origin.x;
5965       emacsframe->top_pos =
5966         [screen frame].size.height - (r.origin.y + r.size.height);
5967     }
5971 /* Called AFTER method below, but before our windowWillResize call there leads
5972    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5973    location so set_window_size moves the frame. */
5974 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5976   emacsframe->output_data.ns->zooming = 1;
5977   return YES;
5981 /* Override to do something slightly nonstandard, but nice.  First click on
5982    zoom button will zoom vertically.  Second will zoom completely.  Third
5983    returns to original. */
5984 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5985                         defaultFrame:(NSRect)defaultFrame
5987   NSRect result = [sender frame];
5989   NSTRACE (windowWillUseStandardFrame);
5991   if (fs_before_fs != -1) /* Entering fullscreen */
5992       {
5993         result = defaultFrame;
5994       }
5995   else if (next_maximized == FULLSCREEN_HEIGHT
5996       || (next_maximized == -1
5997           && abs (defaultFrame.size.height - result.size.height)
5998           > FRAME_LINE_HEIGHT (emacsframe)))
5999     {
6000       /* first click */
6001       ns_userRect = result;
6002       maximized_height = result.size.height = defaultFrame.size.height;
6003       maximized_width = -1;
6004       result.origin.y = defaultFrame.origin.y;
6005       [self setFSValue: FULLSCREEN_HEIGHT];
6006 #ifdef NS_IMPL_COCOA
6007       maximizing_resize = YES;
6008 #endif
6009     }
6010   else if (next_maximized == FULLSCREEN_WIDTH)
6011     {
6012       ns_userRect = result;
6013       maximized_width = result.size.width = defaultFrame.size.width;
6014       maximized_height = -1;
6015       result.origin.x = defaultFrame.origin.x;
6016       [self setFSValue: FULLSCREEN_WIDTH];
6017     }
6018   else if (next_maximized == FULLSCREEN_MAXIMIZED
6019            || (next_maximized == -1
6020                && abs (defaultFrame.size.width - result.size.width)
6021                > FRAME_COLUMN_WIDTH (emacsframe)))
6022     {
6023       result = defaultFrame;  /* second click */
6024       maximized_width = result.size.width;
6025       maximized_height = result.size.height;
6026       [self setFSValue: FULLSCREEN_MAXIMIZED];
6027 #ifdef NS_IMPL_COCOA
6028       maximizing_resize = YES;
6029 #endif
6030     }
6031   else
6032     {
6033       /* restore */
6034       result = ns_userRect.size.height ? ns_userRect : result;
6035       ns_userRect = NSMakeRect (0, 0, 0, 0);
6036 #ifdef NS_IMPL_COCOA
6037       maximizing_resize = fs_state != FULLSCREEN_NONE;
6038 #endif
6039       [self setFSValue: FULLSCREEN_NONE];
6040       maximized_width = maximized_height = -1;
6041     }
6043   if (fs_before_fs == -1) next_maximized = -1;
6044   [self windowWillResize: sender toSize: result.size];
6045   return result;
6049 - (void)windowDidDeminiaturize: sender
6051   NSTRACE (windowDidDeminiaturize);
6052   if (!emacsframe->output_data.ns)
6053     return;
6055   SET_FRAME_ICONIFIED (emacsframe, 0);
6056   SET_FRAME_VISIBLE (emacsframe, 1);
6057   windows_or_buffers_changed++;
6059   if (emacs_event)
6060     {
6061       emacs_event->kind = DEICONIFY_EVENT;
6062       EV_TRAILER ((id)nil);
6063     }
6067 - (void)windowDidExpose: sender
6069   NSTRACE (windowDidExpose);
6070   if (!emacsframe->output_data.ns)
6071     return;
6073   SET_FRAME_VISIBLE (emacsframe, 1);
6074   SET_FRAME_GARBAGED (emacsframe);
6076   if (send_appdefined)
6077     ns_send_appdefined (-1);
6081 - (void)windowDidMiniaturize: sender
6083   NSTRACE (windowDidMiniaturize);
6084   if (!emacsframe->output_data.ns)
6085     return;
6087   SET_FRAME_ICONIFIED (emacsframe, 1);
6088   SET_FRAME_VISIBLE (emacsframe, 0);
6090   if (emacs_event)
6091     {
6092       emacs_event->kind = ICONIFY_EVENT;
6093       EV_TRAILER ((id)nil);
6094     }
6097 #ifdef HAVE_NATIVE_FS
6098 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6099       willUseFullScreenPresentationOptions:
6100   (NSApplicationPresentationOptions)proposedOptions
6102   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6104 #endif
6106 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6108   fs_before_fs = fs_state;
6111 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6113   [self setFSValue: FULLSCREEN_BOTH];
6114   if (! [self fsIsNative])
6115     {
6116       [self windowDidBecomeKey:notification];
6117       [nonfs_window orderOut:self];
6118     }
6119   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6120     [toolbar setVisible:NO];
6123 - (void)windowWillExitFullScreen:(NSNotification *)notification
6125   if (next_maximized != -1)
6126     fs_before_fs = next_maximized;
6129 - (void)windowDidExitFullScreen:(NSNotification *)notification
6131   [self setFSValue: fs_before_fs];
6132   fs_before_fs = -1;
6133 #ifdef NS_IMPL_COCOA
6134   [self updateCollectionBehaviour];
6135 #endif
6136   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6137     {
6138       [toolbar setVisible:YES];
6139       update_frame_tool_bar (emacsframe);
6140       [self updateFrameSize:YES];
6141       [[self window] display];
6142     }
6143   else
6144     [toolbar setVisible:NO];
6146   if (next_maximized != -1)
6147     [[self window] performZoom:self];
6150 - (BOOL)fsIsNative
6152   return fs_is_native;
6155 - (BOOL)isFullscreen
6157   if (! fs_is_native) return nonfs_window != nil;
6158 #ifdef HAVE_NATIVE_FS
6159   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6160 #else
6161   return NO;
6162 #endif
6165 #ifdef HAVE_NATIVE_FS
6166 - (void)updateCollectionBehaviour
6168   if (! [self isFullscreen])
6169     {
6170       NSWindow *win = [self window];
6171       NSWindowCollectionBehavior b = [win collectionBehavior];
6172       if (ns_use_native_fullscreen)
6173         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6174       else
6175         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6177       [win setCollectionBehavior: b];
6178       fs_is_native = ns_use_native_fullscreen;
6179     }
6181 #endif
6183 - (void)toggleFullScreen: (id)sender
6185   NSWindow *w, *fw;
6186   BOOL onFirstScreen;
6187   struct frame *f;
6188   NSSize sz;
6189   NSRect r, wr;
6190   NSColor *col;
6192   if (fs_is_native)
6193     {
6194 #ifdef NS_IMPL_COCOA
6195       [[self window] toggleFullScreen:sender];
6196 #endif
6197       return;
6198     }
6200   w = [self window];
6201   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6202   f = emacsframe;
6203   wr = [w frame];
6204   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6205                                  (FRAME_DEFAULT_FACE (f)),
6206                                  f);
6208   sz.width = FRAME_COLUMN_WIDTH (f);
6209   sz.height = FRAME_LINE_HEIGHT (f);
6211   if (fs_state != FULLSCREEN_BOTH)
6212     {
6213       /* Hide dock and menubar if we are on the primary screen.  */
6214       if (onFirstScreen)
6215         {
6216 #if defined (NS_IMPL_COCOA) && \
6217   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6218           NSApplicationPresentationOptions options
6219             = NSApplicationPresentationAutoHideDock
6220             | NSApplicationPresentationAutoHideMenuBar;
6222           [NSApp setPresentationOptions: options];
6223 #else
6224           [NSMenu setMenuBarVisible:NO];
6225 #endif
6226         }
6228       fw = [[EmacsFSWindow alloc]
6229                        initWithContentRect:[w contentRectForFrameRect:wr]
6230                                  styleMask:NSBorderlessWindowMask
6231                                    backing:NSBackingStoreBuffered
6232                                      defer:YES
6233                                     screen:[w screen]];
6235       [fw setContentView:[w contentView]];
6236       [fw setTitle:[w title]];
6237       [fw setDelegate:self];
6238       [fw setAcceptsMouseMovedEvents: YES];
6239       [fw useOptimizedDrawing: YES];
6240       [fw setResizeIncrements: sz];
6241       [fw setBackgroundColor: col];
6242       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6243         [fw setOpaque: NO];
6245       f->border_width = 0;
6246       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6247       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6248       FRAME_TOOLBAR_HEIGHT (f) = 0;
6250       nonfs_window = w;
6252       [self windowWillEnterFullScreen:nil];
6253       [fw makeKeyAndOrderFront:NSApp];
6254       [fw makeFirstResponder:self];
6255       [w orderOut:self];
6256       r = [fw frameRectForContentRect:[[fw screen] frame]];
6257       [fw setFrame: r display:YES animate:YES];
6258       [self windowDidEnterFullScreen:nil];
6259       [fw display];
6260     }
6261   else
6262     {
6263       fw = w;
6264       w = nonfs_window;
6265       nonfs_window = nil;
6267       if (onFirstScreen)
6268         {
6269 #if defined (NS_IMPL_COCOA) && \
6270   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6271           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6272 #else
6273           [NSMenu setMenuBarVisible:YES];
6274 #endif
6275         }
6277       [w setContentView:[fw contentView]];
6278       [w setResizeIncrements: sz];
6279       [w setBackgroundColor: col];
6280       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6281         [w setOpaque: NO];
6283       f->border_width = bwidth;
6284       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6285       if (FRAME_EXTERNAL_TOOL_BAR (f))
6286         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6288       [self windowWillExitFullScreen:nil];
6289       [fw setFrame: [w frame] display:YES animate:YES];
6290       [fw close];
6291       [w makeKeyAndOrderFront:NSApp];
6292       [self windowDidExitFullScreen:nil];
6293       [self updateFrameSize:YES];
6294     }
6297 - (void)handleFS
6299   if (fs_state != emacsframe->want_fullscreen)
6300     {
6301       if (fs_state == FULLSCREEN_BOTH)
6302         {
6303           [self toggleFullScreen:self];
6304         }
6306       switch (emacsframe->want_fullscreen)
6307         {
6308         case FULLSCREEN_BOTH:
6309           [self toggleFullScreen:self];
6310           break;
6311         case FULLSCREEN_WIDTH:
6312           next_maximized = FULLSCREEN_WIDTH;
6313           if (fs_state != FULLSCREEN_BOTH)
6314             [[self window] performZoom:self];
6315           break;
6316         case FULLSCREEN_HEIGHT:
6317           next_maximized = FULLSCREEN_HEIGHT;
6318           if (fs_state != FULLSCREEN_BOTH)
6319             [[self window] performZoom:self];
6320           break;
6321         case FULLSCREEN_MAXIMIZED:
6322           next_maximized = FULLSCREEN_MAXIMIZED;
6323           if (fs_state != FULLSCREEN_BOTH)
6324             [[self window] performZoom:self];
6325           break;
6326         case FULLSCREEN_NONE:
6327           if (fs_state != FULLSCREEN_BOTH)
6328             {
6329               next_maximized = FULLSCREEN_NONE;
6330               [[self window] performZoom:self];
6331             }
6332           break;
6333         }
6335       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6336     }
6340 - (void) setFSValue: (int)value
6342   Lisp_Object lval = Qnil;
6343   switch (value)
6344     {
6345     case FULLSCREEN_BOTH:
6346       lval = Qfullboth;
6347       break;
6348     case FULLSCREEN_WIDTH:
6349       lval = Qfullwidth;
6350       break;
6351     case FULLSCREEN_HEIGHT:
6352       lval = Qfullheight;
6353       break;
6354     case FULLSCREEN_MAXIMIZED:
6355       lval = Qmaximized;
6356       break;
6357     }
6358   store_frame_param (emacsframe, Qfullscreen, lval);
6359   fs_state = value;
6362 - (void)mouseEntered: (NSEvent *)theEvent
6364   NSTRACE (mouseEntered);
6365   if (emacsframe)
6366     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6367       = EV_TIMESTAMP (theEvent);
6371 - (void)mouseExited: (NSEvent *)theEvent
6373   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6375   NSTRACE (mouseExited);
6377   if (!hlinfo)
6378     return;
6380   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6381     = EV_TIMESTAMP (theEvent);
6383   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6384     {
6385       clear_mouse_face (hlinfo);
6386       hlinfo->mouse_face_mouse_frame = 0;
6387     }
6391 - menuDown: sender
6393   NSTRACE (menuDown);
6394   if (context_menu_value == -1)
6395     context_menu_value = [sender tag];
6396   else
6397     {
6398       NSInteger tag = [sender tag];
6399       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6400                                     emacsframe->menu_bar_vector,
6401                                     (void *)tag);
6402     }
6404   ns_send_appdefined (-1);
6405   return self;
6409 - (EmacsToolbar *)toolbar
6411   return toolbar;
6415 /* this gets called on toolbar button click */
6416 - toolbarClicked: (id)item
6418   NSEvent *theEvent;
6419   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6421   NSTRACE (toolbarClicked);
6423   if (!emacs_event)
6424     return self;
6426   /* send first event (for some reason two needed) */
6427   theEvent = [[self window] currentEvent];
6428   emacs_event->kind = TOOL_BAR_EVENT;
6429   XSETFRAME (emacs_event->arg, emacsframe);
6430   EV_TRAILER (theEvent);
6432   emacs_event->kind = TOOL_BAR_EVENT;
6433 /*   XSETINT (emacs_event->code, 0); */
6434   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6435                            idx + TOOL_BAR_ITEM_KEY);
6436   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6437   EV_TRAILER (theEvent);
6438   return self;
6442 - toggleToolbar: (id)sender
6444   if (!emacs_event)
6445     return self;
6447   emacs_event->kind = NS_NONKEY_EVENT;
6448   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6449   EV_TRAILER ((id)nil);
6450   return self;
6454 - (void)drawRect: (NSRect)rect
6456   int x = NSMinX (rect), y = NSMinY (rect);
6457   int width = NSWidth (rect), height = NSHeight (rect);
6459   NSTRACE (drawRect);
6461   if (!emacsframe || !emacsframe->output_data.ns)
6462     return;
6464   ns_clear_frame_area (emacsframe, x, y, width, height);
6465   expose_frame (emacsframe, x, y, width, height);
6467   /*
6468     drawRect: may be called (at least in OS X 10.5) for invisible
6469     views as well for some reason.  Thus, do not infer visibility
6470     here.
6472     emacsframe->async_visible = 1;
6473     emacsframe->async_iconified = 0;
6474   */
6478 /* NSDraggingDestination protocol methods.  Actually this is not really a
6479    protocol, but a category of Object.  O well...  */
6481 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6483   NSTRACE (draggingEntered);
6484   return NSDragOperationGeneric;
6488 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6490   return YES;
6494 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6496   id pb;
6497   int x, y;
6498   NSString *type;
6499   NSEvent *theEvent = [[self window] currentEvent];
6500   NSPoint position;
6502   NSTRACE (performDragOperation);
6504   if (!emacs_event)
6505     return NO;
6507   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6508   x = lrint (position.x);  y = lrint (position.y);
6510   pb = [sender draggingPasteboard];
6511   type = [pb availableTypeFromArray: ns_drag_types];
6512   if (type == 0)
6513     {
6514       return NO;
6515     }
6516   else if ([type isEqualToString: NSFilenamesPboardType])
6517     {
6518       NSArray *files;
6519       NSEnumerator *fenum;
6520       NSString *file;
6522       if (!(files = [pb propertyListForType: type]))
6523         return NO;
6525       fenum = [files objectEnumerator];
6526       while ( (file = [fenum nextObject]) )
6527         {
6528           emacs_event->kind = NS_NONKEY_EVENT;
6529           emacs_event->code = KEY_NS_DRAG_FILE;
6530           XSETINT (emacs_event->x, x);
6531           XSETINT (emacs_event->y, y);
6532           ns_input_file = append2 (ns_input_file,
6533                                    build_string ([file UTF8String]));
6534           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6535           EV_TRAILER (theEvent);
6536         }
6537       return YES;
6538     }
6539   else if ([type isEqualToString: NSURLPboardType])
6540     {
6541       NSString *file;
6542       NSURL *fileURL;
6544       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6545           [fileURL isFileURL] == NO)
6546         return NO;
6548       file = [fileURL path];
6549       emacs_event->kind = NS_NONKEY_EVENT;
6550       emacs_event->code = KEY_NS_DRAG_FILE;
6551       XSETINT (emacs_event->x, x);
6552       XSETINT (emacs_event->y, y);
6553       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6554       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6555       EV_TRAILER (theEvent);
6556       return YES;
6557     }
6558   else if ([type isEqualToString: NSStringPboardType]
6559            || [type isEqualToString: NSTabularTextPboardType])
6560     {
6561       NSString *data;
6563       if (! (data = [pb stringForType: type]))
6564         return NO;
6566       emacs_event->kind = NS_NONKEY_EVENT;
6567       emacs_event->code = KEY_NS_DRAG_TEXT;
6568       XSETINT (emacs_event->x, x);
6569       XSETINT (emacs_event->y, y);
6570       ns_input_text = build_string ([data UTF8String]);
6571       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6572       EV_TRAILER (theEvent);
6573       return YES;
6574     }
6575   else if ([type isEqualToString: NSColorPboardType])
6576     {
6577       NSColor *c = [NSColor colorFromPasteboard: pb];
6578       emacs_event->kind = NS_NONKEY_EVENT;
6579       emacs_event->code = KEY_NS_DRAG_COLOR;
6580       XSETINT (emacs_event->x, x);
6581       XSETINT (emacs_event->y, y);
6582       ns_input_color = ns_color_to_lisp (c);
6583       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6584       EV_TRAILER (theEvent);
6585       return YES;
6586     }
6587   else if ([type isEqualToString: NSFontPboardType])
6588     {
6589       /* impl based on GNUstep NSTextView.m */
6590       NSData *data = [pb dataForType: NSFontPboardType];
6591       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6592       NSFont *font = [dict objectForKey: NSFontAttributeName];
6593       char fontSize[10];
6595       if (font == nil)
6596         return NO;
6598       emacs_event->kind = NS_NONKEY_EVENT;
6599       emacs_event->code = KEY_NS_CHANGE_FONT;
6600       XSETINT (emacs_event->x, x);
6601       XSETINT (emacs_event->y, y);
6602       ns_input_font = build_string ([[font fontName] UTF8String]);
6603       snprintf (fontSize, 10, "%f", [font pointSize]);
6604       ns_input_fontsize = build_string (fontSize);
6605       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6606       EV_TRAILER (theEvent);
6607       return YES;
6608     }
6609   else
6610     {
6611       error ("Invalid data type in dragging pasteboard.");
6612       return NO;
6613     }
6617 - (id) validRequestorForSendType: (NSString *)typeSent
6618                       returnType: (NSString *)typeReturned
6620   NSTRACE (validRequestorForSendType);
6621   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6622       && typeReturned == nil)
6623     {
6624       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6625         return self;
6626     }
6628   return [super validRequestorForSendType: typeSent
6629                                returnType: typeReturned];
6633 /* The next two methods are part of NSServicesRequests informal protocol,
6634    supposedly called when a services menu item is chosen from this app.
6635    But this should not happen because we override the services menu with our
6636    own entries which call ns-perform-service.
6637    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6638    So let's at least stub them out until further investigation can be done. */
6640 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6642   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6643      be written into the buffer in place of the existing selection..
6644      ordinary service calls go through functions defined in ns-win.el */
6645   return NO;
6648 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6650   NSArray *typesDeclared;
6651   Lisp_Object val;
6653   /* We only support NSStringPboardType */
6654   if ([types containsObject:NSStringPboardType] == NO) {
6655     return NO;
6656   }
6658   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6659   if (CONSP (val) && SYMBOLP (XCAR (val)))
6660     {
6661       val = XCDR (val);
6662       if (CONSP (val) && NILP (XCDR (val)))
6663         val = XCAR (val);
6664     }
6665   if (! STRINGP (val))
6666     return NO;
6668   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6669   [pb declareTypes:typesDeclared owner:nil];
6670   ns_string_to_pasteboard (pb, val);
6671   return YES;
6675 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6676    (gives a miniaturized version of the window); currently we use the latter for
6677    frames whose active buffer doesn't correspond to any file
6678    (e.g., '*scratch*') */
6679 - setMiniwindowImage: (BOOL) setMini
6681   id image = [[self window] miniwindowImage];
6682   NSTRACE (setMiniwindowImage);
6684   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6685      about "AppleDockIconEnabled" notwithstanding, however the set message
6686      below has its effect nonetheless. */
6687   if (image != emacsframe->output_data.ns->miniimage)
6688     {
6689       if (image && [image isKindOfClass: [EmacsImage class]])
6690         [image release];
6691       [[self window] setMiniwindowImage:
6692                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6693     }
6695   return self;
6699 - (void) setRows: (int) r andColumns: (int) c
6701   rows = r;
6702   cols = c;
6705 @end  /* EmacsView */
6709 /* ==========================================================================
6711     EmacsWindow implementation
6713    ========================================================================== */
6715 @implementation EmacsWindow
6717 #ifdef NS_IMPL_COCOA
6718 - (id)accessibilityAttributeValue:(NSString *)attribute
6720   Lisp_Object str = Qnil;
6721   struct frame *f = SELECTED_FRAME ();
6722   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6724   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6725     return NSAccessibilityTextFieldRole;
6727   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6728       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6729     {
6730       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6731     }
6732   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6733     {
6734       if (! NILP (BVAR (curbuf, mark_active)))
6735           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6737       if (NILP (str))
6738         {
6739           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6740           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6741           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6743           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6744             str = make_uninit_multibyte_string (range, byte_range);
6745           else
6746             str = make_uninit_string (range);
6747           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6748              Is this a problem?  */
6749           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6750         }
6751     }
6754   if (! NILP (str))
6755     {
6756       if (CONSP (str) && SYMBOLP (XCAR (str)))
6757         {
6758           str = XCDR (str);
6759           if (CONSP (str) && NILP (XCDR (str)))
6760             str = XCAR (str);
6761         }
6762       if (STRINGP (str))
6763         {
6764           const char *utfStr = SSDATA (str);
6765           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6766           return nsStr;
6767         }
6768     }
6770   return [super accessibilityAttributeValue:attribute];
6772 #endif /* NS_IMPL_COCOA */
6774 /* If we have multiple monitors, one above the other, we don't want to
6775    restrict the height to just one monitor.  So we override this.  */
6776 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6778   /* When making the frame visible for the first time or if there is just
6779      one screen, we want to constrain.  Other times not.  */
6780   NSUInteger nr_screens = [[NSScreen screens] count];
6781   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6782   NSTRACE (constrainFrameRect);
6784   if (nr_screens == 1)
6785     {
6786       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6787       return r;
6788     }
6790   if (f->output_data.ns->dont_constrain
6791       || ns_menu_bar_should_be_hidden ())
6792     return frameRect;
6794   f->output_data.ns->dont_constrain = 1;
6795   return [super constrainFrameRect:frameRect toScreen:screen];
6798 @end /* EmacsWindow */
6801 @implementation EmacsFSWindow
6803 - (BOOL)canBecomeKeyWindow
6805   return YES;
6808 - (BOOL)canBecomeMainWindow
6810   return YES;
6813 @end
6815 /* ==========================================================================
6817     EmacsScroller implementation
6819    ========================================================================== */
6822 @implementation EmacsScroller
6824 /* for repeat button push */
6825 #define SCROLL_BAR_FIRST_DELAY 0.5
6826 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6828 + (CGFloat) scrollerWidth
6830   /* TODO: if we want to allow variable widths, this is the place to do it,
6831            however neither GNUstep nor Cocoa support it very well */
6832   return [NSScroller scrollerWidth];
6836 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6838   NSTRACE (EmacsScroller_initFrame);
6840   r.size.width = [EmacsScroller scrollerWidth];
6841   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6842   [self setContinuous: YES];
6843   [self setEnabled: YES];
6845   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6846      locked against the top and bottom edges, and right edge on OS X, where
6847      scrollers are on right. */
6848 #ifdef NS_IMPL_GNUSTEP
6849   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6850 #else
6851   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6852 #endif
6854   win = nwin;
6855   condemned = NO;
6856   pixel_height = NSHeight (r);
6857   if (pixel_height == 0) pixel_height = 1;
6858   min_portion = 20 / pixel_height;
6860   frame = XFRAME (XWINDOW (win)->frame);
6861   if (FRAME_LIVE_P (frame))
6862     {
6863       int i;
6864       EmacsView *view = FRAME_NS_VIEW (frame);
6865       NSView *sview = [[view window] contentView];
6866       NSArray *subs = [sview subviews];
6868       /* disable optimization stopping redraw of other scrollbars */
6869       view->scrollbarsNeedingUpdate = 0;
6870       for (i =[subs count]-1; i >= 0; i--)
6871         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6872           view->scrollbarsNeedingUpdate++;
6873       [sview addSubview: self];
6874     }
6876 /*  [self setFrame: r]; */
6878   return self;
6882 - (void)setFrame: (NSRect)newRect
6884   NSTRACE (EmacsScroller_setFrame);
6885 /*  block_input (); */
6886   pixel_height = NSHeight (newRect);
6887   if (pixel_height == 0) pixel_height = 1;
6888   min_portion = 20 / pixel_height;
6889   [super setFrame: newRect];
6890   [self display];
6891 /*  unblock_input (); */
6895 - (void)dealloc
6897   NSTRACE (EmacsScroller_dealloc);
6898   if (!NILP (win))
6899     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6900   [super dealloc];
6904 - condemn
6906   NSTRACE (condemn);
6907   condemned =YES;
6908   return self;
6912 - reprieve
6914   NSTRACE (reprieve);
6915   condemned =NO;
6916   return self;
6920 - judge
6922   NSTRACE (judge);
6923   if (condemned)
6924     {
6925       EmacsView *view;
6926       block_input ();
6927       /* ensure other scrollbar updates after deletion */
6928       view = (EmacsView *)FRAME_NS_VIEW (frame);
6929       if (view != nil)
6930         view->scrollbarsNeedingUpdate++;
6931       [self removeFromSuperview];
6932       [self release];
6933       unblock_input ();
6934     }
6935   return self;
6939 - (void)resetCursorRects
6941   NSRect visible = [self visibleRect];
6942   NSTRACE (resetCursorRects);
6944   if (!NSIsEmptyRect (visible))
6945     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6946   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6950 - (int) checkSamePosition: (int) position portion: (int) portion
6951                     whole: (int) whole
6953   return em_position ==position && em_portion ==portion && em_whole ==whole
6954     && portion != whole; /* needed for resize empty buf */
6958 - setPosition: (int)position portion: (int)portion whole: (int)whole
6960   NSTRACE (setPosition);
6962   em_position = position;
6963   em_portion = portion;
6964   em_whole = whole;
6966   if (portion >= whole)
6967     {
6968 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6969       [self setKnobProportion: 1.0];
6970       [self setDoubleValue: 1.0];
6971 #else
6972       [self setFloatValue: 0.0 knobProportion: 1.0];
6973 #endif
6974     }
6975   else
6976     {
6977       float pos;
6978       CGFloat por;
6979       portion = max ((float)whole*min_portion/pixel_height, portion);
6980       pos = (float)position / (whole - portion);
6981       por = (CGFloat)portion/whole;
6982 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6983       [self setKnobProportion: por];
6984       [self setDoubleValue: pos];
6985 #else
6986       [self setFloatValue: pos knobProportion: por];
6987 #endif
6988     }
6990   /* Events may come here even if the event loop is not running.
6991      If we don't enter the event loop, the scroll bar will not update.
6992      So send SIGIO to ourselves.  */
6993   if (apploopnr == 0) raise (SIGIO);
6995   return self;
6998 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6999      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7000 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7001                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7003   *part = last_hit_part;
7004   *window = win;
7005   XSETINT (*y, pixel_height);
7006   if ([self floatValue] > 0.999F)
7007     XSETINT (*x, pixel_height);
7008   else
7009     XSETINT (*x, pixel_height * [self floatValue]);
7013 /* set up emacs_event */
7014 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7016   if (!emacs_event)
7017     return;
7019   emacs_event->part = last_hit_part;
7020   emacs_event->code = 0;
7021   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7022   emacs_event->frame_or_window = win;
7023   emacs_event->timestamp = EV_TIMESTAMP (e);
7024   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7025   emacs_event->arg = Qnil;
7026   XSETINT (emacs_event->x, loc * pixel_height);
7027   XSETINT (emacs_event->y, pixel_height-20);
7029   if (q_event_ptr)
7030     {
7031       n_emacs_events_pending++;
7032       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7033     }
7034   else
7035     hold_event (emacs_event);
7036   EVENT_INIT (*emacs_event);
7037   ns_send_appdefined (-1);
7041 /* called manually thru timer to implement repeated button action w/hold-down */
7042 - repeatScroll: (NSTimer *)scrollEntry
7044   NSEvent *e = [[self window] currentEvent];
7045   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7046   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7048   /* clear timer if need be */
7049   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7050     {
7051         [scroll_repeat_entry invalidate];
7052         [scroll_repeat_entry release];
7053         scroll_repeat_entry = nil;
7055         if (inKnob)
7056           return self;
7058         scroll_repeat_entry
7059           = [[NSTimer scheduledTimerWithTimeInterval:
7060                         SCROLL_BAR_CONTINUOUS_DELAY
7061                                             target: self
7062                                           selector: @selector (repeatScroll:)
7063                                           userInfo: 0
7064                                            repeats: YES]
7065               retain];
7066     }
7068   [self sendScrollEventAtLoc: 0 fromEvent: e];
7069   return self;
7073 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7074    mouseDragged events without going into a modal loop. */
7075 - (void)mouseDown: (NSEvent *)e
7077   NSRect sr, kr;
7078   /* hitPart is only updated AFTER event is passed on */
7079   NSScrollerPart part = [self testPart: [e locationInWindow]];
7080   CGFloat inc = 0.0, loc, kloc, pos;
7081   int edge = 0;
7083   NSTRACE (EmacsScroller_mouseDown);
7085   switch (part)
7086     {
7087     case NSScrollerDecrementPage:
7088         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7089     case NSScrollerIncrementPage:
7090         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7091     case NSScrollerDecrementLine:
7092       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7093     case NSScrollerIncrementLine:
7094       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7095     case NSScrollerKnob:
7096       last_hit_part = scroll_bar_handle; break;
7097     case NSScrollerKnobSlot:  /* GNUstep-only */
7098       last_hit_part = scroll_bar_move_ratio; break;
7099     default:  /* NSScrollerNoPart? */
7100       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7101                (long) part);
7102       return;
7103     }
7105   if (inc != 0.0)
7106     {
7107       pos = 0;      /* ignored */
7109       /* set a timer to repeat, as we can't let superclass do this modally */
7110       scroll_repeat_entry
7111         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7112                                             target: self
7113                                           selector: @selector (repeatScroll:)
7114                                           userInfo: 0
7115                                            repeats: YES]
7116             retain];
7117     }
7118   else
7119     {
7120       /* handle, or on GNUstep possibly slot */
7121       NSEvent *fake_event;
7123       /* compute float loc in slot and mouse offset on knob */
7124       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7125                       toView: nil];
7126       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7127       if (loc <= 0.0)
7128         {
7129           loc = 0.0;
7130           edge = -1;
7131         }
7132       else if (loc >= NSHeight (sr))
7133         {
7134           loc = NSHeight (sr);
7135           edge = 1;
7136         }
7138       if (edge)
7139         kloc = 0.5 * edge;
7140       else
7141         {
7142           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7143                           toView: nil];
7144           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7145         }
7146       last_mouse_offset = kloc;
7148       /* if knob, tell emacs a location offset by knob pos
7149          (to indicate top of handle) */
7150       if (part == NSScrollerKnob)
7151           pos = (loc - last_mouse_offset) / NSHeight (sr);
7152       else
7153         /* else this is a slot click on GNUstep: go straight there */
7154         pos = loc / NSHeight (sr);
7156       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7157       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7158                                       location: [e locationInWindow]
7159                                  modifierFlags: [e modifierFlags]
7160                                      timestamp: [e timestamp]
7161                                   windowNumber: [e windowNumber]
7162                                        context: [e context]
7163                                    eventNumber: [e eventNumber]
7164                                     clickCount: [e clickCount]
7165                                       pressure: [e pressure]];
7166       [super mouseUp: fake_event];
7167     }
7169   if (part != NSScrollerKnob)
7170     [self sendScrollEventAtLoc: pos fromEvent: e];
7174 /* Called as we manually track scroller drags, rather than superclass. */
7175 - (void)mouseDragged: (NSEvent *)e
7177     NSRect sr;
7178     double loc, pos;
7180     NSTRACE (EmacsScroller_mouseDragged);
7182       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7183                       toView: nil];
7184       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7186       if (loc <= 0.0)
7187         {
7188           loc = 0.0;
7189         }
7190       else if (loc >= NSHeight (sr) + last_mouse_offset)
7191         {
7192           loc = NSHeight (sr) + last_mouse_offset;
7193         }
7195       pos = (loc - last_mouse_offset) / NSHeight (sr);
7196       [self sendScrollEventAtLoc: pos fromEvent: e];
7200 - (void)mouseUp: (NSEvent *)e
7202   if (scroll_repeat_entry)
7203     {
7204       [scroll_repeat_entry invalidate];
7205       [scroll_repeat_entry release];
7206       scroll_repeat_entry = nil;
7207     }
7208   last_hit_part = 0;
7212 /* treat scrollwheel events in the bar as though they were in the main window */
7213 - (void) scrollWheel: (NSEvent *)theEvent
7215   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7216   [view mouseDown: theEvent];
7219 @end  /* EmacsScroller */
7222 #ifdef NS_IMPL_GNUSTEP
7223 /* Dummy class to get rid of startup warnings.  */
7224 @implementation EmacsDocument
7226 @end
7227 #endif
7230 /* ==========================================================================
7232    Font-related functions; these used to be in nsfaces.m
7234    ========================================================================== */
7237 Lisp_Object
7238 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7240   struct font *font = XFONT_OBJECT (font_object);
7242   if (fontset < 0)
7243     fontset = fontset_from_font (font_object);
7244   FRAME_FONTSET (f) = fontset;
7246   if (FRAME_FONT (f) == font)
7247     /* This font is already set in frame F.  There's nothing more to
7248        do.  */
7249     return font_object;
7251   FRAME_FONT (f) = font;
7253   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7254   FRAME_COLUMN_WIDTH (f) = font->average_width;
7255   FRAME_LINE_HEIGHT (f) = font->height;
7257   compute_fringe_widths (f, 1);
7259   /* Compute the scroll bar width in character columns.  */
7260   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7261     {
7262       int wid = FRAME_COLUMN_WIDTH (f);
7263       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7264         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7265     }
7266   else
7267     {
7268       int wid = FRAME_COLUMN_WIDTH (f);
7269       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7270     }
7272   /* Now make the frame display the given font.  */
7273   if (FRAME_NS_WINDOW (f) != 0)
7274         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7276   return font_object;
7280 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7281 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7282          in 1.43. */
7284 const char *
7285 ns_xlfd_to_fontname (const char *xlfd)
7286 /* --------------------------------------------------------------------------
7287     Convert an X font name (XLFD) to an NS font name.
7288     Only family is used.
7289     The string returned is temporarily allocated.
7290    -------------------------------------------------------------------------- */
7292   char *name = xmalloc (180);
7293   int i, len;
7294   const char *ret;
7296   if (!strncmp (xlfd, "--", 2))
7297     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7298   else
7299     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7301   /* stopgap for malformed XLFD input */
7302   if (strlen (name) == 0)
7303     strcpy (name, "Monaco");
7305   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7306      also uppercase after '-' or ' ' */
7307   name[0] = c_toupper (name[0]);
7308   for (len =strlen (name), i =0; i<len; i++)
7309     {
7310       if (name[i] == '$')
7311         {
7312           name[i] = '-';
7313           if (i+1<len)
7314             name[i+1] = c_toupper (name[i+1]);
7315         }
7316       else if (name[i] == '_')
7317         {
7318           name[i] = ' ';
7319           if (i+1<len)
7320             name[i+1] = c_toupper (name[i+1]);
7321         }
7322     }
7323 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7324   ret = [[NSString stringWithUTF8String: name] UTF8String];
7325   xfree (name);
7326   return ret;
7330 void
7331 syms_of_nsterm (void)
7333   NSTRACE (syms_of_nsterm);
7335   ns_antialias_threshold = 10.0;
7337   /* from 23+ we need to tell emacs what modifiers there are.. */
7338   DEFSYM (Qmodifier_value, "modifier-value");
7339   DEFSYM (Qalt, "alt");
7340   DEFSYM (Qhyper, "hyper");
7341   DEFSYM (Qmeta, "meta");
7342   DEFSYM (Qsuper, "super");
7343   DEFSYM (Qcontrol, "control");
7344   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7346   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7347   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7348   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7349   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7350   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7352   DEFVAR_LISP ("ns-input-file", ns_input_file,
7353               "The file specified in the last NS event.");
7354   ns_input_file =Qnil;
7356   DEFVAR_LISP ("ns-input-text", ns_input_text,
7357               "The data received in the last NS text drag event.");
7358   ns_input_text =Qnil;
7360   DEFVAR_LISP ("ns-working-text", ns_working_text,
7361               "String for visualizing working composition sequence.");
7362   ns_working_text =Qnil;
7364   DEFVAR_LISP ("ns-input-font", ns_input_font,
7365               "The font specified in the last NS event.");
7366   ns_input_font =Qnil;
7368   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7369               "The fontsize specified in the last NS event.");
7370   ns_input_fontsize =Qnil;
7372   DEFVAR_LISP ("ns-input-line", ns_input_line,
7373                "The line specified in the last NS event.");
7374   ns_input_line =Qnil;
7376   DEFVAR_LISP ("ns-input-color", ns_input_color,
7377                "The color specified in the last NS event.");
7378   ns_input_color =Qnil;
7380   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7381                "The service name specified in the last NS event.");
7382   ns_input_spi_name =Qnil;
7384   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7385                "The service argument specified in the last NS event.");
7386   ns_input_spi_arg =Qnil;
7388   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7389                "This variable describes the behavior of the alternate or option key.\n\
7390 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7391 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7392 at all, allowing it to be used at a lower level for accented character entry.");
7393   ns_alternate_modifier = Qmeta;
7395   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7396                "This variable describes the behavior of the right alternate or option key.\n\
7397 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7398 Set to left means be the same key as `ns-alternate-modifier'.\n\
7399 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7400 at all, allowing it to be used at a lower level for accented character entry.");
7401   ns_right_alternate_modifier = Qleft;
7403   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7404                "This variable describes the behavior of the command key.\n\
7405 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7406   ns_command_modifier = Qsuper;
7408   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7409                "This variable describes the behavior of the right command key.\n\
7410 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7411 Set to left means be the same key as `ns-command-modifier'.\n\
7412 Set to none means that the command / option key is not interpreted by Emacs\n\
7413 at all, allowing it to be used at a lower level for accented character entry.");
7414   ns_right_command_modifier = Qleft;
7416   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7417                "This variable describes the behavior of the control key.\n\
7418 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7419   ns_control_modifier = Qcontrol;
7421   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7422                "This variable describes the behavior of the right control key.\n\
7423 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7424 Set to left means be the same key as `ns-control-modifier'.\n\
7425 Set to none means that the control / option key is not interpreted by Emacs\n\
7426 at all, allowing it to be used at a lower level for accented character entry.");
7427   ns_right_control_modifier = Qleft;
7429   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7430                "This variable describes the behavior of the function key (on laptops).\n\
7431 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7432 Set to none means that the function key is not interpreted by Emacs at all,\n\
7433 allowing it to be used at a lower level for accented character entry.");
7434   ns_function_modifier = Qnone;
7436   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7437                "Non-nil (the default) means to render text antialiased.");
7438   ns_antialias_text = Qt;
7440   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7441                "Whether to confirm application quit using dialog.");
7442   ns_confirm_quit = Qnil;
7444   staticpro (&ns_display_name_list);
7445   ns_display_name_list = Qnil;
7447   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7448                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7449 Only works on OSX 10.6 or later.  */);
7450   ns_auto_hide_menu_bar = Qnil;
7452   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7453      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7454 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7455 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7456 Default is t for OSX >= 10.7, nil otherwise. */);
7457 #ifdef HAVE_NATIVE_FS
7458   ns_use_native_fullscreen = YES;
7459 #else
7460   ns_use_native_fullscreen = NO;
7461 #endif
7462   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7464   /* TODO: move to common code */
7465   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7466                doc: /* Which toolkit scroll bars Emacs uses, if any.
7467 A value of nil means Emacs doesn't use toolkit scroll bars.
7468 With the X Window system, the value is a symbol describing the
7469 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7470 With MS Windows or Nextstep, the value is t.  */);
7471   Vx_toolkit_scroll_bars = Qt;
7473   DEFVAR_BOOL ("x-use-underline-position-properties",
7474                x_use_underline_position_properties,
7475      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7476 A value of nil means ignore them.  If you encounter fonts with bogus
7477 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7478 to 4.1, set this to nil. */);
7479   x_use_underline_position_properties = 0;
7481   DEFVAR_BOOL ("x-underline-at-descent-line",
7482                x_underline_at_descent_line,
7483      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7484 A value of nil means to draw the underline according to the value of the
7485 variable `x-use-underline-position-properties', which is usually at the
7486 baseline level.  The default value is nil.  */);
7487   x_underline_at_descent_line = 0;
7489   /* Tell Emacs about this window system.  */
7490   Fprovide (Qns, Qnil);
7492   syms_of_nsfont ();
7493 #ifdef NS_IMPL_COCOA
7494 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7495   syms_of_macfont ();
7496 #endif
7497 #endif
7498