1 /* NeXT/Open/GNUstep / MacOSX communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2016 Free Software
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 (at
11 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. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
72 extern NSString *NSMenuDidBeginTrackingNotification;
75 /* ==========================================================================
77 NSTRACE, Trace support.
79 ========================================================================== */
83 /* The following use "volatile" since they can be accessed from
85 volatile int nstrace_num = 0;
86 volatile int nstrace_depth = 0;
88 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
89 NSTRACE_UNLESS to silence functions called.
91 TODO: This should really be a thread-local variable, to avoid that
92 a function with disabled trace thread silence trace output in
93 another. However, in practice this seldom is a problem. */
94 volatile int nstrace_enabled_global = 1;
96 /* Called when nstrace_enabled goes out of scope. */
97 void nstrace_leave(int * pointer_to_nstrace_enabled)
99 if (*pointer_to_nstrace_enabled)
106 /* Called when nstrace_saved_enabled_global goes out of scope. */
107 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
109 nstrace_enabled_global = *pointer_to_saved_enabled_global;
113 char const * nstrace_fullscreen_type_name (int fs_type)
117 case -1: return "-1";
118 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
119 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
120 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
121 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
122 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
123 default: return "FULLSCREEN_?????";
129 /* ==========================================================================
131 NSColor, EmacsColor category.
133 ========================================================================== */
134 @implementation NSColor (EmacsColor)
135 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
136 blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
140 if (ns_use_srgb_colorspace)
141 return [NSColor colorWithSRGBRed: red
147 return [NSColor colorWithCalibratedRed: red
153 - (NSColor *)colorUsingDefaultColorSpace
156 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
157 if (ns_use_srgb_colorspace)
158 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
161 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
166 /* ==========================================================================
170 ========================================================================== */
172 /* Convert a symbol indexed with an NSxxx value to a value as defined
173 in keyboard.c (lispy_function_key). I hope this is a correct way
174 of doing things... */
175 static unsigned convert_ns_to_X_keysym[] =
177 NSHomeFunctionKey, 0x50,
178 NSLeftArrowFunctionKey, 0x51,
179 NSUpArrowFunctionKey, 0x52,
180 NSRightArrowFunctionKey, 0x53,
181 NSDownArrowFunctionKey, 0x54,
182 NSPageUpFunctionKey, 0x55,
183 NSPageDownFunctionKey, 0x56,
184 NSEndFunctionKey, 0x57,
185 NSBeginFunctionKey, 0x58,
186 NSSelectFunctionKey, 0x60,
187 NSPrintFunctionKey, 0x61,
188 NSClearLineFunctionKey, 0x0B,
189 NSExecuteFunctionKey, 0x62,
190 NSInsertFunctionKey, 0x63,
191 NSUndoFunctionKey, 0x65,
192 NSRedoFunctionKey, 0x66,
193 NSMenuFunctionKey, 0x67,
194 NSFindFunctionKey, 0x68,
195 NSHelpFunctionKey, 0x6A,
196 NSBreakFunctionKey, 0x6B,
198 NSF1FunctionKey, 0xBE,
199 NSF2FunctionKey, 0xBF,
200 NSF3FunctionKey, 0xC0,
201 NSF4FunctionKey, 0xC1,
202 NSF5FunctionKey, 0xC2,
203 NSF6FunctionKey, 0xC3,
204 NSF7FunctionKey, 0xC4,
205 NSF8FunctionKey, 0xC5,
206 NSF9FunctionKey, 0xC6,
207 NSF10FunctionKey, 0xC7,
208 NSF11FunctionKey, 0xC8,
209 NSF12FunctionKey, 0xC9,
210 NSF13FunctionKey, 0xCA,
211 NSF14FunctionKey, 0xCB,
212 NSF15FunctionKey, 0xCC,
213 NSF16FunctionKey, 0xCD,
214 NSF17FunctionKey, 0xCE,
215 NSF18FunctionKey, 0xCF,
216 NSF19FunctionKey, 0xD0,
217 NSF20FunctionKey, 0xD1,
218 NSF21FunctionKey, 0xD2,
219 NSF22FunctionKey, 0xD3,
220 NSF23FunctionKey, 0xD4,
221 NSF24FunctionKey, 0xD5,
223 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
224 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
225 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
227 NSTabCharacter, 0x09,
228 0x19, 0x09, /* left tab->regular since pass shift */
229 NSCarriageReturnCharacter, 0x0D,
230 NSNewlineCharacter, 0x0D,
231 NSEnterCharacter, 0x8D,
233 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
234 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
235 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
236 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
237 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
238 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
239 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
240 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
241 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
242 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
243 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
244 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
245 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
246 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
247 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
248 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
250 0x1B, 0x1B /* escape */
253 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
254 the maximum font size to NOT antialias. On GNUstep there is currently
255 no way to control this behavior. */
256 float ns_antialias_threshold;
258 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
259 NSString *ns_app_name = @"Emacs"; /* default changed later */
261 /* Display variables */
262 struct ns_display_info *x_display_list; /* Chain of existing displays */
263 long context_menu_value = 0;
266 static struct frame *ns_updating_frame;
267 static NSView *focus_view = NULL;
268 static int ns_window_num = 0;
269 #ifdef NS_IMPL_GNUSTEP
270 static NSRect uRect; // TODO: This is dead, remove it?
272 static BOOL gsaved = NO;
273 static BOOL ns_fake_keydown = NO;
275 static BOOL ns_menu_bar_is_hidden = NO;
277 /*static int debug_lock = 0; */
280 static BOOL send_appdefined = YES;
281 #define NO_APPDEFINED_DATA (-8)
282 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
283 static NSTimer *timed_entry = 0;
284 static NSTimer *scroll_repeat_entry = nil;
285 static fd_set select_readfds, select_writefds;
286 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
287 static int select_nfds = 0, select_valid = 0;
288 static struct timespec select_timeout = { 0, 0 };
289 static int selfds[2] = { -1, -1 };
290 static pthread_mutex_t select_mutex;
291 static int apploopnr = 0;
292 static NSAutoreleasePool *outerpool;
293 static struct input_event *emacs_event = NULL;
294 static struct input_event *q_event_ptr = NULL;
295 static int n_emacs_events_pending = 0;
296 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
297 *ns_pending_service_args;
298 static BOOL ns_do_open_file = NO;
299 static BOOL ns_last_use_native_fullscreen;
301 /* Non-zero means that a HELP_EVENT has been generated since Emacs
304 static BOOL any_help_event_p = NO;
307 struct input_event *q;
313 static NSString *represented_filename = nil;
314 static struct frame *represented_frame = 0;
318 * State for pending menu activation:
319 * MENU_NONE Normal state
320 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
321 * run lisp to update the menu.
322 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
326 #define MENU_PENDING 1
327 #define MENU_OPENING 2
328 static int menu_will_open_state = MENU_NONE;
330 /* Saved position for menu click. */
331 static CGPoint menu_mouse_point;
334 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
335 #define NS_FUNCTION_KEY_MASK 0x800000
336 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
337 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
338 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
339 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
340 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
341 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
342 #define EV_MODIFIERS2(flags) \
343 (((flags & NSHelpKeyMask) ? \
344 hyper_modifier : 0) \
345 | (!EQ (ns_right_alternate_modifier, Qleft) && \
346 ((flags & NSRightAlternateKeyMask) \
347 == NSRightAlternateKeyMask) ? \
348 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
349 | ((flags & NSAlternateKeyMask) ? \
350 parse_solitary_modifier (ns_alternate_modifier) : 0) \
351 | ((flags & NSShiftKeyMask) ? \
352 shift_modifier : 0) \
353 | (!EQ (ns_right_control_modifier, Qleft) && \
354 ((flags & NSRightControlKeyMask) \
355 == NSRightControlKeyMask) ? \
356 parse_solitary_modifier (ns_right_control_modifier) : 0) \
357 | ((flags & NSControlKeyMask) ? \
358 parse_solitary_modifier (ns_control_modifier) : 0) \
359 | ((flags & NS_FUNCTION_KEY_MASK) ? \
360 parse_solitary_modifier (ns_function_modifier) : 0) \
361 | (!EQ (ns_right_command_modifier, Qleft) && \
362 ((flags & NSRightCommandKeyMask) \
363 == NSRightCommandKeyMask) ? \
364 parse_solitary_modifier (ns_right_command_modifier) : 0) \
365 | ((flags & NSCommandKeyMask) ? \
366 parse_solitary_modifier (ns_command_modifier):0))
367 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
369 #define EV_UDMODIFIERS(e) \
370 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
371 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
372 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
373 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
374 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
375 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
376 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
377 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
378 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
380 #define EV_BUTTON(e) \
381 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
382 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
383 [e buttonNumber] - 1)
385 /* Convert the time field to a timestamp in milliseconds. */
386 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
388 /* This is a piece of code which is common to all the event handling
389 methods. Maybe it should even be a function. */
390 #define EV_TRAILER(e) \
392 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
396 #define EV_TRAILER2(e) \
398 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
401 Lisp_Object tem = Vinhibit_quit; \
402 Vinhibit_quit = Qt; \
403 n_emacs_events_pending++; \
404 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
405 Vinhibit_quit = tem; \
408 hold_event (emacs_event); \
409 EVENT_INIT (*emacs_event); \
410 ns_send_appdefined (-1); \
413 /* TODO: get rid of need for these forward declarations */
414 static void ns_condemn_scroll_bars (struct frame *f);
415 static void ns_judge_scroll_bars (struct frame *f);
416 void x_set_frame_alpha (struct frame *f);
419 /* ==========================================================================
423 ========================================================================== */
426 ns_set_represented_filename (NSString* fstr, struct frame *f)
428 represented_filename = [fstr retain];
429 represented_frame = f;
433 ns_init_events (struct input_event* ev)
446 hold_event (struct input_event *event)
448 if (hold_event_q.nr == hold_event_q.cap)
450 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
451 else hold_event_q.cap *= 2;
453 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
456 hold_event_q.q[hold_event_q.nr++] = *event;
457 /* Make sure ns_read_socket is called, i.e. we have input. */
459 send_appdefined = YES;
463 append2 (Lisp_Object list, Lisp_Object item)
464 /* --------------------------------------------------------------------------
465 Utility to append to a list
466 -------------------------------------------------------------------------- */
468 return CALLN (Fnconc, list, list1 (item));
473 ns_etc_directory (void)
474 /* If running as a self-contained app bundle, return as a string the
475 filename of the etc directory, if present; else nil. */
477 NSBundle *bundle = [NSBundle mainBundle];
478 NSString *resourceDir = [bundle resourcePath];
479 NSString *resourcePath;
480 NSFileManager *fileManager = [NSFileManager defaultManager];
483 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
484 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
486 if (isDir) return [resourcePath UTF8String];
494 /* If running as a self-contained app bundle, return as a path string
495 the filenames of the libexec and bin directories, ie libexec:bin.
496 Otherwise, return nil.
497 Normally, Emacs does not add its own bin/ directory to the PATH.
498 However, a self-contained NS build has a different layout, with
499 bin/ and libexec/ subdirectories in the directory that contains
501 We put libexec first, because init_callproc_1 uses the first
502 element to initialize exec-directory. An alternative would be
503 for init_callproc to check for invocation-directory/libexec.
506 NSBundle *bundle = [NSBundle mainBundle];
507 NSString *resourceDir = [bundle resourcePath];
508 NSString *binDir = [bundle bundlePath];
509 NSString *resourcePath, *resourcePaths;
511 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
512 NSFileManager *fileManager = [NSFileManager defaultManager];
514 NSEnumerator *pathEnum;
517 range = [resourceDir rangeOfString: @"Contents"];
518 if (range.location != NSNotFound)
520 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
522 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
526 paths = [binDir stringsByAppendingPaths:
527 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
528 pathEnum = [paths objectEnumerator];
531 while ((resourcePath = [pathEnum nextObject]))
533 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
536 if ([resourcePaths length] > 0)
538 = [resourcePaths stringByAppendingString: pathSeparator];
540 = [resourcePaths stringByAppendingString: resourcePath];
543 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
551 /* If running as a self-contained app bundle, return as a path string
552 the filenames of the site-lisp and lisp directories.
553 Ie, site-lisp:lisp. Otherwise, return nil. */
555 NSBundle *bundle = [NSBundle mainBundle];
556 NSString *resourceDir = [bundle resourcePath];
557 NSString *resourcePath, *resourcePaths;
558 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
559 NSFileManager *fileManager = [NSFileManager defaultManager];
561 NSArray *paths = [resourceDir stringsByAppendingPaths:
562 [NSArray arrayWithObjects:
563 @"site-lisp", @"lisp", nil]];
564 NSEnumerator *pathEnum = [paths objectEnumerator];
567 /* Hack to skip site-lisp. */
568 if (no_site_lisp) resourcePath = [pathEnum nextObject];
570 while ((resourcePath = [pathEnum nextObject]))
572 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
575 if ([resourcePaths length] > 0)
577 = [resourcePaths stringByAppendingString: pathSeparator];
579 = [resourcePaths stringByAppendingString: resourcePath];
582 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
589 ns_init_locale (void)
590 /* OS X doesn't set any environment variables for the locale when run
591 from the GUI. Get the locale from the OS and set LANG. */
593 NSLocale *locale = [NSLocale currentLocale];
595 NSTRACE ("ns_init_locale");
599 /* It seems OS X should probably use UTF-8 everywhere.
600 'localeIdentifier' does not specify the encoding, and I can't
601 find any way to get the OS to tell us which encoding to use,
602 so hard-code '.UTF-8'. */
603 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
604 [locale localeIdentifier]];
606 /* Set LANG to locale, but not if LANG is already set. */
607 setenv("LANG", [localeID UTF8String], 0);
609 @catch (NSException *e)
611 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
617 ns_release_object (void *obj)
618 /* --------------------------------------------------------------------------
619 Release an object (callable from C)
620 -------------------------------------------------------------------------- */
627 ns_retain_object (void *obj)
628 /* --------------------------------------------------------------------------
629 Retain an object (callable from C)
630 -------------------------------------------------------------------------- */
637 ns_alloc_autorelease_pool (void)
638 /* --------------------------------------------------------------------------
639 Allocate a pool for temporary objects (callable from C)
640 -------------------------------------------------------------------------- */
642 return [[NSAutoreleasePool alloc] init];
647 ns_release_autorelease_pool (void *pool)
648 /* --------------------------------------------------------------------------
649 Free a pool and temporary objects it refers to (callable from C)
650 -------------------------------------------------------------------------- */
652 ns_release_object (pool);
657 ns_menu_bar_should_be_hidden (void)
658 /* True, if the menu bar should be hidden. */
660 return !NILP (ns_auto_hide_menu_bar)
661 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
674 static struct EmacsMargins
675 ns_screen_margins (NSScreen *screen)
676 /* The parts of SCREEN used by the operating system. */
678 NSTRACE ("ns_screen_margins");
680 struct EmacsMargins margins;
682 NSRect screenFrame = [screen frame];
683 NSRect screenVisibleFrame = [screen visibleFrame];
685 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
686 menu bar, check this explicitly. */
687 if (ns_menu_bar_should_be_hidden())
693 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
694 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
695 + screenVisibleFrame.size.height);
697 margins.top = frameTop - visibleFrameTop;
701 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
702 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
703 + screenVisibleFrame.size.width);
704 margins.right = frameRight - visibleFrameRight;
707 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
708 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
710 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
720 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
721 assumed to contain a hidden dock. OS X currently use 4 pixels for
722 this, however, to be future compatible, a larger value is used. */
723 #define DOCK_IGNORE_LIMIT 6
725 static struct EmacsMargins
726 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
727 /* The parts of SCREEN used by the operating system, excluding the parts
728 reserved for an hidden dock. */
730 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
732 struct EmacsMargins margins = ns_screen_margins(screen);
734 /* OS X (currently) reserved 4 pixels along the edge where a hidden
735 dock is located. Unfortunately, it's not possible to find the
736 location and information about if the dock is hidden. Instead,
737 it is assumed that if the margin of an edge is less than
738 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
739 if (margins.left <= DOCK_IGNORE_LIMIT)
743 if (margins.right <= DOCK_IGNORE_LIMIT)
747 if (margins.top <= DOCK_IGNORE_LIMIT)
751 /* Note: This doesn't occur in current versions of OS X, but
752 included for completeness and future compatibility. */
753 if (margins.bottom <= DOCK_IGNORE_LIMIT)
758 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
769 ns_menu_bar_height (NSScreen *screen)
770 /* The height of the menu bar, if visible.
772 Note: Don't use this when fullscreen is enabled -- the screen
773 sometimes includes, sometimes excludes the menu bar area. */
775 struct EmacsMargins margins = ns_screen_margins(screen);
777 CGFloat res = margins.top;
779 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
785 /* ==========================================================================
787 Focus (clipping) and screen update
789 ========================================================================== */
792 // Window constraining
793 // -------------------
795 // To ensure that the windows are not placed under the menu bar, they
796 // are typically moved by the call-back constrainFrameRect. However,
797 // by overriding it, it's possible to inhibit this, leaving the window
798 // in it's original position.
800 // It's possible to hide the menu bar. However, technically, it's only
801 // possible to hide it when the application is active. To ensure that
802 // this work properly, the menu bar and window constraining are
803 // deferred until the application becomes active.
805 // Even though it's not possible to manually move a window above the
806 // top of the screen, it is allowed if it's done programmatically,
807 // when the menu is hidden. This allows the editable area to cover the
808 // full screen height.
813 // Use the following extra files:
816 // ;; Hide menu and place frame slightly above the top of the screen.
817 // (setq ns-auto-hide-menu-bar t)
818 // (set-frame-position (selected-frame) 0 -20)
822 // emacs -Q -l init.el
824 // Result: No menu bar, and the title bar should be above the screen.
830 // Result: Menu bar visible, frame placed immediately below the menu.
833 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
835 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
836 NSTRACE_ARG_RECT (frameRect));
838 // --------------------
839 // Collect information about the screen the frame is covering.
842 NSArray *screens = [NSScreen screens];
843 NSUInteger nr_screens = [screens count];
847 // The height of the menu bar, if present in any screen the frame is
849 int menu_bar_height = 0;
851 // A rectangle covering all the screen the frame is displayed in.
852 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
853 for (i = 0; i < nr_screens; ++i )
855 NSScreen *s = [screens objectAtIndex: i];
856 NSRect scrRect = [s frame];
858 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
859 i, NSTRACE_ARG_RECT (scrRect));
861 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
863 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
867 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
868 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
873 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
875 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
877 if (multiscreenRect.size.width == 0
878 || multiscreenRect.size.height == 0)
880 // Failed to find any monitor, give up.
881 NSTRACE_MSG ("multiscreenRect empty");
882 NSTRACE_RETURN_RECT (frameRect);
887 // --------------------
888 // Find a suitable placement.
891 if (ns_menu_bar_should_be_hidden())
893 // When the menu bar is hidden, the user may place part of the
894 // frame above the top of the screen, for example to hide the
897 // Hence, keep the original position.
901 // Ensure that the frame is below the menu bar, or below the top
904 // This assume that the menu bar is placed at the top in the
905 // rectangle that covers the monitors. (It doesn't have to be,
906 // but if it's not it's hard to do anything useful.)
907 CGFloat topOfWorkArea = (multiscreenRect.origin.y
908 + multiscreenRect.size.height
911 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
912 if (topOfFrame > topOfWorkArea)
914 frameRect.origin.y -= topOfFrame - topOfWorkArea;
915 NSTRACE_RECT ("After placement adjust", frameRect);
919 // Include the following section to restrict frame to the screens.
920 // (If so, update it to allow the frame to stretch down below the
923 // --------------------
924 // Ensure frame doesn't stretch below the screens.
927 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
931 frameRect.origin.y = multiscreenRect.origin.y;
932 frameRect.size.height -= diff;
936 NSTRACE_RETURN_RECT (frameRect);
942 ns_constrain_all_frames (void)
943 /* --------------------------------------------------------------------------
944 Ensure that the menu bar doesn't cover any frames.
945 -------------------------------------------------------------------------- */
947 Lisp_Object tail, frame;
949 NSTRACE ("ns_constrain_all_frames");
953 FOR_EACH_FRAME (tail, frame)
955 struct frame *f = XFRAME (frame);
958 EmacsView *view = FRAME_NS_VIEW (f);
960 if (![view isFullscreen])
963 setFrame:constrain_frame_rect([[view window] frame], false)
974 ns_update_auto_hide_menu_bar (void)
975 /* --------------------------------------------------------------------------
976 Show or hide the menu bar, based on user setting.
977 -------------------------------------------------------------------------- */
980 NSTRACE ("ns_update_auto_hide_menu_bar");
984 if (NSApp != nil && [NSApp isActive])
986 // Note, "setPresentationOptions" triggers an error unless the
987 // application is active.
988 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
990 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
992 NSApplicationPresentationOptions options
993 = NSApplicationPresentationDefault;
995 if (menu_bar_should_be_hidden)
996 options |= NSApplicationPresentationAutoHideMenuBar
997 | NSApplicationPresentationAutoHideDock;
999 [NSApp setPresentationOptions: options];
1001 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1003 if (!ns_menu_bar_is_hidden)
1005 ns_constrain_all_frames ();
1016 ns_update_begin (struct frame *f)
1017 /* --------------------------------------------------------------------------
1018 Prepare for a grouped sequence of drawing calls
1019 external (RIF) call; whole frame, called before update_window_begin
1020 -------------------------------------------------------------------------- */
1022 EmacsView *view = FRAME_NS_VIEW (f);
1023 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1025 ns_update_auto_hide_menu_bar ();
1027 #ifdef NS_IMPL_COCOA
1028 if ([view isFullscreen] && [view fsIsNative])
1030 // Fix reappearing tool bar in fullscreen for OSX 10.7
1031 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1032 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1033 if (! tbar_visible != ! [toolbar isVisible])
1034 [toolbar setVisible: tbar_visible];
1038 ns_updating_frame = f;
1041 /* drawRect may have been called for say the minibuffer, and then clip path
1042 is for the minibuffer. But the display engine may draw more because
1043 we have set the frame as garbaged. So reset clip path to the whole
1045 #ifdef NS_IMPL_COCOA
1048 NSRect r = [view frame];
1049 NSRect cr = [[view window] frame];
1050 /* If a large frame size is set, r may be larger than the window frame
1051 before constrained. In that case don't change the clip path, as we
1052 will clear in to the tool bar and title bar. */
1054 + FRAME_NS_TITLEBAR_HEIGHT (f)
1055 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1057 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1064 #ifdef NS_IMPL_GNUSTEP
1065 uRect = NSMakeRect (0, 0, 0, 0);
1071 ns_update_window_begin (struct window *w)
1072 /* --------------------------------------------------------------------------
1073 Prepare for a grouped sequence of drawing calls
1074 external (RIF) call; for one window, called after update_begin
1075 -------------------------------------------------------------------------- */
1077 struct frame *f = XFRAME (WINDOW_FRAME (w));
1078 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1080 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1081 w->output_cursor = w->cursor;
1085 if (f == hlinfo->mouse_face_mouse_frame)
1087 /* Don't do highlighting for mouse motion during the update. */
1088 hlinfo->mouse_face_defer = 1;
1090 /* If the frame needs to be redrawn,
1091 simply forget about any prior mouse highlighting. */
1092 if (FRAME_GARBAGED_P (f))
1093 hlinfo->mouse_face_window = Qnil;
1095 /* (further code for mouse faces ifdef'd out in other terms elided) */
1103 ns_update_window_end (struct window *w, bool cursor_on_p,
1104 bool mouse_face_overwritten_p)
1105 /* --------------------------------------------------------------------------
1106 Finished a grouped sequence of drawing calls
1107 external (RIF) call; for one window called before update_end
1108 -------------------------------------------------------------------------- */
1110 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1112 /* note: this fn is nearly identical in all terms */
1113 if (!w->pseudo_window_p)
1118 display_and_set_cursor (w, 1,
1119 w->output_cursor.hpos, w->output_cursor.vpos,
1120 w->output_cursor.x, w->output_cursor.y);
1122 if (draw_window_fringes (w, 1))
1124 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1125 x_draw_right_divider (w);
1127 x_draw_vertical_border (w);
1133 /* If a row with mouse-face was overwritten, arrange for
1134 frame_up_to_date to redisplay the mouse highlight. */
1135 if (mouse_face_overwritten_p)
1136 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1141 ns_update_end (struct frame *f)
1142 /* --------------------------------------------------------------------------
1143 Finished a grouped sequence of drawing calls
1144 external (RIF) call; for whole frame, called after update_window_end
1145 -------------------------------------------------------------------------- */
1147 EmacsView *view = FRAME_NS_VIEW (f);
1149 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1151 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1152 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1157 [[view window] flushWindow];
1160 ns_updating_frame = NULL;
1164 ns_focus (struct frame *f, NSRect *r, int n)
1165 /* --------------------------------------------------------------------------
1166 Internal: Focus on given frame. During small local updates this is used to
1167 draw, however during large updates, ns_update_begin and ns_update_end are
1168 called to wrap the whole thing, in which case these calls are stubbed out.
1169 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1170 the back end won't do this automatically, and will just end up flushing
1172 -------------------------------------------------------------------------- */
1174 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1177 NSTRACE_RECT ("r", *r);
1180 if (f != ns_updating_frame)
1182 NSView *view = FRAME_NS_VIEW (f);
1183 if (view != focus_view)
1185 if (focus_view != NULL)
1187 [focus_view unlockFocus];
1188 [[focus_view window] flushWindow];
1195 /*if (view) debug_lock++; */
1202 [[NSGraphicsContext currentContext] saveGraphicsState];
1204 NSRectClipList (r, 2);
1213 ns_unfocus (struct frame *f)
1214 /* --------------------------------------------------------------------------
1215 Internal: Remove focus on given frame
1216 -------------------------------------------------------------------------- */
1218 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1222 [[NSGraphicsContext currentContext] restoreGraphicsState];
1226 if (f != ns_updating_frame)
1228 if (focus_view != NULL)
1230 [focus_view unlockFocus];
1231 [[focus_view window] flushWindow];
1240 ns_clip_to_row (struct window *w, struct glyph_row *row,
1241 enum glyph_row_area area, BOOL gc)
1242 /* --------------------------------------------------------------------------
1243 Internal (but parallels other terms): Focus drawing on given row
1244 -------------------------------------------------------------------------- */
1246 struct frame *f = XFRAME (WINDOW_FRAME (w));
1248 int window_x, window_y, window_width;
1250 window_box (w, area, &window_x, &window_y, &window_width, 0);
1252 clip_rect.origin.x = window_x;
1253 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1254 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1255 clip_rect.size.width = window_width;
1256 clip_rect.size.height = row->visible_height;
1258 ns_focus (f, &clip_rect, 1);
1262 /* ==========================================================================
1264 Visible bell and beep.
1266 ========================================================================== */
1269 // This bell implementation shows the visual bell image asynchronously
1270 // from the rest of Emacs. This is done by adding a NSView to the
1271 // superview of the Emacs window and removing it using a timer.
1273 // Unfortunately, some Emacs operations, like scrolling, is done using
1274 // low-level primitives that copy the content of the window, including
1275 // the bell image. To some extent, this is handled by removing the
1276 // image prior to scrolling and marking that the window is in need for
1279 // To test this code, make sure that there is no artifacts of the bell
1280 // image in the following situations. Use a non-empty buffer (like the
1281 // tutorial) to ensure that a scroll is performed:
1283 // * Single-window: C-g C-v
1285 // * Side-by-windows: C-x 3 C-g C-v
1287 // * Windows above each other: C-x 2 C-g C-v
1289 @interface EmacsBell : NSImageView
1291 // Number of currently active bell:s.
1292 unsigned int nestCount;
1296 - (void)show:(NSView *)view;
1301 @implementation EmacsBell
1305 NSTRACE ("[EmacsBell init]");
1306 if ((self = [super init]))
1310 #ifdef NS_IMPL_GNUSTEP
1311 // GNUstep doesn't provide named images. This was reported in
1312 // 2011, see https://savannah.gnu.org/bugs/?33396
1314 // As a drop in replacement, a semitransparent gray square is used.
1315 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1316 [self.image lockFocus];
1317 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1318 NSRectFill(NSMakeRect(0, 0, 32, 32));
1319 [self.image unlockFocus];
1321 self.image = [NSImage imageNamed:NSImageNameCaution];
1322 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1323 self.image.size.height * 5)];
1329 - (void)show:(NSView *)view
1331 NSTRACE ("[EmacsBell show:]");
1332 NSTRACE_MSG ("nestCount: %u", nestCount);
1334 // Show the image, unless it's already shown.
1337 NSRect rect = [view bounds];
1339 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1340 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1342 [self setFrameOrigin:pos];
1343 [self setFrameSize:self.image.size];
1347 [[[view window] contentView] addSubview:self
1348 positioned:NSWindowAbove
1354 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1360 // Note: Trace output from this method isn't shown, reason unknown.
1361 // NSTRACE ("[EmacsBell hide]");
1366 // Remove the image once the last bell became inactive.
1376 NSTRACE ("[EmacsBell remove]");
1379 NSTRACE_MSG ("removeFromSuperview");
1380 [self removeFromSuperview];
1381 mView.needsDisplay = YES;
1389 static EmacsBell * bell_view = nil;
1392 ns_ring_bell (struct frame *f)
1393 /* --------------------------------------------------------------------------
1395 -------------------------------------------------------------------------- */
1397 NSTRACE ("ns_ring_bell");
1400 struct frame *frame = SELECTED_FRAME ();
1403 if (bell_view == nil)
1405 bell_view = [[EmacsBell alloc] init];
1411 view = FRAME_NS_VIEW (frame);
1414 [bell_view show:view];
1426 static void hide_bell ()
1427 /* --------------------------------------------------------------------------
1428 Ensure the bell is hidden.
1429 -------------------------------------------------------------------------- */
1431 NSTRACE ("hide_bell");
1433 if (bell_view != nil)
1440 /* ==========================================================================
1442 Frame / window manager related functions
1444 ========================================================================== */
1448 ns_raise_frame (struct frame *f)
1449 /* --------------------------------------------------------------------------
1450 Bring window to foreground and make it active
1451 -------------------------------------------------------------------------- */
1455 check_window_system (f);
1456 view = FRAME_NS_VIEW (f);
1458 if (FRAME_VISIBLE_P (f))
1459 [[view window] makeKeyAndOrderFront: NSApp];
1465 ns_lower_frame (struct frame *f)
1466 /* --------------------------------------------------------------------------
1468 -------------------------------------------------------------------------- */
1472 check_window_system (f);
1473 view = FRAME_NS_VIEW (f);
1475 [[view window] orderBack: NSApp];
1481 ns_frame_raise_lower (struct frame *f, bool raise)
1482 /* --------------------------------------------------------------------------
1484 -------------------------------------------------------------------------- */
1486 NSTRACE ("ns_frame_raise_lower");
1496 ns_frame_rehighlight (struct frame *frame)
1497 /* --------------------------------------------------------------------------
1498 External (hook): called on things like window switching within frame
1499 -------------------------------------------------------------------------- */
1501 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1502 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1504 NSTRACE ("ns_frame_rehighlight");
1505 if (dpyinfo->x_focus_frame)
1507 dpyinfo->x_highlight_frame
1508 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1509 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1510 : dpyinfo->x_focus_frame);
1511 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1513 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1514 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1518 dpyinfo->x_highlight_frame = 0;
1520 if (dpyinfo->x_highlight_frame &&
1521 dpyinfo->x_highlight_frame != old_highlight)
1525 x_update_cursor (old_highlight, 1);
1526 x_set_frame_alpha (old_highlight);
1528 if (dpyinfo->x_highlight_frame)
1530 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1531 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1538 x_make_frame_visible (struct frame *f)
1539 /* --------------------------------------------------------------------------
1540 External: Show the window (X11 semantics)
1541 -------------------------------------------------------------------------- */
1543 NSTRACE ("x_make_frame_visible");
1544 /* XXX: at some points in past this was not needed, as the only place that
1545 called this (frame.c:Fraise_frame ()) also called raise_lower;
1546 if this ends up the case again, comment this out again. */
1547 if (!FRAME_VISIBLE_P (f))
1549 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1551 SET_FRAME_VISIBLE (f, 1);
1554 /* Making a new frame from a fullscreen frame will make the new frame
1555 fullscreen also. So skip handleFS as this will print an error. */
1556 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1557 && [view isFullscreen])
1560 if (f->want_fullscreen != FULLSCREEN_NONE)
1571 x_make_frame_invisible (struct frame *f)
1572 /* --------------------------------------------------------------------------
1573 External: Hide the window (X11 semantics)
1574 -------------------------------------------------------------------------- */
1577 NSTRACE ("x_make_frame_invisible");
1578 check_window_system (f);
1579 view = FRAME_NS_VIEW (f);
1580 [[view window] orderOut: NSApp];
1581 SET_FRAME_VISIBLE (f, 0);
1582 SET_FRAME_ICONIFIED (f, 0);
1587 x_iconify_frame (struct frame *f)
1588 /* --------------------------------------------------------------------------
1589 External: Iconify window
1590 -------------------------------------------------------------------------- */
1593 struct ns_display_info *dpyinfo;
1595 NSTRACE ("x_iconify_frame");
1596 check_window_system (f);
1597 view = FRAME_NS_VIEW (f);
1598 dpyinfo = FRAME_DISPLAY_INFO (f);
1600 if (dpyinfo->x_highlight_frame == f)
1601 dpyinfo->x_highlight_frame = 0;
1603 if ([[view window] windowNumber] <= 0)
1605 /* the window is still deferred. Make it very small, bring it
1606 on screen and order it out. */
1607 NSRect s = { { 100, 100}, {0, 0} };
1609 t = [[view window] frame];
1610 [[view window] setFrame: s display: NO];
1611 [[view window] orderBack: NSApp];
1612 [[view window] orderOut: NSApp];
1613 [[view window] setFrame: t display: NO];
1615 [[view window] miniaturize: NSApp];
1618 /* Free X resources of frame F. */
1621 x_free_frame_resources (struct frame *f)
1624 struct ns_display_info *dpyinfo;
1625 Mouse_HLInfo *hlinfo;
1627 NSTRACE ("x_free_frame_resources");
1628 check_window_system (f);
1629 view = FRAME_NS_VIEW (f);
1630 dpyinfo = FRAME_DISPLAY_INFO (f);
1631 hlinfo = MOUSE_HL_INFO (f);
1633 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1637 free_frame_menubar (f);
1638 free_frame_faces (f);
1640 if (f == dpyinfo->x_focus_frame)
1641 dpyinfo->x_focus_frame = 0;
1642 if (f == dpyinfo->x_highlight_frame)
1643 dpyinfo->x_highlight_frame = 0;
1644 if (f == hlinfo->mouse_face_mouse_frame)
1645 reset_mouse_highlight (hlinfo);
1647 if (f->output_data.ns->miniimage != nil)
1648 [f->output_data.ns->miniimage release];
1650 [[view window] close];
1653 xfree (f->output_data.ns);
1659 x_destroy_window (struct frame *f)
1660 /* --------------------------------------------------------------------------
1661 External: Delete the window
1662 -------------------------------------------------------------------------- */
1664 NSTRACE ("x_destroy_window");
1665 check_window_system (f);
1666 x_free_frame_resources (f);
1672 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1673 /* --------------------------------------------------------------------------
1674 External: Position the window
1675 -------------------------------------------------------------------------- */
1677 NSView *view = FRAME_NS_VIEW (f);
1678 NSArray *screens = [NSScreen screens];
1679 NSScreen *fscreen = [screens objectAtIndex: 0];
1680 NSScreen *screen = [[view window] screen];
1682 NSTRACE ("x_set_offset");
1689 if (view != nil && screen && fscreen)
1691 f->left_pos = f->size_hint_flags & XNegative
1692 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1694 /* We use visibleFrame here to take menu bar into account.
1695 Ideally we should also adjust left/top with visibleFrame.origin. */
1697 f->top_pos = f->size_hint_flags & YNegative
1698 ? ([screen visibleFrame].size.height + f->top_pos
1699 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1700 - FRAME_TOOLBAR_HEIGHT (f))
1702 #ifdef NS_IMPL_GNUSTEP
1703 if (f->left_pos < 100)
1704 f->left_pos = 100; /* don't overlap menu */
1706 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1708 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1709 SCREENMAXBOUND ([fscreen frame].size.height
1711 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1712 [[view window] setFrameTopLeftPoint: pt];
1713 f->size_hint_flags &= ~(XNegative|YNegative);
1721 x_set_window_size (struct frame *f,
1722 bool change_gravity,
1726 /* --------------------------------------------------------------------------
1727 Adjust window pixel size based on given character grid size
1728 Impl is a bit more complex than other terms, need to do some
1730 -------------------------------------------------------------------------- */
1732 EmacsView *view = FRAME_NS_VIEW (f);
1733 NSWindow *window = [view window];
1734 NSRect wr = [window frame];
1735 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1736 int pixelwidth, pixelheight;
1737 int orig_height = wr.size.height;
1739 NSTRACE ("x_set_window_size");
1744 NSTRACE_RECT ("current", wr);
1745 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1746 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1752 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1753 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1757 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1758 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1761 /* If we have a toolbar, take its height into account. */
1762 if (tb && ! [view isFullscreen])
1764 /* NOTE: previously this would generate wrong result if toolbar not
1765 yet displayed and fixing toolbar_height=32 helped, but
1766 now (200903) seems no longer needed */
1767 FRAME_TOOLBAR_HEIGHT (f) =
1768 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1769 - FRAME_NS_TITLEBAR_HEIGHT (f);
1771 /* Only breaks things here, removed by martin 2015-09-30. */
1772 #ifdef NS_IMPL_GNUSTEP
1773 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1778 FRAME_TOOLBAR_HEIGHT (f) = 0;
1780 wr.size.width = pixelwidth + f->border_width;
1781 wr.size.height = pixelheight;
1782 if (! [view isFullscreen])
1783 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1784 + FRAME_TOOLBAR_HEIGHT (f);
1786 /* Do not try to constrain to this screen. We may have multiple
1787 screens, and want Emacs to span those. Constraining to screen
1788 prevents that, and that is not nice to the user. */
1789 if (f->output_data.ns->zooming)
1790 f->output_data.ns->zooming = 0;
1792 wr.origin.y += orig_height - wr.size.height;
1794 frame_size_history_add
1795 (f, Qx_set_window_size_1, width, height,
1796 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1797 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1798 make_number (f->border_width),
1799 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1800 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1802 [window setFrame: wr display: YES];
1804 /* This is a trick to compensate for Emacs' managing the scrollbar area
1805 as a fixed number of standard character columns. Instead of leaving
1806 blank space for the extra, we chopped it off above. Now for
1807 left-hand scrollbars, we shift all rendering to the left by the
1808 difference between the real width and Emacs' imagined one. For
1809 right-hand bars, don't worry about it since the extra is never used.
1810 (Obviously doesn't work for vertically split windows tho..) */
1812 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1813 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1814 - NS_SCROLL_BAR_WIDTH (f), 0)
1815 : NSMakePoint (0, 0);
1817 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1818 [view setBoundsOrigin: origin];
1821 [view updateFrameSize: NO];
1827 ns_fullscreen_hook (struct frame *f)
1829 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1831 NSTRACE ("ns_fullscreen_hook");
1833 if (!FRAME_VISIBLE_P (f))
1836 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1838 /* Old style fs don't initiate correctly if created from
1839 init/default-frame alist, so use a timer (not nice...).
1841 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1842 selector: @selector (handleFS)
1843 userInfo: nil repeats: NO];
1852 /* ==========================================================================
1856 ========================================================================== */
1860 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1862 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1863 if (idx < 1 || idx >= color_table->avail)
1865 return color_table->colors[idx];
1870 ns_index_color (NSColor *color, struct frame *f)
1872 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1876 if (!color_table->colors)
1878 color_table->size = NS_COLOR_CAPACITY;
1879 color_table->avail = 1; /* skip idx=0 as marker */
1880 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1881 color_table->colors[0] = nil;
1882 color_table->empty_indices = [[NSMutableSet alloc] init];
1885 /* Do we already have this color? */
1886 for (i = 1; i < color_table->avail; i++)
1887 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1890 if ([color_table->empty_indices count] > 0)
1892 NSNumber *index = [color_table->empty_indices anyObject];
1893 [color_table->empty_indices removeObject: index];
1894 idx = [index unsignedLongValue];
1898 if (color_table->avail == color_table->size)
1899 color_table->colors =
1900 xpalloc (color_table->colors, &color_table->size, 1,
1901 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1902 idx = color_table->avail++;
1905 color_table->colors[idx] = color;
1907 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1913 ns_free_indexed_color (unsigned long idx, struct frame *f)
1915 struct ns_color_table *color_table;
1922 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1924 if (idx <= 0 || idx >= color_table->size) {
1925 message1 ("ns_free_indexed_color: Color index out of range.\n");
1929 index = [NSNumber numberWithUnsignedInt: idx];
1930 if ([color_table->empty_indices containsObject: index]) {
1931 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1935 color = color_table->colors[idx];
1937 color_table->colors[idx] = nil;
1938 [color_table->empty_indices addObject: index];
1939 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1944 ns_get_color (const char *name, NSColor **col)
1945 /* --------------------------------------------------------------------------
1947 -------------------------------------------------------------------------- */
1948 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1949 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1950 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1953 static char hex[20];
1955 float r = -1.0, g, b;
1956 NSString *nsname = [NSString stringWithUTF8String: name];
1958 NSTRACE ("ns_get_color(%s, **)", name);
1962 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1964 #ifdef NS_IMPL_COCOA
1965 NSString *defname = [[NSUserDefaults standardUserDefaults]
1966 stringForKey: @"AppleHighlightColor"];
1971 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1973 *col = [new colorUsingDefaultColorSpace];
1978 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1980 name = [nsname UTF8String];
1982 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1984 /* NOTE: OSX applications normally don't set foreground selection, but
1985 text may be unreadable if we don't.
1987 if ((new = [NSColor selectedTextColor]) != nil)
1989 *col = [new colorUsingDefaultColorSpace];
1994 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1995 name = [nsname UTF8String];
1998 /* First, check for some sort of numeric specification. */
2001 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2003 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2004 [scanner scanFloat: &r];
2005 [scanner scanFloat: &g];
2006 [scanner scanFloat: &b];
2008 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2009 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2010 else if (name[0] == '#') /* An old X11 format; convert to newer */
2012 int len = (strlen(name) - 1);
2013 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2015 scaling = strlen(name+start) / 3;
2016 for (i = 0; i < 3; i++)
2017 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2018 name + start + i * scaling);
2019 hex[3 * (scaling + 1) - 1] = '\0';
2025 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2026 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2036 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2041 /* Otherwise, color is expected to be from a list */
2043 NSEnumerator *lenum, *cenum;
2047 #ifdef NS_IMPL_GNUSTEP
2048 /* XXX: who is wrong, the requestor or the implementation? */
2049 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2051 nsname = @"highlightColor";
2054 lenum = [[NSColorList availableColorLists] objectEnumerator];
2055 while ( (clist = [lenum nextObject]) && new == nil)
2057 cenum = [[clist allKeys] objectEnumerator];
2058 while ( (name = [cenum nextObject]) && new == nil )
2060 if ([name compare: nsname
2061 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2062 new = [clist colorWithKey: name];
2068 *col = [new colorUsingDefaultColorSpace];
2075 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2076 /* --------------------------------------------------------------------------
2077 Convert a Lisp string object to a NS color
2078 -------------------------------------------------------------------------- */
2080 NSTRACE ("ns_lisp_to_color");
2081 if (STRINGP (color))
2082 return ns_get_color (SSDATA (color), col);
2083 else if (SYMBOLP (color))
2084 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2090 ns_color_to_lisp (NSColor *col)
2091 /* --------------------------------------------------------------------------
2092 Convert a color to a lisp string with the RGB equivalent
2093 -------------------------------------------------------------------------- */
2095 EmacsCGFloat red, green, blue, alpha, gray;
2098 NSTRACE ("ns_color_to_lisp");
2101 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
2103 if ((str =[[col colorNameComponent] UTF8String]))
2106 return build_string ((char *)str);
2109 [[col colorUsingDefaultColorSpace]
2110 getRed: &red green: &green blue: &blue alpha: &alpha];
2111 if (red == green && red == blue)
2113 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
2114 getWhite: &gray alpha: &alpha];
2115 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2116 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
2118 return build_string (buf);
2121 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2122 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2125 return build_string (buf);
2130 ns_query_color(void *col, XColor *color_def, int setPixel)
2131 /* --------------------------------------------------------------------------
2132 Get ARGB values out of NSColor col and put them into color_def.
2133 If setPixel, set the pixel to a concatenated version.
2134 and set color_def pixel to the resulting index.
2135 -------------------------------------------------------------------------- */
2137 EmacsCGFloat r, g, b, a;
2139 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2140 color_def->red = r * 65535;
2141 color_def->green = g * 65535;
2142 color_def->blue = b * 65535;
2144 if (setPixel == YES)
2146 = ARGB_TO_ULONG((int)(a*255),
2147 (int)(r*255), (int)(g*255), (int)(b*255));
2152 ns_defined_color (struct frame *f,
2157 /* --------------------------------------------------------------------------
2158 Return true if named color found, and set color_def rgb accordingly.
2159 If makeIndex and alloc are nonzero put the color in the color_table,
2160 and set color_def pixel to the resulting index.
2161 If makeIndex is zero, set color_def pixel to ARGB.
2162 Return false if not found
2163 -------------------------------------------------------------------------- */
2166 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2169 if (ns_get_color (name, &col) != 0) /* Color not found */
2174 if (makeIndex && alloc)
2175 color_def->pixel = ns_index_color (col, f);
2176 ns_query_color (col, color_def, !makeIndex);
2183 x_set_frame_alpha (struct frame *f)
2184 /* --------------------------------------------------------------------------
2185 change the entire-frame transparency
2186 -------------------------------------------------------------------------- */
2188 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2190 double alpha_min = 1.0;
2192 NSTRACE ("x_set_frame_alpha");
2194 if (dpyinfo->x_highlight_frame == f)
2195 alpha = f->alpha[0];
2197 alpha = f->alpha[1];
2199 if (FLOATP (Vframe_alpha_lower_limit))
2200 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2201 else if (INTEGERP (Vframe_alpha_lower_limit))
2202 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2206 else if (1.0 < alpha)
2208 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2211 #ifdef NS_IMPL_COCOA
2213 EmacsView *view = FRAME_NS_VIEW (f);
2214 [[view window] setAlphaValue: alpha];
2220 /* ==========================================================================
2224 ========================================================================== */
2228 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2229 /* --------------------------------------------------------------------------
2230 Programmatically reposition mouse pointer in pixel coordinates
2231 -------------------------------------------------------------------------- */
2233 NSTRACE ("frame_set_mouse_pixel_position");
2236 /* FIXME: this does not work, and what about GNUstep? */
2237 #ifdef NS_IMPL_COCOA
2238 [FRAME_NS_VIEW (f) lockFocus];
2239 PSsetmouse ((float)pix_x, (float)pix_y);
2240 [FRAME_NS_VIEW (f) unlockFocus];
2246 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2247 /* ------------------------------------------------------------------------
2248 Called by EmacsView on mouseMovement events. Passes on
2249 to emacs mainstream code if we moved off of a rect of interest
2250 known as last_mouse_glyph.
2251 ------------------------------------------------------------------------ */
2253 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2256 // NSTRACE ("note_mouse_movement");
2258 dpyinfo->last_mouse_motion_frame = frame;
2259 r = &dpyinfo->last_mouse_glyph;
2261 /* Note, this doesn't get called for enter/leave, since we don't have a
2262 position. Those are taken care of in the corresponding NSView methods. */
2264 /* has movement gone beyond last rect we were tracking? */
2265 if (x < r->origin.x || x >= r->origin.x + r->size.width
2266 || y < r->origin.y || y >= r->origin.y + r->size.height)
2268 ns_update_begin (frame);
2269 frame->mouse_moved = 1;
2270 note_mouse_highlight (frame, x, y);
2271 remember_mouse_glyph (frame, x, y, r);
2272 ns_update_end (frame);
2281 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2282 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2284 /* --------------------------------------------------------------------------
2285 External (hook): inform emacs about mouse position and hit parts.
2286 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2287 x & y should be position in the scrollbar (the whole bar, not the handle)
2288 and length of scrollbar respectively
2289 -------------------------------------------------------------------------- */
2293 Lisp_Object frame, tail;
2295 struct ns_display_info *dpyinfo;
2297 NSTRACE ("ns_mouse_position");
2301 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2305 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2309 /* Clear the mouse-moved flag for every frame on this display. */
2310 FOR_EACH_FRAME (tail, frame)
2311 if (FRAME_NS_P (XFRAME (frame))
2312 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2313 XFRAME (frame)->mouse_moved = 0;
2315 dpyinfo->last_mouse_scroll_bar = nil;
2316 if (dpyinfo->last_mouse_frame
2317 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2318 f = dpyinfo->last_mouse_frame;
2320 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2322 if (f && FRAME_NS_P (f))
2324 view = FRAME_NS_VIEW (*fp);
2326 position = [[view window] mouseLocationOutsideOfEventStream];
2327 position = [view convertPoint: position fromView: nil];
2328 remember_mouse_glyph (f, position.x, position.y,
2329 &dpyinfo->last_mouse_glyph);
2330 NSTRACE_POINT ("position", position);
2332 if (bar_window) *bar_window = Qnil;
2333 if (part) *part = scroll_bar_above_handle;
2335 if (x) XSETINT (*x, lrint (position.x));
2336 if (y) XSETINT (*y, lrint (position.y));
2338 *time = dpyinfo->last_mouse_movement_time;
2347 ns_frame_up_to_date (struct frame *f)
2348 /* --------------------------------------------------------------------------
2349 External (hook): Fix up mouse highlighting right after a full update.
2350 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2351 -------------------------------------------------------------------------- */
2353 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2357 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2358 if (f == hlinfo->mouse_face_mouse_frame)
2362 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2363 hlinfo->mouse_face_mouse_x,
2364 hlinfo->mouse_face_mouse_y);
2373 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2374 /* --------------------------------------------------------------------------
2375 External (RIF): set frame mouse pointer type.
2376 -------------------------------------------------------------------------- */
2378 NSTRACE ("ns_define_frame_cursor");
2379 if (FRAME_POINTER_TYPE (f) != cursor)
2381 EmacsView *view = FRAME_NS_VIEW (f);
2382 FRAME_POINTER_TYPE (f) = cursor;
2383 [[view window] invalidateCursorRectsForView: view];
2384 /* Redisplay assumes this function also draws the changed frame
2385 cursor, but this function doesn't, so do it explicitly. */
2386 x_update_cursor (f, 1);
2392 /* ==========================================================================
2396 ========================================================================== */
2400 ns_convert_key (unsigned code)
2401 /* --------------------------------------------------------------------------
2402 Internal call used by NSView-keyDown.
2403 -------------------------------------------------------------------------- */
2405 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2407 /* An array would be faster, but less easy to read. */
2408 for (keysym = 0; keysym < last_keysym; keysym += 2)
2409 if (code == convert_ns_to_X_keysym[keysym])
2410 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2412 /* if decide to use keyCode and Carbon table, use this line:
2413 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2418 x_get_keysym_name (int keysym)
2419 /* --------------------------------------------------------------------------
2420 Called by keyboard.c. Not sure if the return val is important, except
2422 -------------------------------------------------------------------------- */
2424 static char value[16];
2425 NSTRACE ("x_get_keysym_name");
2426 sprintf (value, "%d", keysym);
2432 /* ==========================================================================
2434 Block drawing operations
2436 ========================================================================== */
2440 ns_redraw_scroll_bars (struct frame *f)
2444 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2445 NSTRACE ("ns_redraw_scroll_bars");
2446 for (i =[subviews count]-1; i >= 0; i--)
2448 view = [subviews objectAtIndex: i];
2449 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2456 ns_clear_frame (struct frame *f)
2457 /* --------------------------------------------------------------------------
2458 External (hook): Erase the entire frame
2459 -------------------------------------------------------------------------- */
2461 NSView *view = FRAME_NS_VIEW (f);
2464 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2466 /* comes on initial frame because we have
2467 after-make-frame-functions = select-frame */
2468 if (!FRAME_DEFAULT_FACE (f))
2471 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2476 ns_focus (f, &r, 1);
2477 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2481 /* as of 2006/11 or so this is now needed */
2482 ns_redraw_scroll_bars (f);
2488 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2489 /* --------------------------------------------------------------------------
2490 External (RIF): Clear section of frame
2491 -------------------------------------------------------------------------- */
2493 NSRect r = NSMakeRect (x, y, width, height);
2494 NSView *view = FRAME_NS_VIEW (f);
2495 struct face *face = FRAME_DEFAULT_FACE (f);
2500 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2502 r = NSIntersectionRect (r, [view frame]);
2503 ns_focus (f, &r, 1);
2504 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2513 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2515 NSTRACE ("ns_copy_bits");
2517 if (FRAME_NS_VIEW (f))
2519 hide_bell(); // Ensure the bell image isn't scrolled.
2521 ns_focus (f, &dest, 1);
2522 [FRAME_NS_VIEW (f) scrollRect: src
2523 by: NSMakeSize (dest.origin.x - src.origin.x,
2524 dest.origin.y - src.origin.y)];
2530 ns_scroll_run (struct window *w, struct run *run)
2531 /* --------------------------------------------------------------------------
2532 External (RIF): Insert or delete n lines at line vpos
2533 -------------------------------------------------------------------------- */
2535 struct frame *f = XFRAME (w->frame);
2536 int x, y, width, height, from_y, to_y, bottom_y;
2538 NSTRACE ("ns_scroll_run");
2540 /* begin copy from other terms */
2541 /* Get frame-relative bounding box of the text display area of W,
2542 without mode lines. Include in this box the left and right
2544 window_box (w, ANY_AREA, &x, &y, &width, &height);
2546 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2547 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2548 bottom_y = y + height;
2552 /* Scrolling up. Make sure we don't copy part of the mode
2553 line at the bottom. */
2554 if (from_y + run->height > bottom_y)
2555 height = bottom_y - from_y;
2557 height = run->height;
2561 /* Scrolling down. Make sure we don't copy over the mode line.
2563 if (to_y + run->height > bottom_y)
2564 height = bottom_y - to_y;
2566 height = run->height;
2568 /* end copy from other terms */
2578 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2579 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2581 ns_copy_bits (f, srcRect , dstRect);
2589 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2590 /* --------------------------------------------------------------------------
2591 External (RIF): preparatory to fringe update after text was updated
2592 -------------------------------------------------------------------------- */
2597 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2599 /* begin copy from other terms */
2602 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2603 desired_row->redraw_fringe_bitmaps_p = 1;
2605 /* When a window has disappeared, make sure that no rest of
2606 full-width rows stays visible in the internal border. */
2607 if (windows_or_buffers_changed
2608 && desired_row->full_width_p
2609 && (f = XFRAME (w->frame),
2610 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2612 && (height = desired_row->visible_height,
2615 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2618 ns_clear_frame_area (f, 0, y, width, height);
2619 ns_clear_frame_area (f,
2620 FRAME_PIXEL_WIDTH (f) - width,
2628 ns_shift_glyphs_for_insert (struct frame *f,
2629 int x, int y, int width, int height,
2631 /* --------------------------------------------------------------------------
2632 External (RIF): copy an area horizontally, don't worry about clearing src
2633 -------------------------------------------------------------------------- */
2635 NSRect srcRect = NSMakeRect (x, y, width, height);
2636 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2638 NSTRACE ("ns_shift_glyphs_for_insert");
2640 ns_copy_bits (f, srcRect, dstRect);
2645 /* ==========================================================================
2647 Character encoding and metrics
2649 ========================================================================== */
2653 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2654 /* --------------------------------------------------------------------------
2655 External (RIF); compute left/right overhang of whole string and set in s
2656 -------------------------------------------------------------------------- */
2658 struct font *font = s->font;
2662 struct font_metrics metrics;
2663 unsigned int codes[2];
2664 codes[0] = *(s->char2b);
2665 codes[1] = *(s->char2b + s->nchars - 1);
2667 font->driver->text_extents (font, codes, 2, &metrics);
2668 s->left_overhang = -metrics.lbearing;
2670 = metrics.rbearing > metrics.width
2671 ? metrics.rbearing - metrics.width : 0;
2675 s->left_overhang = 0;
2676 if (EQ (font->driver->type, Qns))
2677 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2678 FONT_HEIGHT (font) * 0.2 : 0;
2680 s->right_overhang = 0;
2686 /* ==========================================================================
2688 Fringe and cursor drawing
2690 ========================================================================== */
2693 extern int max_used_fringe_bitmap;
2695 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2696 struct draw_fringe_bitmap_params *p)
2697 /* --------------------------------------------------------------------------
2698 External (RIF); fringe-related
2699 -------------------------------------------------------------------------- */
2701 /* Fringe bitmaps comes in two variants, normal and periodic. A
2702 periodic bitmap is used to create a continuous pattern. Since a
2703 bitmap is rendered one text line at a time, the start offset (dh)
2704 of the bitmap varies. Concretely, this is used for the empty
2707 For a bitmap, "h + dh" is the full height and is always
2708 invariant. For a normal bitmap "dh" is zero.
2710 For example, when the period is three and the full height is 72
2711 the following combinations exists:
2717 struct frame *f = XFRAME (WINDOW_FRAME (w));
2718 struct face *face = p->face;
2719 static EmacsImage **bimgs = NULL;
2720 static int nBimgs = 0;
2722 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2723 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2724 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2726 /* grow bimgs if needed */
2727 if (nBimgs < max_used_fringe_bitmap)
2729 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2730 memset (bimgs + nBimgs, 0,
2731 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2732 nBimgs = max_used_fringe_bitmap;
2735 /* Must clip because of partially visible lines. */
2736 ns_clip_to_row (w, row, ANY_AREA, YES);
2740 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2742 if (bx >= 0 && nx > 0)
2744 NSRect r = NSMakeRect (bx, by, nx, ny);
2746 [ns_lookup_indexed_color (face->background, f) set];
2753 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2754 EmacsImage *img = bimgs[p->which - 1];
2758 // Note: For "periodic" images, allocate one EmacsImage for
2759 // the base image, and use it for all dh:s.
2760 unsigned short *bits = p->bits;
2761 int full_height = p->h + p->dh;
2763 unsigned char *cbits = xmalloc (full_height);
2765 for (i = 0; i < full_height; i++)
2767 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2770 bimgs[p->which - 1] = img;
2774 NSTRACE_RECT ("r", r);
2777 /* Since we composite the bitmap instead of just blitting it, we need
2778 to erase the whole background. */
2779 [ns_lookup_indexed_color(face->background, f) set];
2785 bm_color = ns_lookup_indexed_color(face->foreground, f);
2786 else if (p->overlay_p)
2787 bm_color = ns_lookup_indexed_color(face->background, f);
2789 bm_color = f->output_data.ns->cursor_color;
2790 [img setXBMColor: bm_color];
2793 #ifdef NS_IMPL_COCOA
2794 // Note: For periodic images, the full image height is "h + hd".
2795 // By using the height h, a suitable part of the image is used.
2796 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2798 NSTRACE_RECT ("fromRect", fromRect);
2802 operation: NSCompositeSourceOver
2808 NSPoint pt = r.origin;
2810 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2819 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2820 int x, int y, enum text_cursor_kinds cursor_type,
2821 int cursor_width, bool on_p, bool active_p)
2822 /* --------------------------------------------------------------------------
2823 External call (RIF): draw cursor.
2824 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2825 -------------------------------------------------------------------------- */
2828 int fx, fy, h, cursor_height;
2829 struct frame *f = WINDOW_XFRAME (w);
2830 struct glyph *phys_cursor_glyph;
2831 struct glyph *cursor_glyph;
2833 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2835 /* If cursor is out of bounds, don't draw garbage. This can happen
2836 in mini-buffer windows when switching between echo area glyphs
2839 NSTRACE ("ns_draw_window_cursor");
2844 w->phys_cursor_type = cursor_type;
2845 w->phys_cursor_on_p = on_p;
2847 if (cursor_type == NO_CURSOR)
2849 w->phys_cursor_width = 0;
2853 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2855 if (glyph_row->exact_window_width_line_p
2856 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2858 glyph_row->cursor_in_fringe_p = 1;
2859 draw_fringe_bitmap (w, glyph_row, 0);
2864 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2865 (other terminals do it the other way round). We must set
2866 w->phys_cursor_width to the cursor width. For bar cursors, that
2867 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2868 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2870 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2871 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2872 if (cursor_type == BAR_CURSOR)
2874 if (cursor_width < 1)
2875 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2876 w->phys_cursor_width = cursor_width;
2878 /* If we have an HBAR, "cursor_width" MAY specify height. */
2879 else if (cursor_type == HBAR_CURSOR)
2881 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2882 if (cursor_height > glyph_row->height)
2883 cursor_height = glyph_row->height;
2884 if (h > cursor_height) // Cursor smaller than line height, move down
2885 fy += h - cursor_height;
2889 r.origin.x = fx, r.origin.y = fy;
2891 r.size.width = w->phys_cursor_width;
2893 /* TODO: only needed in rare cases with last-resort font in HELLO..
2894 should we do this more efficiently? */
2895 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2898 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2899 if (face && NS_FACE_BACKGROUND (face)
2900 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2902 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2903 hollow_color = FRAME_CURSOR_COLOR (f);
2906 [FRAME_CURSOR_COLOR (f) set];
2908 #ifdef NS_IMPL_COCOA
2909 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2910 atomic. Cleaner ways of doing this should be investigated.
2911 One way would be to set a global variable DRAWING_CURSOR
2912 when making the call to draw_phys..(), don't focus in that
2913 case, then move the ns_unfocus() here after that call. */
2914 NSDisableScreenUpdates ();
2917 switch (cursor_type)
2919 case DEFAULT_CURSOR:
2922 case FILLED_BOX_CURSOR:
2925 case HOLLOW_BOX_CURSOR:
2928 NSRectFill (NSInsetRect (r, 1, 1));
2929 [FRAME_CURSOR_COLOR (f) set];
2936 /* If the character under cursor is R2L, draw the bar cursor
2937 on the right of its glyph, rather than on the left. */
2938 cursor_glyph = get_phys_cursor_glyph (w);
2939 if ((cursor_glyph->resolved_level & 1) != 0)
2940 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2947 /* draw the character under the cursor */
2948 if (cursor_type != NO_CURSOR)
2949 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2951 #ifdef NS_IMPL_COCOA
2952 NSEnableScreenUpdates ();
2959 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2960 /* --------------------------------------------------------------------------
2961 External (RIF): Draw a vertical line.
2962 -------------------------------------------------------------------------- */
2964 struct frame *f = XFRAME (WINDOW_FRAME (w));
2966 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2968 NSTRACE ("ns_draw_vertical_window_border");
2970 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2972 [ns_lookup_indexed_color(face->foreground, f) set];
2974 ns_focus (f, &r, 1);
2981 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2982 /* --------------------------------------------------------------------------
2983 External (RIF): Draw a window divider.
2984 -------------------------------------------------------------------------- */
2986 struct frame *f = XFRAME (WINDOW_FRAME (w));
2988 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2990 NSTRACE ("ns_draw_window_divider");
2992 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2994 [ns_lookup_indexed_color(face->foreground, f) set];
2996 ns_focus (f, &r, 1);
3002 ns_show_hourglass (struct frame *f)
3004 /* TODO: add NSProgressIndicator to all frames. */
3008 ns_hide_hourglass (struct frame *f)
3010 /* TODO: remove NSProgressIndicator from all frames. */
3013 /* ==========================================================================
3015 Glyph drawing operations
3017 ========================================================================== */
3020 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3021 /* --------------------------------------------------------------------------
3022 Wrapper utility to account for internal border width on full-width lines,
3023 and allow top full-width rows to hit the frame top. nr should be pointer
3024 to two successive NSRects. Number of rects actually used is returned.
3025 -------------------------------------------------------------------------- */
3027 int n = get_glyph_string_clip_rects (s, nr, 2);
3031 /* --------------------------------------------------------------------
3032 Draw a wavy line under glyph string s. The wave fills wave_height
3039 wave_height = 3 | * * * *
3040 --------------------------------------------------------------------- */
3043 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3045 int wave_height = 3, wave_length = 2;
3046 int y, dx, dy, odd, xmax;
3051 dy = wave_height - 1;
3052 y = s->ybase - wave_height + 3;
3055 /* Find and set clipping rectangle */
3056 waveClip = NSMakeRect (x, y, width, wave_height);
3057 [[NSGraphicsContext currentContext] saveGraphicsState];
3058 NSRectClip (waveClip);
3060 /* Draw the waves */
3061 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3063 odd = (int)(a.x/dx) % 2;
3064 a.y = b.y = y + 0.5;
3073 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3074 a.x = b.x, a.y = b.y;
3075 b.x += dx, b.y = y + 0.5 + odd*dy;
3079 /* Restore previous clipping rectangle(s) */
3080 [[NSGraphicsContext currentContext] restoreGraphicsState];
3086 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3087 NSColor *defaultCol, CGFloat width, CGFloat x)
3088 /* --------------------------------------------------------------------------
3089 Draw underline, overline, and strike-through on glyph string s.
3090 -------------------------------------------------------------------------- */
3092 if (s->for_overlaps)
3096 if (face->underline_p)
3098 if (s->face->underline_type == FACE_UNDER_WAVE)
3100 if (face->underline_defaulted_p)
3103 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3105 ns_draw_underwave (s, width, x);
3107 else if (s->face->underline_type == FACE_UNDER_LINE)
3111 unsigned long thickness, position;
3113 /* If the prev was underlined, match its appearance. */
3114 if (s->prev && s->prev->face->underline_p
3115 && s->prev->face->underline_type == FACE_UNDER_LINE
3116 && s->prev->underline_thickness > 0)
3118 thickness = s->prev->underline_thickness;
3119 position = s->prev->underline_position;
3124 unsigned long descent;
3127 descent = s->y + s->height - s->ybase;
3129 /* Use underline thickness of font, defaulting to 1. */
3130 thickness = (font && font->underline_thickness > 0)
3131 ? font->underline_thickness : 1;
3133 /* Determine the offset of underlining from the baseline. */
3134 if (x_underline_at_descent_line)
3135 position = descent - thickness;
3136 else if (x_use_underline_position_properties
3137 && font && font->underline_position >= 0)
3138 position = font->underline_position;
3140 position = lround (font->descent / 2);
3142 position = underline_minimum_offset;
3144 position = max (position, underline_minimum_offset);
3146 /* Ensure underlining is not cropped. */
3147 if (descent <= position)
3149 position = descent - 1;
3152 else if (descent < position + thickness)
3156 s->underline_thickness = thickness;
3157 s->underline_position = position;
3159 r = NSMakeRect (x, s->ybase + position, width, thickness);
3161 if (face->underline_defaulted_p)
3164 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3168 /* Do overline. We follow other terms in using a thickness of 1
3169 and ignoring overline_margin. */
3170 if (face->overline_p)
3173 r = NSMakeRect (x, s->y, width, 1);
3175 if (face->overline_color_defaulted_p)
3178 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3182 /* Do strike-through. We follow other terms for thickness and
3183 vertical position.*/
3184 if (face->strike_through_p)
3189 dy = lrint ((s->height - 1) / 2);
3190 r = NSMakeRect (x, s->y + dy, width, 1);
3192 if (face->strike_through_color_defaulted_p)
3195 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3201 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3202 char left_p, char right_p)
3203 /* --------------------------------------------------------------------------
3204 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3205 Note we can't just use an NSDrawRect command, because of the possibility
3206 of some sides not being drawn, and because the rect will be filled.
3207 -------------------------------------------------------------------------- */
3213 s.size.height = thickness;
3215 s.origin.y += r.size.height - thickness;
3218 s.size.height = r.size.height;
3219 s.origin.y = r.origin.y;
3221 /* left, right (optional) */
3222 s.size.width = thickness;
3227 s.origin.x += r.size.width - thickness;
3234 ns_draw_relief (NSRect r, int thickness, char raised_p,
3235 char top_p, char bottom_p, char left_p, char right_p,
3236 struct glyph_string *s)
3237 /* --------------------------------------------------------------------------
3238 Draw a relief rect inside r, optionally leaving some sides open.
3239 Note we can't just use an NSDrawBezel command, because of the possibility
3240 of some sides not being drawn, and because the rect will be filled.
3241 -------------------------------------------------------------------------- */
3243 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3244 NSColor *newBaseCol = nil;
3247 NSTRACE ("ns_draw_relief");
3251 if (s->face->use_box_color_for_shadows_p)
3253 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3255 /* else if (s->first_glyph->type == IMAGE_GLYPH
3257 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3259 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3263 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3266 if (newBaseCol == nil)
3267 newBaseCol = [NSColor grayColor];
3269 if (newBaseCol != baseCol) /* TODO: better check */
3272 baseCol = [newBaseCol retain];
3274 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3276 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3279 [(raised_p ? lightCol : darkCol) set];
3281 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3284 sr.size.height = thickness;
3285 if (top_p) NSRectFill (sr);
3288 sr.size.height = r.size.height;
3289 sr.size.width = thickness;
3290 if (left_p) NSRectFill (sr);
3292 [(raised_p ? darkCol : lightCol) set];
3295 sr.size.width = r.size.width;
3296 sr.size.height = thickness;
3297 sr.origin.y += r.size.height - thickness;
3298 if (bottom_p) NSRectFill (sr);
3301 sr.size.height = r.size.height;
3302 sr.origin.y = r.origin.y;
3303 sr.size.width = thickness;
3304 sr.origin.x += r.size.width - thickness;
3305 if (right_p) NSRectFill (sr);
3310 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3311 /* --------------------------------------------------------------------------
3312 Function modeled after x_draw_glyph_string_box ().
3313 Sets up parameters for drawing.
3314 -------------------------------------------------------------------------- */
3316 int right_x, last_x;
3317 char left_p, right_p;
3318 struct glyph *last_glyph;
3323 if (s->hl == DRAW_MOUSE_FACE)
3325 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3327 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3332 thickness = face->box_line_width;
3334 NSTRACE ("ns_dumpglyphs_box_or_relief");
3336 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3337 ? WINDOW_RIGHT_EDGE_X (s->w)
3338 : window_box_right (s->w, s->area));
3339 last_glyph = (s->cmp || s->img
3340 ? s->first_glyph : s->first_glyph + s->nchars-1);
3342 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3343 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3345 left_p = (s->first_glyph->left_box_line_p
3346 || (s->hl == DRAW_MOUSE_FACE
3347 && (s->prev == NULL || s->prev->hl != s->hl)));
3348 right_p = (last_glyph->right_box_line_p
3349 || (s->hl == DRAW_MOUSE_FACE
3350 && (s->next == NULL || s->next->hl != s->hl)));
3352 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3354 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3355 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3357 ns_draw_box (r, abs (thickness),
3358 ns_lookup_indexed_color (face->box_color, s->f),
3363 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3364 1, 1, left_p, right_p, s);
3370 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3371 /* --------------------------------------------------------------------------
3372 Modeled after x_draw_glyph_string_background, which draws BG in
3373 certain cases. Others are left to the text rendering routine.
3374 -------------------------------------------------------------------------- */
3376 NSTRACE ("ns_maybe_dumpglyphs_background");
3378 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3380 int box_line_width = max (s->face->box_line_width, 0);
3381 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3382 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3383 dimensions, since the actual glyphs might be much
3384 smaller. So in that case we always clear the rectangle
3385 with background color. */
3386 || FONT_TOO_HIGH (s->font)
3387 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3390 if (s->hl == DRAW_MOUSE_FACE)
3392 face = FACE_FROM_ID (s->f,
3393 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3395 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3398 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3400 [(NS_FACE_BACKGROUND (face) != 0
3401 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3402 : FRAME_BACKGROUND_COLOR (s->f)) set];
3405 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3406 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3409 if (s->hl != DRAW_CURSOR)
3411 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3412 s->background_width,
3413 s->height-2*box_line_width);
3417 s->background_filled_p = 1;
3424 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3425 /* --------------------------------------------------------------------------
3426 Renders an image and associated borders.
3427 -------------------------------------------------------------------------- */
3429 EmacsImage *img = s->img->pixmap;
3430 int box_line_vwidth = max (s->face->box_line_width, 0);
3431 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3432 int bg_x, bg_y, bg_height;
3439 NSTRACE ("ns_dumpglyphs_image");
3441 if (s->face->box != FACE_NO_BOX
3442 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3443 x += abs (s->face->box_line_width);
3446 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3447 bg_height = s->height;
3448 /* other terms have this, but was causing problems w/tabbar mode */
3449 /* - 2 * box_line_vwidth; */
3451 if (s->slice.x == 0) x += s->img->hmargin;
3452 if (s->slice.y == 0) y += s->img->vmargin;
3454 /* Draw BG: if we need larger area than image itself cleared, do that,
3455 otherwise, since we composite the image under NS (instead of mucking
3456 with its background color), we must clear just the image area. */
3457 if (s->hl == DRAW_MOUSE_FACE)
3459 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3461 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3464 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3466 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3468 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3469 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3471 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3472 s->background_filled_p = 1;
3476 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3481 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3484 #ifdef NS_IMPL_COCOA
3485 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3486 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3487 s->slice.width, s->slice.height);
3490 operation: NSCompositeSourceOver
3495 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3496 operation: NSCompositeSourceOver];
3500 if (s->hl == DRAW_CURSOR)
3502 [FRAME_CURSOR_COLOR (s->f) set];
3503 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3504 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3506 /* Currently on NS img->mask is always 0. Since
3507 get_window_cursor_type specifies a hollow box cursor when on
3508 a non-masked image we never reach this clause. But we put it
3509 in in anticipation of better support for image masks on
3511 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3515 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3518 /* Draw underline, overline, strike-through. */
3519 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3521 /* Draw relief, if requested */
3522 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3524 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3526 th = tool_bar_button_relief >= 0 ?
3527 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3528 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3532 th = abs (s->img->relief);
3533 raised_p = (s->img->relief > 0);
3536 r.origin.x = x - th;
3537 r.origin.y = y - th;
3538 r.size.width = s->slice.width + 2*th-1;
3539 r.size.height = s->slice.height + 2*th-1;
3540 ns_draw_relief (r, th, raised_p,
3542 s->slice.y + s->slice.height == s->img->height,
3544 s->slice.x + s->slice.width == s->img->width, s);
3547 /* If there is no mask, the background won't be seen,
3548 so draw a rectangle on the image for the cursor.
3549 Do this for all images, getting transparency right is not reliable. */
3550 if (s->hl == DRAW_CURSOR)
3552 int thickness = abs (s->img->relief);
3553 if (thickness == 0) thickness = 1;
3554 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3560 ns_dumpglyphs_stretch (struct glyph_string *s)
3565 NSColor *fgCol, *bgCol;
3567 if (!s->background_filled_p)
3569 n = ns_get_glyph_string_clip_rect (s, r);
3570 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3572 ns_focus (s->f, r, n);
3574 if (s->hl == DRAW_MOUSE_FACE)
3576 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3578 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3581 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3583 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3584 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3586 for (i = 0; i < n; ++i)
3588 if (!s->row->full_width_p)
3590 int overrun, leftoverrun;
3592 /* truncate to avoid overwriting fringe and/or scrollbar */
3593 overrun = max (0, (s->x + s->background_width)
3594 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3595 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3596 r[i].size.width -= overrun;
3598 /* truncate to avoid overwriting to left of the window box */
3599 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3600 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3602 if (leftoverrun > 0)
3604 r[i].origin.x += leftoverrun;
3605 r[i].size.width -= leftoverrun;
3608 /* XXX: Try to work between problem where a stretch glyph on
3609 a partially-visible bottom row will clear part of the
3610 modeline, and another where list-buffers headers and similar
3611 rows erroneously have visible_height set to 0. Not sure
3612 where this is coming from as other terms seem not to show. */
3613 r[i].size.height = min (s->height, s->row->visible_height);
3618 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3619 overwriting cursor (usually when cursor on a tab) */
3620 if (s->hl == DRAW_CURSOR)
3625 width = s->w->phys_cursor_width;
3626 r[i].size.width -= width;
3627 r[i].origin.x += width;
3631 /* Draw overlining, etc. on the cursor. */
3632 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3633 ns_draw_text_decoration (s, face, bgCol, width, x);
3635 ns_draw_text_decoration (s, face, fgCol, width, x);
3642 /* Draw overlining, etc. on the stretch glyph (or the part
3643 of the stretch glyph after the cursor). */
3644 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3648 s->background_filled_p = 1;
3654 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3657 struct font *font = s->font;
3659 /* If first glyph of S has a left box line, start drawing the text
3660 of S to the right of that box line. */
3661 if (s->face && s->face->box != FACE_NO_BOX
3662 && s->first_glyph->left_box_line_p)
3663 x = s->x + eabs (s->face->box_line_width);
3667 /* S is a glyph string for a composition. S->cmp_from is the index
3668 of the first character drawn for glyphs of this composition.
3669 S->cmp_from == 0 means we are drawing the very first character of
3670 this composition. */
3672 /* Draw a rectangle for the composition if the font for the very
3673 first character of the composition could not be loaded. */
3674 if (s->font_not_found_p)
3676 if (s->cmp_from == 0)
3678 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3679 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3682 else if (! s->first_glyph->u.cmp.automatic)
3686 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3687 /* TAB in a composition means display glyphs with padding
3688 space on the left or right. */
3689 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3691 int xx = x + s->cmp->offsets[j * 2];
3692 int yy = y - s->cmp->offsets[j * 2 + 1];
3694 font->driver->draw (s, j, j + 1, xx, yy, false);
3695 if (s->face->overstrike)
3696 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3701 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3706 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3708 glyph = LGSTRING_GLYPH (gstring, i);
3709 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3710 width += LGLYPH_WIDTH (glyph);
3713 int xoff, yoff, wadjust;
3717 font->driver->draw (s, j, i, x, y, false);
3718 if (s->face->overstrike)
3719 font->driver->draw (s, j, i, x + 1, y, false);
3722 xoff = LGLYPH_XOFF (glyph);
3723 yoff = LGLYPH_YOFF (glyph);
3724 wadjust = LGLYPH_WADJUST (glyph);
3725 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3726 if (s->face->overstrike)
3727 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3736 font->driver->draw (s, j, i, x, y, false);
3737 if (s->face->overstrike)
3738 font->driver->draw (s, j, i, x + 1, y, false);
3744 ns_draw_glyph_string (struct glyph_string *s)
3745 /* --------------------------------------------------------------------------
3746 External (RIF): Main draw-text call.
3747 -------------------------------------------------------------------------- */
3749 /* TODO (optimize): focus for box and contents draw */
3752 char box_drawn_p = 0;
3753 struct font *font = s->face->font;
3754 if (! font) font = FRAME_FONT (s->f);
3756 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3758 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3761 struct glyph_string *next;
3763 for (width = 0, next = s->next;
3764 next && width < s->right_overhang;
3765 width += next->width, next = next->next)
3766 if (next->first_glyph->type != IMAGE_GLYPH)
3768 if (next->first_glyph->type != STRETCH_GLYPH)
3770 n = ns_get_glyph_string_clip_rect (s->next, r);
3771 ns_focus (s->f, r, n);
3772 ns_maybe_dumpglyphs_background (s->next, 1);
3777 ns_dumpglyphs_stretch (s->next);
3779 next->num_clips = 0;
3783 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3784 && (s->first_glyph->type == CHAR_GLYPH
3785 || s->first_glyph->type == COMPOSITE_GLYPH))
3787 n = ns_get_glyph_string_clip_rect (s, r);
3788 ns_focus (s->f, r, n);
3789 ns_maybe_dumpglyphs_background (s, 1);
3790 ns_dumpglyphs_box_or_relief (s);
3795 switch (s->first_glyph->type)
3799 n = ns_get_glyph_string_clip_rect (s, r);
3800 ns_focus (s->f, r, n);
3801 ns_dumpglyphs_image (s, r[0]);
3806 ns_dumpglyphs_stretch (s);
3810 case COMPOSITE_GLYPH:
3811 n = ns_get_glyph_string_clip_rect (s, r);
3812 ns_focus (s->f, r, n);
3814 if (s->for_overlaps || (s->cmp_from > 0
3815 && ! s->first_glyph->u.cmp.automatic))
3816 s->background_filled_p = 1;
3818 ns_maybe_dumpglyphs_background
3819 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3821 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3822 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3823 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3824 NS_DUMPGLYPH_NORMAL));
3826 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3828 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3829 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3830 NS_FACE_FOREGROUND (s->face) = tmp;
3834 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3837 ns_draw_composite_glyph_string_foreground (s);
3840 (s, s->cmp_from, s->nchars, s->x, s->ybase,
3841 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3842 || flags == NS_DUMPGLYPH_MOUSEFACE);
3846 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3847 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3849 : FRAME_FOREGROUND_COLOR (s->f));
3852 /* Draw underline, overline, strike-through. */
3853 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3856 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3858 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3859 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3860 NS_FACE_FOREGROUND (s->face) = tmp;
3866 case GLYPHLESS_GLYPH:
3867 n = ns_get_glyph_string_clip_rect (s, r);
3868 ns_focus (s->f, r, n);
3870 if (s->for_overlaps || (s->cmp_from > 0
3871 && ! s->first_glyph->u.cmp.automatic))
3872 s->background_filled_p = 1;
3874 ns_maybe_dumpglyphs_background
3875 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3877 /* Not yet implemented. */
3886 /* Draw box if not done already. */
3887 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3889 n = ns_get_glyph_string_clip_rect (s, r);
3890 ns_focus (s->f, r, n);
3891 ns_dumpglyphs_box_or_relief (s);
3900 /* ==========================================================================
3904 ========================================================================== */
3908 ns_send_appdefined (int value)
3909 /* --------------------------------------------------------------------------
3910 Internal: post an appdefined event which EmacsApp-sendEvent will
3911 recognize and take as a command to halt the event loop.
3912 -------------------------------------------------------------------------- */
3914 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3916 #ifdef NS_IMPL_GNUSTEP
3917 // GNUstep needs postEvent to happen on the main thread.
3918 if (! [[NSThread currentThread] isMainThread])
3920 EmacsApp *app = (EmacsApp *)NSApp;
3921 app->nextappdefined = value;
3922 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3929 /* Only post this event if we haven't already posted one. This will end
3930 the [NXApp run] main loop after having processed all events queued at
3933 #ifdef NS_IMPL_COCOA
3934 if (! send_appdefined)
3936 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3937 in certain situations (rapid incoming events).
3938 So check if we have one, if not add one. */
3939 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3940 untilDate:[NSDate distantPast]
3941 inMode:NSDefaultRunLoopMode
3943 if (! appev) send_appdefined = YES;
3947 if (send_appdefined)
3951 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3952 send_appdefined = NO;
3954 /* Don't need wakeup timer any more */
3957 [timed_entry invalidate];
3958 [timed_entry release];
3962 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3963 location: NSMakePoint (0, 0)
3966 windowNumber: [[NSApp mainWindow] windowNumber]
3967 context: [NSApp context]
3972 /* Post an application defined event on the event queue. When this is
3973 received the [NXApp run] will return, thus having processed all
3974 events which are currently queued. */
3975 [NSApp postEvent: nxev atStart: NO];
3979 #ifdef HAVE_NATIVE_FS
3983 Lisp_Object frame, tail;
3985 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3988 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3990 FOR_EACH_FRAME (tail, frame)
3992 struct frame *f = XFRAME (frame);
3995 EmacsView *view = FRAME_NS_VIEW (f);
3996 [view updateCollectionBehavior];
4002 /* GNUstep does not have cancelTracking. */
4003 #ifdef NS_IMPL_COCOA
4004 /* Check if menu open should be canceled or continued as normal. */
4006 ns_check_menu_open (NSMenu *menu)
4008 /* Click in menu bar? */
4009 NSArray *a = [[NSApp mainMenu] itemArray];
4013 if (menu == nil) // Menu tracking ended.
4015 if (menu_will_open_state == MENU_OPENING)
4016 menu_will_open_state = MENU_NONE;
4020 for (i = 0; ! found && i < [a count]; i++)
4021 found = menu == [[a objectAtIndex:i] submenu];
4024 if (menu_will_open_state == MENU_NONE && emacs_event)
4026 NSEvent *theEvent = [NSApp currentEvent];
4027 struct frame *emacsframe = SELECTED_FRAME ();
4029 [menu cancelTracking];
4030 menu_will_open_state = MENU_PENDING;
4031 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4032 EV_TRAILER (theEvent);
4034 CGEventRef ourEvent = CGEventCreate (NULL);
4035 menu_mouse_point = CGEventGetLocation (ourEvent);
4036 CFRelease (ourEvent);
4038 else if (menu_will_open_state == MENU_OPENING)
4040 menu_will_open_state = MENU_NONE;
4045 /* Redo saved menu click if state is MENU_PENDING. */
4047 ns_check_pending_open_menu ()
4049 if (menu_will_open_state == MENU_PENDING)
4051 CGEventSourceRef source
4052 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4054 CGEventRef event = CGEventCreateMouseEvent (source,
4055 kCGEventLeftMouseDown,
4057 kCGMouseButtonLeft);
4058 CGEventSetType (event, kCGEventLeftMouseDown);
4059 CGEventPost (kCGHIDEventTap, event);
4063 menu_will_open_state = MENU_OPENING;
4066 #endif /* NS_IMPL_COCOA */
4069 unwind_apploopnr (Lisp_Object not_used)
4072 n_emacs_events_pending = 0;
4073 ns_finish_events ();
4078 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4079 /* --------------------------------------------------------------------------
4080 External (hook): Post an event to ourself and keep reading events until
4081 we read it back again. In effect process all events which were waiting.
4082 From 21+ we have to manage the event buffer ourselves.
4083 -------------------------------------------------------------------------- */
4085 struct input_event ev;
4088 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4090 #ifdef HAVE_NATIVE_FS
4094 if ([NSApp modalWindow] != nil)
4097 if (hold_event_q.nr > 0)
4100 for (i = 0; i < hold_event_q.nr; ++i)
4101 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4102 hold_event_q.nr = 0;
4107 n_emacs_events_pending = 0;
4108 ns_init_events (&ev);
4109 q_event_ptr = hold_quit;
4111 /* we manage autorelease pools by allocate/reallocate each time around
4112 the loop; strict nesting is occasionally violated but seems not to
4113 matter.. earlier methods using full nesting caused major memory leaks */
4114 [outerpool release];
4115 outerpool = [[NSAutoreleasePool alloc] init];
4117 /* If have pending open-file requests, attend to the next one of those. */
4118 if (ns_pending_files && [ns_pending_files count] != 0
4119 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4121 [ns_pending_files removeObjectAtIndex: 0];
4123 /* Deal with pending service requests. */
4124 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4126 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4127 withArg: [ns_pending_service_args objectAtIndex: 0]])
4129 [ns_pending_service_names removeObjectAtIndex: 0];
4130 [ns_pending_service_args removeObjectAtIndex: 0];
4134 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4135 /* Run and wait for events. We must always send one NX_APPDEFINED event
4136 to ourself, otherwise [NXApp run] will never exit. */
4137 send_appdefined = YES;
4138 ns_send_appdefined (-1);
4140 if (++apploopnr != 1)
4144 record_unwind_protect (unwind_apploopnr, Qt);
4146 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4149 nevents = n_emacs_events_pending;
4150 n_emacs_events_pending = 0;
4151 ns_finish_events ();
4160 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4161 fd_set *exceptfds, struct timespec const *timeout,
4162 sigset_t const *sigmask)
4163 /* --------------------------------------------------------------------------
4164 Replacement for select, checking for events
4165 -------------------------------------------------------------------------- */
4169 struct input_event event;
4172 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4174 #ifdef HAVE_NATIVE_FS
4178 if (hold_event_q.nr > 0)
4180 /* We already have events pending. */
4186 for (k = 0; k < nfds+1; k++)
4188 if (readfds && FD_ISSET(k, readfds)) ++nr;
4189 if (writefds && FD_ISSET(k, writefds)) ++nr;
4193 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4194 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4196 [outerpool release];
4197 outerpool = [[NSAutoreleasePool alloc] init];
4200 send_appdefined = YES;
4203 pthread_mutex_lock (&select_mutex);
4208 select_readfds = *readfds;
4209 select_valid += SELECT_HAVE_READ;
4213 select_writefds = *writefds;
4214 select_valid += SELECT_HAVE_WRITE;
4219 select_timeout = *timeout;
4220 select_valid += SELECT_HAVE_TMO;
4223 pthread_mutex_unlock (&select_mutex);
4225 /* Inform fd_handler that select should be called */
4227 emacs_write_sig (selfds[1], &c, 1);
4229 else if (nr == 0 && timeout)
4231 /* No file descriptor, just a timeout, no need to wake fd_handler */
4232 double time = timespectod (*timeout);
4233 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4236 @selector (timeout_handler:)
4241 else /* No timeout and no file descriptors, can this happen? */
4243 /* Send appdefined so we exit from the loop */
4244 ns_send_appdefined (-1);
4248 ns_init_events (&event);
4249 if (++apploopnr != 1)
4255 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4256 record_unwind_protect (unwind_apploopnr, Qt);
4258 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4261 ns_finish_events ();
4262 if (nr > 0 && readfds)
4265 emacs_write_sig (selfds[1], &c, 1);
4269 t = last_appdefined_event_data;
4271 if (t != NO_APPDEFINED_DATA)
4273 last_appdefined_event_data = NO_APPDEFINED_DATA;
4277 /* The NX_APPDEFINED event we received was a timeout. */
4282 /* The NX_APPDEFINED event we received was the result of
4283 at least one real input event arriving. */
4289 /* Received back from select () in fd_handler; copy the results */
4290 pthread_mutex_lock (&select_mutex);
4291 if (readfds) *readfds = select_readfds;
4292 if (writefds) *writefds = select_writefds;
4293 pthread_mutex_unlock (&select_mutex);
4308 /* ==========================================================================
4312 ========================================================================== */
4316 ns_set_vertical_scroll_bar (struct window *window,
4317 int portion, int whole, int position)
4318 /* --------------------------------------------------------------------------
4319 External (hook): Update or add scrollbar
4320 -------------------------------------------------------------------------- */
4324 struct frame *f = XFRAME (WINDOW_FRAME (window));
4325 EmacsView *view = FRAME_NS_VIEW (f);
4327 int window_y, window_height;
4328 int top, left, height, width;
4329 BOOL update_p = YES;
4331 /* optimization; display engine sends WAY too many of these.. */
4332 if (!NILP (window->vertical_scroll_bar))
4334 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4335 if ([bar checkSamePosition: position portion: portion whole: whole])
4337 if (view->scrollbarsNeedingUpdate == 0)
4339 if (!windows_or_buffers_changed)
4343 view->scrollbarsNeedingUpdate--;
4348 NSTRACE ("ns_set_vertical_scroll_bar");
4350 /* Get dimensions. */
4351 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4353 height = window_height;
4354 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4355 left = WINDOW_SCROLL_BAR_AREA_X (window);
4357 r = NSMakeRect (left, top, width, height);
4358 /* the parent view is flipped, so we need to flip y value */
4360 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4362 XSETWINDOW (win, window);
4365 /* we want at least 5 lines to display a scrollbar */
4366 if (WINDOW_TOTAL_LINES (window) < 5)
4368 if (!NILP (window->vertical_scroll_bar))
4370 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4371 [bar removeFromSuperview];
4372 wset_vertical_scroll_bar (window, Qnil);
4375 ns_clear_frame_area (f, left, top, width, height);
4380 if (NILP (window->vertical_scroll_bar))
4382 if (width > 0 && height > 0)
4383 ns_clear_frame_area (f, left, top, width, height);
4385 bar = [[EmacsScroller alloc] initFrame: r window: win];
4386 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4392 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4393 oldRect = [bar frame];
4394 r.size.width = oldRect.size.width;
4395 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4397 if (oldRect.origin.x != r.origin.x)
4398 ns_clear_frame_area (f, left, top, width, height);
4404 [bar setPosition: position portion: portion whole: whole];
4410 ns_set_horizontal_scroll_bar (struct window *window,
4411 int portion, int whole, int position)
4412 /* --------------------------------------------------------------------------
4413 External (hook): Update or add scrollbar
4414 -------------------------------------------------------------------------- */
4418 struct frame *f = XFRAME (WINDOW_FRAME (window));
4419 EmacsView *view = FRAME_NS_VIEW (f);
4421 int top, height, left, width;
4422 int window_x, window_width;
4423 BOOL update_p = YES;
4425 /* optimization; display engine sends WAY too many of these.. */
4426 if (!NILP (window->horizontal_scroll_bar))
4428 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4429 if ([bar checkSamePosition: position portion: portion whole: whole])
4431 if (view->scrollbarsNeedingUpdate == 0)
4433 if (!windows_or_buffers_changed)
4437 view->scrollbarsNeedingUpdate--;
4442 NSTRACE ("ns_set_horizontal_scroll_bar");
4444 /* Get dimensions. */
4445 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4447 width = window_width;
4448 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4449 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4451 r = NSMakeRect (left, top, width, height);
4452 /* the parent view is flipped, so we need to flip y value */
4454 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4455 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4457 XSETWINDOW (win, window);
4460 if (WINDOW_TOTAL_COLS (window) < 5)
4462 if (!NILP (window->horizontal_scroll_bar))
4464 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4465 [bar removeFromSuperview];
4466 wset_horizontal_scroll_bar (window, Qnil);
4468 ns_clear_frame_area (f, left, top, width, height);
4473 if (NILP (window->horizontal_scroll_bar))
4475 if (width > 0 && height > 0)
4476 ns_clear_frame_area (f, left, top, width, height);
4478 bar = [[EmacsScroller alloc] initFrame: r window: win];
4479 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4485 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4486 oldRect = [bar frame];
4487 r.size.width = oldRect.size.width;
4488 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4490 if (oldRect.origin.x != r.origin.x)
4491 ns_clear_frame_area (f, left, top, width, height);
4498 [bar setPosition: position portion: portion whole: whole];
4504 ns_condemn_scroll_bars (struct frame *f)
4505 /* --------------------------------------------------------------------------
4506 External (hook): arrange for all frame's scrollbars to be removed
4507 at next call to judge_scroll_bars, except for those redeemed.
4508 -------------------------------------------------------------------------- */
4512 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4514 NSTRACE ("ns_condemn_scroll_bars");
4516 for (i =[subviews count]-1; i >= 0; i--)
4518 view = [subviews objectAtIndex: i];
4519 if ([view isKindOfClass: [EmacsScroller class]])
4526 ns_redeem_scroll_bar (struct window *window)
4527 /* --------------------------------------------------------------------------
4528 External (hook): arrange to spare this window's scrollbar
4529 at next call to judge_scroll_bars.
4530 -------------------------------------------------------------------------- */
4533 NSTRACE ("ns_redeem_scroll_bar");
4534 if (!NILP (window->vertical_scroll_bar))
4536 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4540 if (!NILP (window->horizontal_scroll_bar))
4542 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4549 ns_judge_scroll_bars (struct frame *f)
4550 /* --------------------------------------------------------------------------
4551 External (hook): destroy all scrollbars on frame that weren't
4552 redeemed after call to condemn_scroll_bars.
4553 -------------------------------------------------------------------------- */
4557 EmacsView *eview = FRAME_NS_VIEW (f);
4558 NSArray *subviews = [[eview superview] subviews];
4561 NSTRACE ("ns_judge_scroll_bars");
4562 for (i = [subviews count]-1; i >= 0; --i)
4564 view = [subviews objectAtIndex: i];
4565 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4571 [eview updateFrameSize: NO];
4574 /* ==========================================================================
4578 ========================================================================== */
4581 x_display_pixel_height (struct ns_display_info *dpyinfo)
4583 NSArray *screens = [NSScreen screens];
4584 NSEnumerator *enumerator = [screens objectEnumerator];
4589 while ((screen = [enumerator nextObject]) != nil)
4590 frame = NSUnionRect (frame, [screen frame]);
4592 return NSHeight (frame);
4596 x_display_pixel_width (struct ns_display_info *dpyinfo)
4598 NSArray *screens = [NSScreen screens];
4599 NSEnumerator *enumerator = [screens objectEnumerator];
4604 while ((screen = [enumerator nextObject]) != nil)
4605 frame = NSUnionRect (frame, [screen frame]);
4607 return NSWidth (frame);
4611 static Lisp_Object ns_string_to_lispmod (const char *s)
4612 /* --------------------------------------------------------------------------
4613 Convert modifier name to lisp symbol
4614 -------------------------------------------------------------------------- */
4616 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4618 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4620 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4622 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4624 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4626 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4634 ns_default (const char *parameter, Lisp_Object *result,
4635 Lisp_Object yesval, Lisp_Object noval,
4636 BOOL is_float, BOOL is_modstring)
4637 /* --------------------------------------------------------------------------
4638 Check a parameter value in user's preferences
4639 -------------------------------------------------------------------------- */
4641 const char *value = ns_get_defaults_value (parameter);
4647 if (c_strcasecmp (value, "YES") == 0)
4649 else if (c_strcasecmp (value, "NO") == 0)
4651 else if (is_float && (f = strtod (value, &pos), pos != value))
4652 *result = make_float (f);
4653 else if (is_modstring && value)
4654 *result = ns_string_to_lispmod (value);
4655 else fprintf (stderr,
4656 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4662 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4663 /* --------------------------------------------------------------------------
4664 Initialize global info and storage for display.
4665 -------------------------------------------------------------------------- */
4667 NSScreen *screen = [NSScreen mainScreen];
4668 NSWindowDepth depth = [screen depth];
4670 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4671 dpyinfo->resy = 72.27;
4672 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4673 NSColorSpaceFromDepth (depth)]
4674 && ![NSCalibratedWhiteColorSpace isEqualToString:
4675 NSColorSpaceFromDepth (depth)];
4676 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4677 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4678 dpyinfo->color_table->colors = NULL;
4679 dpyinfo->root_window = 42; /* a placeholder.. */
4680 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4681 dpyinfo->n_fonts = 0;
4682 dpyinfo->smallest_font_height = 1;
4683 dpyinfo->smallest_char_width = 1;
4685 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4689 /* This and next define (many of the) public functions in this file. */
4690 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4691 with using despite presence in the "system dependent" redisplay
4692 interface. In addition, many of the ns_ methods have code that is
4693 shared with all terms, indicating need for further refactoring. */
4694 extern frame_parm_handler ns_frame_parm_handlers[];
4695 static struct redisplay_interface ns_redisplay_interface =
4697 ns_frame_parm_handlers,
4701 x_clear_end_of_line,
4703 ns_after_update_window_line,
4704 ns_update_window_begin,
4705 ns_update_window_end,
4706 0, /* flush_display */
4707 x_clear_window_mouse_face,
4708 x_get_glyph_overhangs,
4709 x_fix_overlapping_area,
4710 ns_draw_fringe_bitmap,
4711 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4712 0, /* destroy_fringe_bitmap */
4713 ns_compute_glyph_string_overhangs,
4714 ns_draw_glyph_string,
4715 ns_define_frame_cursor,
4716 ns_clear_frame_area,
4717 ns_draw_window_cursor,
4718 ns_draw_vertical_window_border,
4719 ns_draw_window_divider,
4720 ns_shift_glyphs_for_insert,
4727 ns_delete_display (struct ns_display_info *dpyinfo)
4733 /* This function is called when the last frame on a display is deleted. */
4735 ns_delete_terminal (struct terminal *terminal)
4737 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4739 NSTRACE ("ns_delete_terminal");
4741 /* Protect against recursive calls. delete_frame in
4742 delete_terminal calls us back when it deletes our last frame. */
4743 if (!terminal->name)
4748 x_destroy_all_bitmaps (dpyinfo);
4749 ns_delete_display (dpyinfo);
4754 static struct terminal *
4755 ns_create_terminal (struct ns_display_info *dpyinfo)
4756 /* --------------------------------------------------------------------------
4757 Set up use of NS before we make the first connection.
4758 -------------------------------------------------------------------------- */
4760 struct terminal *terminal;
4762 NSTRACE ("ns_create_terminal");
4764 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4766 terminal->display_info.ns = dpyinfo;
4767 dpyinfo->terminal = terminal;
4769 terminal->clear_frame_hook = ns_clear_frame;
4770 terminal->ring_bell_hook = ns_ring_bell;
4771 terminal->update_begin_hook = ns_update_begin;
4772 terminal->update_end_hook = ns_update_end;
4773 terminal->read_socket_hook = ns_read_socket;
4774 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4775 terminal->mouse_position_hook = ns_mouse_position;
4776 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4777 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4778 terminal->fullscreen_hook = ns_fullscreen_hook;
4779 terminal->menu_show_hook = ns_menu_show;
4780 terminal->popup_dialog_hook = ns_popup_dialog;
4781 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4782 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4783 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4784 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4785 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4786 terminal->delete_frame_hook = x_destroy_window;
4787 terminal->delete_terminal_hook = ns_delete_terminal;
4788 /* Other hooks are NULL by default. */
4794 struct ns_display_info *
4795 ns_term_init (Lisp_Object display_name)
4796 /* --------------------------------------------------------------------------
4797 Start the Application and get things rolling.
4798 -------------------------------------------------------------------------- */
4800 struct terminal *terminal;
4801 struct ns_display_info *dpyinfo;
4802 static int ns_initialized = 0;
4805 if (ns_initialized) return x_display_list;
4810 NSTRACE ("ns_term_init");
4812 [outerpool release];
4813 outerpool = [[NSAutoreleasePool alloc] init];
4815 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4816 /*GSDebugAllocationActive (YES); */
4820 Fset_input_interrupt_mode (Qnil);
4822 if (selfds[0] == -1)
4824 if (emacs_pipe (selfds) != 0)
4826 fprintf (stderr, "Failed to create pipe: %s\n",
4827 emacs_strerror (errno));
4831 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4832 FD_ZERO (&select_readfds);
4833 FD_ZERO (&select_writefds);
4834 pthread_mutex_init (&select_mutex, NULL);
4837 ns_pending_files = [[NSMutableArray alloc] init];
4838 ns_pending_service_names = [[NSMutableArray alloc] init];
4839 ns_pending_service_args = [[NSMutableArray alloc] init];
4841 /* Start app and create the main menu, window, view.
4842 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4843 The view will then ask the NSApp to stop and return to Emacs. */
4844 [EmacsApp sharedApplication];
4847 [NSApp setDelegate: NSApp];
4849 /* Start the select thread. */
4850 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4854 /* debugging: log all notifications */
4855 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4856 selector: @selector (logNotification:)
4857 name: nil object: nil]; */
4859 dpyinfo = xzalloc (sizeof *dpyinfo);
4861 ns_initialize_display_info (dpyinfo);
4862 terminal = ns_create_terminal (dpyinfo);
4864 terminal->kboard = allocate_kboard (Qns);
4865 /* Don't let the initial kboard remain current longer than necessary.
4866 That would cause problems if a file loaded on startup tries to
4867 prompt in the mini-buffer. */
4868 if (current_kboard == initial_kboard)
4869 current_kboard = terminal->kboard;
4870 terminal->kboard->reference_count++;
4872 dpyinfo->next = x_display_list;
4873 x_display_list = dpyinfo;
4875 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4877 terminal->name = xlispstrdup (display_name);
4881 if (!inhibit_x_resources)
4883 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4886 /* this is a standard variable */
4887 ns_default ("AppleAntiAliasingThreshold", &tmp,
4888 make_float (10.0), make_float (6.0), YES, NO);
4889 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4892 NSTRACE_MSG ("Colors");
4895 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4899 Lisp_Object color_file, color_map, color;
4903 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4904 Fsymbol_value (intern ("data-directory")));
4906 color_map = Fx_load_color_file (color_file);
4907 if (NILP (color_map))
4908 fatal ("Could not read %s.\n", SDATA (color_file));
4910 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4911 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4913 color = XCAR (color_map);
4914 name = SSDATA (XCAR (color));
4915 c = XINT (XCDR (color));
4917 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4918 green: GREEN_FROM_ULONG (c) / 255.0
4919 blue: BLUE_FROM_ULONG (c) / 255.0
4921 forKey: [NSString stringWithUTF8String: name]];
4923 [cl writeToFile: nil];
4927 NSTRACE_MSG ("Versions");
4930 #ifdef NS_IMPL_GNUSTEP
4931 Vwindow_system_version = build_string (gnustep_base_version);
4933 /*PSnextrelease (128, c); */
4934 char c[DBL_BUFSIZE_BOUND];
4935 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4936 Vwindow_system_version = make_unibyte_string (c, len);
4940 delete_keyboard_wait_descriptor (0);
4942 ns_app_name = [[NSProcessInfo processInfo] processName];
4944 /* Set up OS X app menu */
4946 NSTRACE_MSG ("Menu init");
4948 #ifdef NS_IMPL_COCOA
4952 /* set up the application menu */
4953 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4954 [svcsMenu setAutoenablesItems: NO];
4955 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4956 [appMenu setAutoenablesItems: NO];
4957 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4958 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4960 [appMenu insertItemWithTitle: @"About Emacs"
4961 action: @selector (orderFrontStandardAboutPanel:)
4964 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4965 [appMenu insertItemWithTitle: @"Preferences..."
4966 action: @selector (showPreferencesWindow:)
4969 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4970 item = [appMenu insertItemWithTitle: @"Services"
4971 action: @selector (menuDown:)
4974 [appMenu setSubmenu: svcsMenu forItem: item];
4975 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4976 [appMenu insertItemWithTitle: @"Hide Emacs"
4977 action: @selector (hide:)
4980 item = [appMenu insertItemWithTitle: @"Hide Others"
4981 action: @selector (hideOtherApplications:)
4984 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4985 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4986 [appMenu insertItemWithTitle: @"Quit Emacs"
4987 action: @selector (terminate:)
4991 item = [mainMenu insertItemWithTitle: ns_app_name
4992 action: @selector (menuDown:)
4995 [mainMenu setSubmenu: appMenu forItem: item];
4996 [dockMenu insertItemWithTitle: @"New Frame"
4997 action: @selector (newFrame:)
5001 [NSApp setMainMenu: mainMenu];
5002 [NSApp setAppleMenu: appMenu];
5003 [NSApp setServicesMenu: svcsMenu];
5004 /* Needed at least on Cocoa, to get dock menu to show windows */
5005 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5007 [[NSNotificationCenter defaultCenter]
5008 addObserver: mainMenu
5009 selector: @selector (trackingNotification:)
5010 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5011 [[NSNotificationCenter defaultCenter]
5012 addObserver: mainMenu
5013 selector: @selector (trackingNotification:)
5014 name: NSMenuDidEndTrackingNotification object: mainMenu];
5016 #endif /* MAC OS X menu setup */
5018 /* Register our external input/output types, used for determining
5019 applicable services and also drag/drop eligibility. */
5021 NSTRACE_MSG ("Input/output types");
5023 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5024 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5026 ns_drag_types = [[NSArray arrayWithObjects:
5028 NSTabularTextPboardType,
5029 NSFilenamesPboardType,
5030 NSURLPboardType, nil] retain];
5032 /* If fullscreen is in init/default-frame-alist, focus isn't set
5033 right for fullscreen windows, so set this. */
5034 [NSApp activateIgnoringOtherApps:YES];
5036 NSTRACE_MSG ("Call NSApp run");
5039 ns_do_open_file = YES;
5041 #ifdef NS_IMPL_GNUSTEP
5042 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5043 We must re-catch it so subprocess works. */
5044 catch_child_signal ();
5047 NSTRACE_MSG ("ns_term_init done");
5056 ns_term_shutdown (int sig)
5058 [[NSUserDefaults standardUserDefaults] synchronize];
5060 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5061 if (STRINGP (Vauto_save_list_file_name))
5062 unlink (SSDATA (Vauto_save_list_file_name));
5064 if (sig == 0 || sig == SIGTERM)
5066 [NSApp terminate: NSApp];
5068 else // force a stack trace to happen
5075 /* ==========================================================================
5077 EmacsApp implementation
5079 ========================================================================== */
5082 @implementation EmacsApp
5086 NSTRACE ("[EmacsApp init]");
5088 if ((self = [super init]))
5090 #ifdef NS_IMPL_COCOA
5091 self->isFirst = YES;
5093 #ifdef NS_IMPL_GNUSTEP
5094 self->applicationDidFinishLaunchingCalled = NO;
5101 #ifdef NS_IMPL_COCOA
5104 NSTRACE ("[EmacsApp run]");
5106 #ifndef NSAppKitVersionNumber10_9
5107 #define NSAppKitVersionNumber10_9 1265
5110 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5116 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5118 if (isFirst) [self finishLaunching];
5121 shouldKeepRunning = YES;
5125 pool = [[NSAutoreleasePool alloc] init];
5128 [self nextEventMatchingMask:NSAnyEventMask
5129 untilDate:[NSDate distantFuture]
5130 inMode:NSDefaultRunLoopMode
5133 [self sendEvent:event];
5134 [self updateWindows];
5135 } while (shouldKeepRunning);
5140 - (void)stop: (id)sender
5142 NSTRACE ("[EmacsApp stop:]");
5144 shouldKeepRunning = NO;
5145 // Stop possible dialog also. Noop if no dialog present.
5146 // The file dialog still leaks 7k - 10k on 10.9 though.
5147 [super stop:sender];
5149 #endif /* NS_IMPL_COCOA */
5151 - (void)logNotification: (NSNotification *)notification
5153 NSTRACE ("[EmacsApp logNotification:]");
5155 const char *name = [[notification name] UTF8String];
5156 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5157 && !strstr (name, "WindowNumber"))
5158 NSLog (@"notification: '%@'", [notification name]);
5162 - (void)sendEvent: (NSEvent *)theEvent
5163 /* --------------------------------------------------------------------------
5164 Called when NSApp is running for each event received. Used to stop
5165 the loop when we choose, since there's no way to just run one iteration.
5166 -------------------------------------------------------------------------- */
5168 int type = [theEvent type];
5169 NSWindow *window = [theEvent window];
5171 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5172 NSTRACE_MSG ("Type: %d", type);
5174 #ifdef NS_IMPL_GNUSTEP
5175 // Keyboard events aren't propagated to file dialogs for some reason.
5176 if ([NSApp modalWindow] != nil &&
5177 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5179 [[NSApp modalWindow] sendEvent: theEvent];
5184 if (represented_filename != nil && represented_frame)
5186 NSString *fstr = represented_filename;
5187 NSView *view = FRAME_NS_VIEW (represented_frame);
5188 #ifdef NS_IMPL_COCOA
5189 /* work around a bug observed on 10.3 and later where
5190 setTitleWithRepresentedFilename does not clear out previous state
5191 if given filename does not exist */
5192 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5193 [[view window] setRepresentedFilename: @""];
5195 [[view window] setRepresentedFilename: fstr];
5196 [represented_filename release];
5197 represented_filename = nil;
5198 represented_frame = NULL;
5201 if (type == NSApplicationDefined)
5203 switch ([theEvent data2])
5205 #ifdef NS_IMPL_COCOA
5206 case NSAPP_DATA2_RUNASSCRIPT:
5211 case NSAPP_DATA2_RUNFILEDIALOG:
5212 ns_run_file_dialog ();
5218 if (type == NSCursorUpdate && window == nil)
5220 fprintf (stderr, "Dropping external cursor update event.\n");
5224 if (type == NSApplicationDefined)
5226 /* Events posted by ns_send_appdefined interrupt the run loop here.
5227 But, if a modal window is up, an appdefined can still come through,
5228 (e.g., from a makeKeyWindow event) but stopping self also stops the
5229 modal loop. Just defer it until later. */
5230 if ([NSApp modalWindow] == nil)
5232 last_appdefined_event_data = [theEvent data1];
5237 send_appdefined = YES;
5242 #ifdef NS_IMPL_COCOA
5243 /* If no dialog and none of our frames have focus and it is a move, skip it.
5244 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5245 such as Wifi, sound, date or similar.
5246 This prevents "spooky" highlighting in the frame under the menu. */
5247 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5249 struct ns_display_info *di;
5250 BOOL has_focus = NO;
5251 for (di = x_display_list; ! has_focus && di; di = di->next)
5252 has_focus = di->x_focus_frame != 0;
5258 NSTRACE_UNSILENCE();
5260 [super sendEvent: theEvent];
5264 - (void)showPreferencesWindow: (id)sender
5266 struct frame *emacsframe = SELECTED_FRAME ();
5267 NSEvent *theEvent = [NSApp currentEvent];
5271 emacs_event->kind = NS_NONKEY_EVENT;
5272 emacs_event->code = KEY_NS_SHOW_PREFS;
5273 emacs_event->modifiers = 0;
5274 EV_TRAILER (theEvent);
5278 - (void)newFrame: (id)sender
5280 NSTRACE ("[EmacsApp newFrame:]");
5282 struct frame *emacsframe = SELECTED_FRAME ();
5283 NSEvent *theEvent = [NSApp currentEvent];
5287 emacs_event->kind = NS_NONKEY_EVENT;
5288 emacs_event->code = KEY_NS_NEW_FRAME;
5289 emacs_event->modifiers = 0;
5290 EV_TRAILER (theEvent);
5294 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5295 - (BOOL) openFile: (NSString *)fileName
5297 NSTRACE ("[EmacsApp openFile:]");
5299 struct frame *emacsframe = SELECTED_FRAME ();
5300 NSEvent *theEvent = [NSApp currentEvent];
5305 emacs_event->kind = NS_NONKEY_EVENT;
5306 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5307 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5308 ns_input_line = Qnil; /* can be start or cons start,end */
5309 emacs_event->modifiers =0;
5310 EV_TRAILER (theEvent);
5316 /* **************************************************************************
5318 EmacsApp delegate implementation
5320 ************************************************************************** */
5322 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5323 /* --------------------------------------------------------------------------
5324 When application is loaded, terminate event loop in ns_term_init
5325 -------------------------------------------------------------------------- */
5327 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5329 #ifdef NS_IMPL_GNUSTEP
5330 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5332 [NSApp setServicesProvider: NSApp];
5334 [self antialiasThresholdDidChange:nil];
5335 #ifdef NS_IMPL_COCOA
5336 [[NSNotificationCenter defaultCenter]
5338 selector:@selector(antialiasThresholdDidChange:)
5339 name:NSAntialiasThresholdChangedNotification
5343 ns_send_appdefined (-2);
5346 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5348 #ifdef NS_IMPL_COCOA
5349 macfont_update_antialias_threshold ();
5354 /* Termination sequences:
5357 MenuBar | File | Exit:
5358 Select Quit from App menubar:
5360 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5363 Select Quit from Dock menu:
5366 Cancel -> Nothing else
5370 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5375 - (void) terminate: (id)sender
5377 NSTRACE ("[EmacsApp terminate:]");
5379 struct frame *emacsframe = SELECTED_FRAME ();
5384 emacs_event->kind = NS_NONKEY_EVENT;
5385 emacs_event->code = KEY_NS_POWER_OFF;
5386 emacs_event->arg = Qt; /* mark as non-key event */
5387 EV_TRAILER ((id)nil);
5391 runAlertPanel(NSString *title,
5392 NSString *msgFormat,
5393 NSString *defaultButton,
5394 NSString *alternateButton)
5396 #if !defined (NS_IMPL_COCOA) || \
5397 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5398 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5399 == NSAlertDefaultReturn;
5401 NSAlert *alert = [[NSAlert alloc] init];
5402 [alert setAlertStyle: NSCriticalAlertStyle];
5403 [alert setMessageText: msgFormat];
5404 [alert addButtonWithTitle: defaultButton];
5405 [alert addButtonWithTitle: alternateButton];
5406 NSInteger ret = [alert runModal];
5408 return ret == NSAlertFirstButtonReturn;
5413 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5415 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5419 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5420 return NSTerminateNow;
5422 ret = runAlertPanel(ns_app_name,
5423 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5424 @"Save Buffers and Exit", @"Cancel");
5427 return NSTerminateNow;
5429 return NSTerminateCancel;
5430 return NSTerminateNow; /* just in case */
5434 not_in_argv (NSString *arg)
5437 const char *a = [arg UTF8String];
5438 for (k = 1; k < initial_argc; ++k)
5439 if (strcmp (a, initial_argv[k]) == 0) return 0;
5443 /* Notification from the Workspace to open a file */
5444 - (BOOL)application: sender openFile: (NSString *)file
5446 if (ns_do_open_file || not_in_argv (file))
5447 [ns_pending_files addObject: file];
5452 /* Open a file as a temporary file */
5453 - (BOOL)application: sender openTempFile: (NSString *)file
5455 if (ns_do_open_file || not_in_argv (file))
5456 [ns_pending_files addObject: file];
5461 /* Notification from the Workspace to open a file noninteractively (?) */
5462 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5464 if (ns_do_open_file || not_in_argv (file))
5465 [ns_pending_files addObject: file];
5469 /* Notification from the Workspace to open multiple files */
5470 - (void)application: sender openFiles: (NSArray *)fileList
5472 NSEnumerator *files = [fileList objectEnumerator];
5474 /* Don't open files from the command line unconditionally,
5475 Cocoa parses the command line wrong, --option value tries to open value
5476 if --option is the last option. */
5477 while ((file = [files nextObject]) != nil)
5478 if (ns_do_open_file || not_in_argv (file))
5479 [ns_pending_files addObject: file];
5481 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5486 /* Handle dock menu requests. */
5487 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5493 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5494 - (void)applicationWillBecomeActive: (NSNotification *)notification
5496 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5497 //ns_app_active=YES;
5500 - (void)applicationDidBecomeActive: (NSNotification *)notification
5502 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5504 #ifdef NS_IMPL_GNUSTEP
5505 if (! applicationDidFinishLaunchingCalled)
5506 [self applicationDidFinishLaunching:notification];
5508 //ns_app_active=YES;
5510 ns_update_auto_hide_menu_bar ();
5511 // No constraining takes place when the application is not active.
5512 ns_constrain_all_frames ();
5514 - (void)applicationDidResignActive: (NSNotification *)notification
5516 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5519 ns_send_appdefined (-1);
5524 /* ==========================================================================
5526 EmacsApp aux handlers for managing event loop
5528 ========================================================================== */
5531 - (void)timeout_handler: (NSTimer *)timedEntry
5532 /* --------------------------------------------------------------------------
5533 The timeout specified to ns_select has passed.
5534 -------------------------------------------------------------------------- */
5536 /*NSTRACE ("timeout_handler"); */
5537 ns_send_appdefined (-2);
5540 #ifdef NS_IMPL_GNUSTEP
5541 - (void)sendFromMainThread:(id)unused
5543 ns_send_appdefined (nextappdefined);
5547 - (void)fd_handler:(id)unused
5548 /* --------------------------------------------------------------------------
5549 Check data waiting on file descriptors and terminate if so
5550 -------------------------------------------------------------------------- */
5553 int waiting = 1, nfds;
5556 fd_set readfds, writefds, *wfds;
5557 struct timespec timeout, *tmo;
5558 NSAutoreleasePool *pool = nil;
5560 /* NSTRACE ("fd_handler"); */
5565 pool = [[NSAutoreleasePool alloc] init];
5571 FD_SET (selfds[0], &fds);
5572 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5573 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5578 pthread_mutex_lock (&select_mutex);
5581 if (select_valid & SELECT_HAVE_READ)
5582 readfds = select_readfds;
5586 if (select_valid & SELECT_HAVE_WRITE)
5588 writefds = select_writefds;
5593 if (select_valid & SELECT_HAVE_TMO)
5595 timeout = select_timeout;
5601 pthread_mutex_unlock (&select_mutex);
5603 FD_SET (selfds[0], &readfds);
5604 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5606 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5609 ns_send_appdefined (-2);
5610 else if (result > 0)
5612 if (FD_ISSET (selfds[0], &readfds))
5614 if (read (selfds[0], &c, 1) == 1 && c == 's')
5619 pthread_mutex_lock (&select_mutex);
5620 if (select_valid & SELECT_HAVE_READ)
5621 select_readfds = readfds;
5622 if (select_valid & SELECT_HAVE_WRITE)
5623 select_writefds = writefds;
5624 if (select_valid & SELECT_HAVE_TMO)
5625 select_timeout = timeout;
5626 pthread_mutex_unlock (&select_mutex);
5628 ns_send_appdefined (result);
5638 /* ==========================================================================
5642 ========================================================================== */
5644 /* called from system: queue for next pass through event loop */
5645 - (void)requestService: (NSPasteboard *)pboard
5646 userData: (NSString *)userData
5647 error: (NSString **)error
5649 [ns_pending_service_names addObject: userData];
5650 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5651 SSDATA (ns_string_from_pasteboard (pboard))]];
5655 /* called from ns_read_socket to clear queue */
5656 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5658 struct frame *emacsframe = SELECTED_FRAME ();
5659 NSEvent *theEvent = [NSApp currentEvent];
5661 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5666 emacs_event->kind = NS_NONKEY_EVENT;
5667 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5668 ns_input_spi_name = build_string ([name UTF8String]);
5669 ns_input_spi_arg = build_string ([arg UTF8String]);
5670 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5671 EV_TRAILER (theEvent);
5681 /* ==========================================================================
5683 EmacsView implementation
5685 ========================================================================== */
5688 @implementation EmacsView
5690 /* needed to inform when window closed from LISP */
5691 - (void) setWindowClosing: (BOOL)closing
5693 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5695 windowClosing = closing;
5701 NSTRACE ("[EmacsView dealloc]");
5703 if (fs_state == FULLSCREEN_BOTH)
5704 [nonfs_window release];
5709 /* called on font panel selection */
5710 - (void)changeFont: (id)sender
5712 NSEvent *e = [[self window] currentEvent];
5713 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5714 struct font *font = face->font;
5719 NSTRACE ("[EmacsView changeFont:]");
5724 #ifdef NS_IMPL_GNUSTEP
5725 nsfont = ((struct nsfont_info *)font)->nsfont;
5727 #ifdef NS_IMPL_COCOA
5728 nsfont = (NSFont *) macfont_get_nsctfont (font);
5731 if ((newFont = [sender convertFont: nsfont]))
5733 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5735 emacs_event->kind = NS_NONKEY_EVENT;
5736 emacs_event->modifiers = 0;
5737 emacs_event->code = KEY_NS_CHANGE_FONT;
5739 size = [newFont pointSize];
5740 ns_input_fontsize = make_number (lrint (size));
5741 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5747 - (BOOL)acceptsFirstResponder
5749 NSTRACE ("[EmacsView acceptsFirstResponder]");
5754 - (void)resetCursorRects
5756 NSRect visible = [self visibleRect];
5757 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5758 NSTRACE ("[EmacsView resetCursorRects]");
5760 if (currentCursor == nil)
5761 currentCursor = [NSCursor arrowCursor];
5763 if (!NSIsEmptyRect (visible))
5764 [self addCursorRect: visible cursor: currentCursor];
5765 [currentCursor setOnMouseEntered: YES];
5770 /*****************************************************************************/
5771 /* Keyboard handling. */
5774 - (void)keyDown: (NSEvent *)theEvent
5776 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5778 unsigned fnKeysym = 0;
5779 static NSMutableArray *nsEvArray;
5781 unsigned int flags = [theEvent modifierFlags];
5783 NSTRACE ("[EmacsView keyDown:]");
5785 /* Rhapsody and OS X give up and down events for the arrow keys */
5786 if (ns_fake_keydown == YES)
5787 ns_fake_keydown = NO;
5788 else if ([theEvent type] != NSKeyDown)
5794 if (![[self window] isKeyWindow]
5795 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5796 /* we must avoid an infinite loop here. */
5797 && (EmacsView *)[[theEvent window] delegate] != self)
5799 /* XXX: There is an occasional condition in which, when Emacs display
5800 updates a different frame from the current one, and temporarily
5801 selects it, then processes some interrupt-driven input
5802 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5803 for some reason that window has its first responder set to the NSView
5804 most recently updated (I guess), which is not the correct one. */
5805 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5809 if (nsEvArray == nil)
5810 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5812 [NSCursor setHiddenUntilMouseMoves: YES];
5814 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5816 clear_mouse_face (hlinfo);
5817 hlinfo->mouse_face_hidden = 1;
5820 if (!processingCompose)
5822 /* When using screen sharing, no left or right information is sent,
5823 so use Left key in those cases. */
5824 int is_left_key, is_right_key;
5826 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5827 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5829 /* (Carbon way: [theEvent keyCode]) */
5831 /* is it a "function key"? */
5832 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5833 flag set (this is probably a bug in the OS).
5835 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5837 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5841 fnKeysym = ns_convert_key (code);
5846 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5847 because Emacs treats Delete and KP-Delete same (in simple.el). */
5848 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5849 #ifdef NS_IMPL_GNUSTEP
5850 /* GNUstep uses incompatible keycodes, even for those that are
5851 supposed to be hardware independent. Just check for delete.
5852 Keypad delete does not have keysym 0xFFFF.
5853 See http://savannah.gnu.org/bugs/?25395
5855 || (fnKeysym == 0xFFFF && code == 127)
5858 code = 0xFF08; /* backspace */
5863 /* are there modifiers? */
5864 emacs_event->modifiers = 0;
5866 if (flags & NSHelpKeyMask)
5867 emacs_event->modifiers |= hyper_modifier;
5869 if (flags & NSShiftKeyMask)
5870 emacs_event->modifiers |= shift_modifier;
5872 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5873 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5874 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5877 emacs_event->modifiers |= parse_solitary_modifier
5878 (EQ (ns_right_command_modifier, Qleft)
5879 ? ns_command_modifier
5880 : ns_right_command_modifier);
5884 emacs_event->modifiers |= parse_solitary_modifier
5885 (ns_command_modifier);
5887 /* if super (default), take input manager's word so things like
5888 dvorak / qwerty layout work */
5889 if (EQ (ns_command_modifier, Qsuper)
5891 && [[theEvent characters] length] != 0)
5893 /* XXX: the code we get will be unshifted, so if we have
5894 a shift modifier, must convert ourselves */
5895 if (!(flags & NSShiftKeyMask))
5896 code = [[theEvent characters] characterAtIndex: 0];
5898 /* this is ugly and also requires linking w/Carbon framework
5899 (for LMGetKbdType) so for now leave this rare (?) case
5900 undealt with.. in future look into CGEvent methods */
5903 long smv = GetScriptManagerVariable (smKeyScript);
5904 Handle uchrHandle = GetResource
5905 ('uchr', GetScriptVariable (smv, smScriptKeys));
5907 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5908 [[theEvent characters] characterAtIndex: 0],
5909 kUCKeyActionDisplay,
5910 (flags & ~NSCommandKeyMask) >> 8,
5911 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5912 &dummy, 1, &dummy, &code);
5919 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5920 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5921 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5924 emacs_event->modifiers |= parse_solitary_modifier
5925 (EQ (ns_right_control_modifier, Qleft)
5926 ? ns_control_modifier
5927 : ns_right_control_modifier);
5930 emacs_event->modifiers |= parse_solitary_modifier
5931 (ns_control_modifier);
5933 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5934 emacs_event->modifiers |=
5935 parse_solitary_modifier (ns_function_modifier);
5937 left_is_none = NILP (ns_alternate_modifier)
5938 || EQ (ns_alternate_modifier, Qnone);
5940 is_right_key = (flags & NSRightAlternateKeyMask)
5941 == NSRightAlternateKeyMask;
5942 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5944 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5948 if ((NILP (ns_right_alternate_modifier)
5949 || EQ (ns_right_alternate_modifier, Qnone)
5950 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5952 { /* accept pre-interp alt comb */
5953 if ([[theEvent characters] length] > 0)
5954 code = [[theEvent characters] characterAtIndex: 0];
5955 /*HACK: clear lone shift modifier to stop next if from firing */
5956 if (emacs_event->modifiers == shift_modifier)
5957 emacs_event->modifiers = 0;
5960 emacs_event->modifiers |= parse_solitary_modifier
5961 (EQ (ns_right_alternate_modifier, Qleft)
5962 ? ns_alternate_modifier
5963 : ns_right_alternate_modifier);
5966 if (is_left_key) /* default = meta */
5968 if (left_is_none && !fnKeysym)
5969 { /* accept pre-interp alt comb */
5970 if ([[theEvent characters] length] > 0)
5971 code = [[theEvent characters] characterAtIndex: 0];
5972 /*HACK: clear lone shift modifier to stop next if from firing */
5973 if (emacs_event->modifiers == shift_modifier)
5974 emacs_event->modifiers = 0;
5977 emacs_event->modifiers |=
5978 parse_solitary_modifier (ns_alternate_modifier);
5982 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5983 code, fnKeysym, flags, emacs_event->modifiers);
5985 /* if it was a function key or had modifiers, pass it directly to emacs */
5986 if (fnKeysym || (emacs_event->modifiers
5987 && (emacs_event->modifiers != shift_modifier)
5988 && [[theEvent charactersIgnoringModifiers] length] > 0))
5989 /*[[theEvent characters] length] */
5991 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5993 code |= (1<<28)|(3<<16);
5994 else if (code == 0x7f)
5995 code |= (1<<28)|(3<<16);
5997 emacs_event->kind = code > 0xFF
5998 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6000 emacs_event->code = code;
6001 EV_TRAILER (theEvent);
6002 processingCompose = NO;
6008 if (NS_KEYLOG && !processingCompose)
6009 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6011 processingCompose = YES;
6012 [nsEvArray addObject: theEvent];
6013 [self interpretKeyEvents: nsEvArray];
6014 [nsEvArray removeObject: theEvent];
6018 #ifdef NS_IMPL_COCOA
6019 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
6020 decided not to send key-down for.
6021 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
6022 This only applies on Tiger and earlier.
6023 If it matches one of these, send it on to keyDown. */
6024 -(void)keyUp: (NSEvent *)theEvent
6026 int flags = [theEvent modifierFlags];
6027 int code = [theEvent keyCode];
6029 NSTRACE ("[EmacsView keyUp:]");
6031 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
6032 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
6035 fprintf (stderr, "keyUp: passed test");
6036 ns_fake_keydown = YES;
6037 [self keyDown: theEvent];
6043 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6046 /* <NSTextInput>: called when done composing;
6047 NOTE: also called when we delete over working text, followed immed.
6048 by doCommandBySelector: deleteBackward: */
6049 - (void)insertText: (id)aString
6052 int len = [(NSString *)aString length];
6055 NSTRACE ("[EmacsView insertText:]");
6058 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6059 processingCompose = NO;
6064 /* first, clear any working text */
6065 if (workingText != nil)
6066 [self deleteWorkingText];
6068 /* now insert the string as keystrokes */
6069 for (i =0; i<len; i++)
6071 code = [aString characterAtIndex: i];
6072 /* TODO: still need this? */
6074 code = '~'; /* 0x7E */
6075 if (code != 32) /* Space */
6076 emacs_event->modifiers = 0;
6078 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6079 emacs_event->code = code;
6080 EV_TRAILER ((id)nil);
6085 /* <NSTextInput>: inserts display of composing characters */
6086 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6088 NSString *str = [aString respondsToSelector: @selector (string)] ?
6089 [aString string] : aString;
6091 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6094 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6095 str, (unsigned long)[str length],
6096 (unsigned long)selRange.length,
6097 (unsigned long)selRange.location);
6099 if (workingText != nil)
6100 [self deleteWorkingText];
6101 if ([str length] == 0)
6107 processingCompose = YES;
6108 workingText = [str copy];
6109 ns_working_text = build_string ([workingText UTF8String]);
6111 emacs_event->kind = NS_TEXT_EVENT;
6112 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6113 EV_TRAILER ((id)nil);
6117 /* delete display of composing characters [not in <NSTextInput>] */
6118 - (void)deleteWorkingText
6120 NSTRACE ("[EmacsView deleteWorkingText]");
6122 if (workingText == nil)
6125 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6126 [workingText release];
6128 processingCompose = NO;
6133 emacs_event->kind = NS_TEXT_EVENT;
6134 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6135 EV_TRAILER ((id)nil);
6139 - (BOOL)hasMarkedText
6141 NSTRACE ("[EmacsView hasMarkedText]");
6143 return workingText != nil;
6147 - (NSRange)markedRange
6149 NSTRACE ("[EmacsView markedRange]");
6151 NSRange rng = workingText != nil
6152 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6154 NSLog (@"markedRange request");
6161 NSTRACE ("[EmacsView unmarkText]");
6164 NSLog (@"unmark (accept) text");
6165 [self deleteWorkingText];
6166 processingCompose = NO;
6170 /* used to position char selection windows, etc. */
6171 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6175 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6177 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6180 NSLog (@"firstRectForCharRange request");
6182 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6183 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6184 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6185 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6186 +FRAME_LINE_HEIGHT (emacsframe));
6188 pt = [self convertPoint: pt toView: nil];
6189 pt = [[self window] convertBaseToScreen: pt];
6195 - (NSInteger)conversationIdentifier
6197 return (NSInteger)self;
6201 - (void)doCommandBySelector: (SEL)aSelector
6203 NSTRACE ("[EmacsView doCommandBySelector:]");
6206 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6208 processingCompose = NO;
6209 if (aSelector == @selector (deleteBackward:))
6211 /* happens when user backspaces over an ongoing composition:
6212 throw a 'delete' into the event queue */
6215 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6216 emacs_event->code = 0xFF08;
6217 EV_TRAILER ((id)nil);
6221 - (NSArray *)validAttributesForMarkedText
6223 static NSArray *arr = nil;
6224 if (arr == nil) arr = [NSArray new];
6225 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6229 - (NSRange)selectedRange
6232 NSLog (@"selectedRange request");
6233 return NSMakeRange (NSNotFound, 0);
6236 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6237 GNUSTEP_GUI_MINOR_VERSION > 22
6238 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6240 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6244 NSLog (@"characterIndexForPoint request");
6248 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6250 static NSAttributedString *str = nil;
6251 if (str == nil) str = [NSAttributedString new];
6253 NSLog (@"attributedSubstringFromRange request");
6257 /* End <NSTextInput> impl. */
6258 /*****************************************************************************/
6261 /* This is what happens when the user presses a mouse button. */
6262 - (void)mouseDown: (NSEvent *)theEvent
6264 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6265 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6267 NSTRACE ("[EmacsView mouseDown:]");
6269 [self deleteWorkingText];
6274 dpyinfo->last_mouse_frame = emacsframe;
6275 /* appears to be needed to prevent spurious movement events generated on
6277 emacsframe->mouse_moved = 0;
6279 if ([theEvent type] == NSScrollWheel)
6281 CGFloat delta = [theEvent deltaY];
6282 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6285 delta = [theEvent deltaX];
6288 NSTRACE_MSG ("deltaIsZero");
6291 emacs_event->kind = HORIZ_WHEEL_EVENT;
6294 emacs_event->kind = WHEEL_EVENT;
6296 emacs_event->code = 0;
6297 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6298 ((delta > 0) ? up_modifier : down_modifier);
6302 emacs_event->kind = MOUSE_CLICK_EVENT;
6303 emacs_event->code = EV_BUTTON (theEvent);
6304 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6305 | EV_UDMODIFIERS (theEvent);
6307 XSETINT (emacs_event->x, lrint (p.x));
6308 XSETINT (emacs_event->y, lrint (p.y));
6309 EV_TRAILER (theEvent);
6313 - (void)rightMouseDown: (NSEvent *)theEvent
6315 NSTRACE ("[EmacsView rightMouseDown:]");
6316 [self mouseDown: theEvent];
6320 - (void)otherMouseDown: (NSEvent *)theEvent
6322 NSTRACE ("[EmacsView otherMouseDown:]");
6323 [self mouseDown: theEvent];
6327 - (void)mouseUp: (NSEvent *)theEvent
6329 NSTRACE ("[EmacsView mouseUp:]");
6330 [self mouseDown: theEvent];
6334 - (void)rightMouseUp: (NSEvent *)theEvent
6336 NSTRACE ("[EmacsView rightMouseUp:]");
6337 [self mouseDown: theEvent];
6341 - (void)otherMouseUp: (NSEvent *)theEvent
6343 NSTRACE ("[EmacsView otherMouseUp:]");
6344 [self mouseDown: theEvent];
6348 - (void) scrollWheel: (NSEvent *)theEvent
6350 NSTRACE ("[EmacsView scrollWheel:]");
6351 [self mouseDown: theEvent];
6355 /* Tell emacs the mouse has moved. */
6356 - (void)mouseMoved: (NSEvent *)e
6358 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6359 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6363 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6365 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6366 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6367 dpyinfo->last_mouse_motion_x = pt.x;
6368 dpyinfo->last_mouse_motion_y = pt.y;
6370 /* update any mouse face */
6371 if (hlinfo->mouse_face_hidden)
6373 hlinfo->mouse_face_hidden = 0;
6374 clear_mouse_face (hlinfo);
6377 /* tooltip handling */
6378 previous_help_echo_string = help_echo_string;
6379 help_echo_string = Qnil;
6381 if (!NILP (Vmouse_autoselect_window))
6383 NSTRACE_MSG ("mouse_autoselect_window");
6384 static Lisp_Object last_mouse_window;
6386 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6388 if (WINDOWP (window)
6389 && !EQ (window, last_mouse_window)
6390 && !EQ (window, selected_window)
6391 && (focus_follows_mouse
6392 || (EQ (XWINDOW (window)->frame,
6393 XWINDOW (selected_window)->frame))))
6395 NSTRACE_MSG ("in_window");
6396 emacs_event->kind = SELECT_WINDOW_EVENT;
6397 emacs_event->frame_or_window = window;
6400 /* Remember the last window where we saw the mouse. */
6401 last_mouse_window = window;
6404 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6405 help_echo_string = previous_help_echo_string;
6407 XSETFRAME (frame, emacsframe);
6408 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6410 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6411 (note_mouse_highlight), which is called through the
6412 note_mouse_movement () call above */
6413 any_help_event_p = YES;
6414 gen_help_event (help_echo_string, frame, help_echo_window,
6415 help_echo_object, help_echo_pos);
6418 if (emacsframe->mouse_moved && send_appdefined)
6419 ns_send_appdefined (-1);
6423 - (void)mouseDragged: (NSEvent *)e
6425 NSTRACE ("[EmacsView mouseDragged:]");
6426 [self mouseMoved: e];
6430 - (void)rightMouseDragged: (NSEvent *)e
6432 NSTRACE ("[EmacsView rightMouseDragged:]");
6433 [self mouseMoved: e];
6437 - (void)otherMouseDragged: (NSEvent *)e
6439 NSTRACE ("[EmacsView otherMouseDragged:]");
6440 [self mouseMoved: e];
6444 - (BOOL)windowShouldClose: (id)sender
6446 NSEvent *e =[[self window] currentEvent];
6448 NSTRACE ("[EmacsView windowShouldClose:]");
6449 windowClosing = YES;
6452 emacs_event->kind = DELETE_WINDOW_EVENT;
6453 emacs_event->modifiers = 0;
6454 emacs_event->code = 0;
6456 /* Don't close this window, let this be done from lisp code. */
6460 - (void) updateFrameSize: (BOOL) delay;
6462 NSWindow *window = [self window];
6463 NSRect wr = [window frame];
6465 int oldc = cols, oldr = rows;
6466 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6467 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6470 NSTRACE ("[EmacsView updateFrameSize:]");
6471 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6472 NSTRACE_RECT ("Original frame", wr);
6473 NSTRACE_MSG ("Original columns: %d", cols);
6474 NSTRACE_MSG ("Original rows: %d", rows);
6476 if (! [self isFullscreen])
6478 #ifdef NS_IMPL_GNUSTEP
6479 // GNUstep does not always update the tool bar height. Force it.
6480 if (toolbar && [toolbar isVisible])
6481 update_frame_tool_bar (emacsframe);
6484 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6485 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6488 if (wait_for_tool_bar)
6490 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6492 NSTRACE_MSG ("Waiting for toolbar");
6495 wait_for_tool_bar = NO;
6498 neww = (int)wr.size.width - emacsframe->border_width;
6499 newh = (int)wr.size.height - extra;
6501 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6502 NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6504 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6505 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6507 if (cols < MINWIDTH)
6510 if (rows < MINHEIGHT)
6513 NSTRACE_MSG ("New columns: %d", cols);
6514 NSTRACE_MSG ("New rows: %d", rows);
6516 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6518 NSView *view = FRAME_NS_VIEW (emacsframe);
6520 change_frame_size (emacsframe,
6521 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6522 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6524 SET_FRAME_GARBAGED (emacsframe);
6525 cancel_mouse_face (emacsframe);
6527 wr = NSMakeRect (0, 0, neww, newh);
6529 [view setFrame: wr];
6531 // to do: consider using [NSNotificationCenter postNotificationName:].
6532 [self windowDidMove: // Update top/left.
6533 [NSNotification notificationWithName:NSWindowDidMoveNotification
6534 object:[view window]]];
6538 NSTRACE_MSG ("No change");
6542 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6543 /* normalize frame to gridded text size */
6547 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6548 NSTRACE_ARG_SIZE (frameSize));
6549 NSTRACE_RECT ("[sender frame]", [sender frame]);
6550 NSTRACE_FSTYPE ("fs_state", fs_state);
6552 if (fs_state == FULLSCREEN_MAXIMIZED
6553 && (maximized_width != (int)frameSize.width
6554 || maximized_height != (int)frameSize.height))
6555 [self setFSValue: FULLSCREEN_NONE];
6556 else if (fs_state == FULLSCREEN_WIDTH
6557 && maximized_width != (int)frameSize.width)
6558 [self setFSValue: FULLSCREEN_NONE];
6559 else if (fs_state == FULLSCREEN_HEIGHT
6560 && maximized_height != (int)frameSize.height)
6561 [self setFSValue: FULLSCREEN_NONE];
6563 if (fs_state == FULLSCREEN_NONE)
6564 maximized_width = maximized_height = -1;
6566 if (! [self isFullscreen])
6568 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6569 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6572 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6573 if (cols < MINWIDTH)
6576 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6577 frameSize.height - extra);
6578 if (rows < MINHEIGHT)
6580 #ifdef NS_IMPL_COCOA
6582 /* this sets window title to have size in it; the wm does this under GS */
6583 NSRect r = [[self window] frame];
6584 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6592 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6595 NSWindow *window = [self window];
6598 char *t = strdup ([[[self window] title] UTF8String]);
6599 char *pos = strstr (t, " — ");
6604 size_title = xmalloc (strlen (old_title) + 40);
6605 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6606 [window setTitle: [NSString stringWithUTF8String: size_title]];
6611 #endif /* NS_IMPL_COCOA */
6613 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6615 /* Restrict the new size to the text gird.
6617 Don't restrict the width if the user only adjusted the height, and
6618 vice versa. (Without this, the frame would shrink, and move
6619 slightly, if the window was resized by dragging one of its
6621 if (!frame_resize_pixelwise)
6623 NSRect r = [[self window] frame];
6625 if (r.size.width != frameSize.width)
6628 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6631 if (r.size.height != frameSize.height)
6634 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6638 NSTRACE_RETURN_SIZE (frameSize);
6644 - (void)windowDidResize: (NSNotification *)notification
6646 NSTRACE ("[EmacsView windowDidResize:]");
6647 if (!FRAME_LIVE_P (emacsframe))
6649 NSTRACE_MSG ("Ignored (frame dead)");
6652 if (emacsframe->output_data.ns->in_animation)
6654 NSTRACE_MSG ("Ignored (in animation)");
6658 if (! [self fsIsNative])
6660 NSWindow *theWindow = [notification object];
6661 /* We can get notification on the non-FS window when in
6663 if ([self window] != theWindow) return;
6666 NSTRACE_RECT ("frame", [[notification object] frame]);
6668 #ifdef NS_IMPL_GNUSTEP
6669 NSWindow *theWindow = [notification object];
6671 /* In GNUstep, at least currently, it's possible to get a didResize
6672 without getting a willResize.. therefore we need to act as if we got
6673 the willResize now */
6674 NSSize sz = [theWindow frame].size;
6675 sz = [self windowWillResize: theWindow toSize: sz];
6676 #endif /* NS_IMPL_GNUSTEP */
6678 if (cols > 0 && rows > 0)
6680 [self updateFrameSize: YES];
6683 ns_send_appdefined (-1);
6686 #ifdef NS_IMPL_COCOA
6687 - (void)viewDidEndLiveResize
6689 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6691 [super viewDidEndLiveResize];
6694 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6698 maximizing_resize = NO;
6700 #endif /* NS_IMPL_COCOA */
6703 - (void)windowDidBecomeKey: (NSNotification *)notification
6704 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6706 [self windowDidBecomeKey];
6710 - (void)windowDidBecomeKey /* for direct calls */
6712 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6713 struct frame *old_focus = dpyinfo->x_focus_frame;
6715 NSTRACE ("[EmacsView windowDidBecomeKey]");
6717 if (emacsframe != old_focus)
6718 dpyinfo->x_focus_frame = emacsframe;
6720 ns_frame_rehighlight (emacsframe);
6724 emacs_event->kind = FOCUS_IN_EVENT;
6725 EV_TRAILER ((id)nil);
6730 - (void)windowDidResignKey: (NSNotification *)notification
6731 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6733 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6734 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6735 NSTRACE ("[EmacsView windowDidResignKey:]");
6738 dpyinfo->x_focus_frame = 0;
6740 emacsframe->mouse_moved = 0;
6741 ns_frame_rehighlight (emacsframe);
6743 /* FIXME: for some reason needed on second and subsequent clicks away
6744 from sole-frame Emacs to get hollow box to show */
6745 if (!windowClosing && [[self window] isVisible] == YES)
6747 x_update_cursor (emacsframe, 1);
6748 x_set_frame_alpha (emacsframe);
6751 if (any_help_event_p)
6754 XSETFRAME (frame, emacsframe);
6755 help_echo_string = Qnil;
6756 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6759 if (emacs_event && is_focus_frame)
6761 [self deleteWorkingText];
6762 emacs_event->kind = FOCUS_OUT_EVENT;
6763 EV_TRAILER ((id)nil);
6768 - (void)windowWillMiniaturize: sender
6770 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6774 - (void)setFrame:(NSRect)frameRect;
6776 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6777 NSTRACE_ARG_RECT (frameRect));
6779 [super setFrame:(NSRect)frameRect];
6795 - initFrameFromEmacs: (struct frame *)f
6803 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6804 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6807 processingCompose = NO;
6808 scrollbarsNeedingUpdate = 0;
6809 fs_state = FULLSCREEN_NONE;
6810 fs_before_fs = next_maximized = -1;
6811 #ifdef HAVE_NATIVE_FS
6812 fs_is_native = ns_use_native_fullscreen;
6816 maximized_width = maximized_height = -1;
6819 ns_userRect = NSMakeRect (0, 0, 0, 0);
6820 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6821 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6822 [self initWithFrame: r];
6823 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6825 FRAME_NS_VIEW (f) = self;
6827 #ifdef NS_IMPL_COCOA
6829 maximizing_resize = NO;
6832 win = [[EmacsWindow alloc]
6833 initWithContentRect: r
6834 styleMask: (NSResizableWindowMask |
6835 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6836 NSTitledWindowMask |
6838 NSMiniaturizableWindowMask |
6839 NSClosableWindowMask)
6840 backing: NSBackingStoreBuffered
6843 #ifdef HAVE_NATIVE_FS
6844 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6848 bwidth = f->border_width = wr.size.width - r.size.width;
6849 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6851 [win setAcceptsMouseMovedEvents: YES];
6852 [win setDelegate: self];
6853 #if !defined (NS_IMPL_COCOA) || \
6854 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6855 [win useOptimizedDrawing: YES];
6858 [[win contentView] addSubview: self];
6861 [self registerForDraggedTypes: ns_drag_types];
6864 name = [NSString stringWithUTF8String:
6865 NILP (tem) ? "Emacs" : SSDATA (tem)];
6866 [win setTitle: name];
6868 /* toolbar support */
6869 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6870 [NSString stringWithFormat: @"Emacs Frame %d",
6872 [win setToolbar: toolbar];
6873 [toolbar setVisible: NO];
6875 /* Don't set frame garbaged until tool bar is up to date?
6876 This avoids an extra clear and redraw (flicker) at frame creation. */
6877 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6878 else wait_for_tool_bar = NO;
6881 #ifdef NS_IMPL_COCOA
6883 NSButton *toggleButton;
6884 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6885 [toggleButton setTarget: self];
6886 [toggleButton setAction: @selector (toggleToolbar: )];
6889 FRAME_TOOLBAR_HEIGHT (f) = 0;
6893 [win setMiniwindowTitle:
6894 [NSString stringWithUTF8String: SSDATA (tem)]];
6897 NSScreen *screen = [win screen];
6901 NSPoint pt = NSMakePoint
6902 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6903 IN_BOUND (-SCREENMAX,
6904 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6906 [win setFrameTopLeftPoint: pt];
6908 NSTRACE_RECT ("new frame", [win frame]);
6912 [win makeFirstResponder: self];
6914 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6915 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6916 [win setBackgroundColor: col];
6917 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6918 [win setOpaque: NO];
6920 #if !defined (NS_IMPL_COCOA) || \
6921 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6922 [self allocateGState];
6924 [NSApp registerServicesMenuSendTypes: ns_send_types
6932 - (void)windowDidMove: sender
6934 NSWindow *win = [self window];
6935 NSRect r = [win frame];
6936 NSArray *screens = [NSScreen screens];
6937 NSScreen *screen = [screens objectAtIndex: 0];
6939 NSTRACE ("[EmacsView windowDidMove:]");
6941 if (!emacsframe->output_data.ns)
6945 emacsframe->left_pos = r.origin.x;
6946 emacsframe->top_pos =
6947 [screen frame].size.height - (r.origin.y + r.size.height);
6952 /* Called AFTER method below, but before our windowWillResize call there leads
6953 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6954 location so set_window_size moves the frame. */
6955 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6957 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6958 NSTRACE_FMT_RETURN "YES"),
6959 NSTRACE_ARG_RECT (newFrame));
6961 emacsframe->output_data.ns->zooming = 1;
6966 /* Override to do something slightly nonstandard, but nice. First click on
6967 zoom button will zoom vertically. Second will zoom completely. Third
6968 returns to original. */
6969 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6970 defaultFrame:(NSRect)defaultFrame
6972 // TODO: Rename to "currentFrame" and assign "result" properly in
6974 NSRect result = [sender frame];
6976 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6977 NSTRACE_FMT_RECT "]"),
6978 NSTRACE_ARG_RECT (defaultFrame));
6979 NSTRACE_FSTYPE ("fs_state", fs_state);
6980 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6981 NSTRACE_FSTYPE ("next_maximized", next_maximized);
6982 NSTRACE_RECT ("ns_userRect", ns_userRect);
6983 NSTRACE_RECT ("[sender frame]", [sender frame]);
6985 if (fs_before_fs != -1) /* Entering fullscreen */
6987 NSTRACE_MSG ("Entering fullscreen");
6988 result = defaultFrame;
6992 // Save the window size and position (frame) before the resize.
6993 if (fs_state != FULLSCREEN_MAXIMIZED
6994 && fs_state != FULLSCREEN_WIDTH)
6996 ns_userRect.size.width = result.size.width;
6997 ns_userRect.origin.x = result.origin.x;
7000 if (fs_state != FULLSCREEN_MAXIMIZED
7001 && fs_state != FULLSCREEN_HEIGHT)
7003 ns_userRect.size.height = result.size.height;
7004 ns_userRect.origin.y = result.origin.y;
7007 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7009 if (next_maximized == FULLSCREEN_HEIGHT
7010 || (next_maximized == -1
7011 && abs ((int)(defaultFrame.size.height - result.size.height))
7012 > FRAME_LINE_HEIGHT (emacsframe)))
7015 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7016 maximized_height = result.size.height = defaultFrame.size.height;
7017 maximized_width = -1;
7018 result.origin.y = defaultFrame.origin.y;
7019 if (ns_userRect.size.height != 0)
7021 result.origin.x = ns_userRect.origin.x;
7022 result.size.width = ns_userRect.size.width;
7024 [self setFSValue: FULLSCREEN_HEIGHT];
7025 #ifdef NS_IMPL_COCOA
7026 maximizing_resize = YES;
7029 else if (next_maximized == FULLSCREEN_WIDTH)
7031 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7032 maximized_width = result.size.width = defaultFrame.size.width;
7033 maximized_height = -1;
7034 result.origin.x = defaultFrame.origin.x;
7035 if (ns_userRect.size.width != 0)
7037 result.origin.y = ns_userRect.origin.y;
7038 result.size.height = ns_userRect.size.height;
7040 [self setFSValue: FULLSCREEN_WIDTH];
7042 else if (next_maximized == FULLSCREEN_MAXIMIZED
7043 || (next_maximized == -1
7044 && abs ((int)(defaultFrame.size.width - result.size.width))
7045 > FRAME_COLUMN_WIDTH (emacsframe)))
7047 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7049 result = defaultFrame; /* second click */
7050 maximized_width = result.size.width;
7051 maximized_height = result.size.height;
7052 [self setFSValue: FULLSCREEN_MAXIMIZED];
7053 #ifdef NS_IMPL_COCOA
7054 maximizing_resize = YES;
7060 NSTRACE_MSG ("Restore");
7061 result = ns_userRect.size.height ? ns_userRect : result;
7062 NSTRACE_RECT ("restore (2)", result);
7063 ns_userRect = NSMakeRect (0, 0, 0, 0);
7064 #ifdef NS_IMPL_COCOA
7065 maximizing_resize = fs_state != FULLSCREEN_NONE;
7067 [self setFSValue: FULLSCREEN_NONE];
7068 maximized_width = maximized_height = -1;
7072 if (fs_before_fs == -1) next_maximized = -1;
7074 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7075 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7076 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7077 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7079 [self windowWillResize: sender toSize: result.size];
7081 NSTRACE_RETURN_RECT (result);
7087 - (void)windowDidDeminiaturize: sender
7089 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7090 if (!emacsframe->output_data.ns)
7093 SET_FRAME_ICONIFIED (emacsframe, 0);
7094 SET_FRAME_VISIBLE (emacsframe, 1);
7095 windows_or_buffers_changed = 63;
7099 emacs_event->kind = DEICONIFY_EVENT;
7100 EV_TRAILER ((id)nil);
7105 - (void)windowDidExpose: sender
7107 NSTRACE ("[EmacsView windowDidExpose:]");
7108 if (!emacsframe->output_data.ns)
7111 SET_FRAME_VISIBLE (emacsframe, 1);
7112 SET_FRAME_GARBAGED (emacsframe);
7114 if (send_appdefined)
7115 ns_send_appdefined (-1);
7119 - (void)windowDidMiniaturize: sender
7121 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7122 if (!emacsframe->output_data.ns)
7125 SET_FRAME_ICONIFIED (emacsframe, 1);
7126 SET_FRAME_VISIBLE (emacsframe, 0);
7130 emacs_event->kind = ICONIFY_EVENT;
7131 EV_TRAILER ((id)nil);
7135 #ifdef HAVE_NATIVE_FS
7136 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7137 willUseFullScreenPresentationOptions:
7138 (NSApplicationPresentationOptions)proposedOptions
7140 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7144 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7146 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7147 [self windowWillEnterFullScreen];
7149 - (void)windowWillEnterFullScreen /* provided for direct calls */
7151 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7152 fs_before_fs = fs_state;
7155 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7157 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7158 [self windowDidEnterFullScreen];
7161 - (void)windowDidEnterFullScreen /* provided for direct calls */
7163 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7164 [self setFSValue: FULLSCREEN_BOTH];
7165 if (! [self fsIsNative])
7167 [self windowDidBecomeKey];
7168 [nonfs_window orderOut:self];
7172 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7173 #ifdef NS_IMPL_COCOA
7174 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7175 unsigned val = (unsigned)[NSApp presentationOptions];
7177 // OSX 10.7 bug fix, the menu won't appear without this.
7178 // val is non-zero on other OSX versions.
7181 NSApplicationPresentationOptions options
7182 = NSApplicationPresentationAutoHideDock
7183 | NSApplicationPresentationAutoHideMenuBar
7184 | NSApplicationPresentationFullScreen
7185 | NSApplicationPresentationAutoHideToolbar;
7187 [NSApp setPresentationOptions: options];
7191 [toolbar setVisible:tbar_visible];
7195 - (void)windowWillExitFullScreen:(NSNotification *)notification
7197 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7198 [self windowWillExitFullScreen];
7201 - (void)windowWillExitFullScreen /* provided for direct calls */
7203 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7204 if (!FRAME_LIVE_P (emacsframe))
7206 NSTRACE_MSG ("Ignored (frame dead)");
7209 if (next_maximized != -1)
7210 fs_before_fs = next_maximized;
7213 - (void)windowDidExitFullScreen:(NSNotification *)notification
7215 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7216 [self windowDidExitFullScreen];
7219 - (void)windowDidExitFullScreen /* provided for direct calls */
7221 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7222 if (!FRAME_LIVE_P (emacsframe))
7224 NSTRACE_MSG ("Ignored (frame dead)");
7227 [self setFSValue: fs_before_fs];
7229 #ifdef HAVE_NATIVE_FS
7230 [self updateCollectionBehavior];
7232 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7234 [toolbar setVisible:YES];
7235 update_frame_tool_bar (emacsframe);
7236 [self updateFrameSize:YES];
7237 [[self window] display];
7240 [toolbar setVisible:NO];
7242 if (next_maximized != -1)
7243 [[self window] performZoom:self];
7248 return fs_is_native;
7251 - (BOOL)isFullscreen
7257 res = (nonfs_window != nil);
7261 #ifdef HAVE_NATIVE_FS
7262 res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7268 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7274 #ifdef HAVE_NATIVE_FS
7275 - (void)updateCollectionBehavior
7277 NSTRACE ("[EmacsView updateCollectionBehavior]");
7279 if (! [self isFullscreen])
7281 NSWindow *win = [self window];
7282 NSWindowCollectionBehavior b = [win collectionBehavior];
7283 if (ns_use_native_fullscreen)
7284 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7286 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7288 [win setCollectionBehavior: b];
7289 fs_is_native = ns_use_native_fullscreen;
7294 - (void)toggleFullScreen: (id)sender
7302 NSTRACE ("[EmacsView toggleFullScreen:]");
7306 #ifdef HAVE_NATIVE_FS
7307 [[self window] toggleFullScreen:sender];
7313 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7316 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7317 (FRAME_DEFAULT_FACE (f)),
7320 if (fs_state != FULLSCREEN_BOTH)
7322 NSScreen *screen = [w screen];
7324 #if defined (NS_IMPL_COCOA) && \
7325 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7326 /* Hide ghost menu bar on secondary monitor? */
7327 if (! onFirstScreen)
7328 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7330 /* Hide dock and menubar if we are on the primary screen. */
7333 #ifdef NS_IMPL_COCOA
7334 NSApplicationPresentationOptions options
7335 = NSApplicationPresentationAutoHideDock
7336 | NSApplicationPresentationAutoHideMenuBar;
7338 [NSApp setPresentationOptions: options];
7340 [NSMenu setMenuBarVisible:NO];
7344 fw = [[EmacsFSWindow alloc]
7345 initWithContentRect:[w contentRectForFrameRect:wr]
7346 styleMask:NSBorderlessWindowMask
7347 backing:NSBackingStoreBuffered
7351 [fw setContentView:[w contentView]];
7352 [fw setTitle:[w title]];
7353 [fw setDelegate:self];
7354 [fw setAcceptsMouseMovedEvents: YES];
7355 #if !defined (NS_IMPL_COCOA) || \
7356 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7357 [fw useOptimizedDrawing: YES];
7359 [fw setBackgroundColor: col];
7360 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7363 f->border_width = 0;
7364 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7365 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7366 FRAME_TOOLBAR_HEIGHT (f) = 0;
7370 [self windowWillEnterFullScreen];
7371 [fw makeKeyAndOrderFront:NSApp];
7372 [fw makeFirstResponder:self];
7374 r = [fw frameRectForContentRect:[screen frame]];
7375 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7376 [self windowDidEnterFullScreen];
7387 #ifdef NS_IMPL_COCOA
7388 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7390 [NSMenu setMenuBarVisible:YES];
7394 [w setContentView:[fw contentView]];
7395 [w setBackgroundColor: col];
7396 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7399 f->border_width = bwidth;
7400 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7401 if (FRAME_EXTERNAL_TOOL_BAR (f))
7402 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7404 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7406 [self windowWillExitFullScreen];
7407 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7409 [w makeKeyAndOrderFront:NSApp];
7410 [self windowDidExitFullScreen];
7411 [self updateFrameSize:YES];
7417 NSTRACE ("[EmacsView handleFS]");
7419 if (fs_state != emacsframe->want_fullscreen)
7421 if (fs_state == FULLSCREEN_BOTH)
7423 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7424 [self toggleFullScreen:self];
7427 switch (emacsframe->want_fullscreen)
7429 case FULLSCREEN_BOTH:
7430 NSTRACE_MSG ("FULLSCREEN_BOTH");
7431 [self toggleFullScreen:self];
7433 case FULLSCREEN_WIDTH:
7434 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7435 next_maximized = FULLSCREEN_WIDTH;
7436 if (fs_state != FULLSCREEN_BOTH)
7437 [[self window] performZoom:self];
7439 case FULLSCREEN_HEIGHT:
7440 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7441 next_maximized = FULLSCREEN_HEIGHT;
7442 if (fs_state != FULLSCREEN_BOTH)
7443 [[self window] performZoom:self];
7445 case FULLSCREEN_MAXIMIZED:
7446 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7447 next_maximized = FULLSCREEN_MAXIMIZED;
7448 if (fs_state != FULLSCREEN_BOTH)
7449 [[self window] performZoom:self];
7451 case FULLSCREEN_NONE:
7452 NSTRACE_MSG ("FULLSCREEN_NONE");
7453 if (fs_state != FULLSCREEN_BOTH)
7455 next_maximized = FULLSCREEN_NONE;
7456 [[self window] performZoom:self];
7461 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7466 - (void) setFSValue: (int)value
7468 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7469 NSTRACE_ARG_FSTYPE(value));
7471 Lisp_Object lval = Qnil;
7474 case FULLSCREEN_BOTH:
7477 case FULLSCREEN_WIDTH:
7480 case FULLSCREEN_HEIGHT:
7483 case FULLSCREEN_MAXIMIZED:
7487 store_frame_param (emacsframe, Qfullscreen, lval);
7491 - (void)mouseEntered: (NSEvent *)theEvent
7493 NSTRACE ("[EmacsView mouseEntered:]");
7495 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7496 = EV_TIMESTAMP (theEvent);
7500 - (void)mouseExited: (NSEvent *)theEvent
7502 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7504 NSTRACE ("[EmacsView mouseExited:]");
7509 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7510 = EV_TIMESTAMP (theEvent);
7512 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7514 clear_mouse_face (hlinfo);
7515 hlinfo->mouse_face_mouse_frame = 0;
7522 NSTRACE ("[EmacsView menuDown:]");
7523 if (context_menu_value == -1)
7524 context_menu_value = [sender tag];
7527 NSInteger tag = [sender tag];
7528 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7529 emacsframe->menu_bar_vector,
7533 ns_send_appdefined (-1);
7538 - (EmacsToolbar *)toolbar
7544 /* this gets called on toolbar button click */
7545 - toolbarClicked: (id)item
7548 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7550 NSTRACE ("[EmacsView toolbarClicked:]");
7555 /* send first event (for some reason two needed) */
7556 theEvent = [[self window] currentEvent];
7557 emacs_event->kind = TOOL_BAR_EVENT;
7558 XSETFRAME (emacs_event->arg, emacsframe);
7559 EV_TRAILER (theEvent);
7561 emacs_event->kind = TOOL_BAR_EVENT;
7562 /* XSETINT (emacs_event->code, 0); */
7563 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7564 idx + TOOL_BAR_ITEM_KEY);
7565 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7566 EV_TRAILER (theEvent);
7571 - toggleToolbar: (id)sender
7573 NSTRACE ("[EmacsView toggleToolbar:]");
7578 emacs_event->kind = NS_NONKEY_EVENT;
7579 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7580 EV_TRAILER ((id)nil);
7585 - (void)drawRect: (NSRect)rect
7587 int x = NSMinX (rect), y = NSMinY (rect);
7588 int width = NSWidth (rect), height = NSHeight (rect);
7590 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7591 NSTRACE_ARG_RECT(rect));
7593 if (!emacsframe || !emacsframe->output_data.ns)
7596 ns_clear_frame_area (emacsframe, x, y, width, height);
7598 expose_frame (emacsframe, x, y, width, height);
7602 drawRect: may be called (at least in OS X 10.5) for invisible
7603 views as well for some reason. Thus, do not infer visibility
7606 emacsframe->async_visible = 1;
7607 emacsframe->async_iconified = 0;
7612 /* NSDraggingDestination protocol methods. Actually this is not really a
7613 protocol, but a category of Object. O well... */
7615 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7617 NSTRACE ("[EmacsView draggingEntered:]");
7618 return NSDragOperationGeneric;
7622 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7628 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7633 NSEvent *theEvent = [[self window] currentEvent];
7635 NSDragOperation op = [sender draggingSourceOperationMask];
7638 NSTRACE ("[EmacsView performDragOperation:]");
7643 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7644 x = lrint (position.x); y = lrint (position.y);
7646 pb = [sender draggingPasteboard];
7647 type = [pb availableTypeFromArray: ns_drag_types];
7649 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7650 // URL drags contain all operations (0xf), don't allow all to be set.
7653 if (op & NSDragOperationLink)
7654 modifiers |= NSControlKeyMask;
7655 if (op & NSDragOperationCopy)
7656 modifiers |= NSAlternateKeyMask;
7657 if (op & NSDragOperationGeneric)
7658 modifiers |= NSCommandKeyMask;
7661 modifiers = EV_MODIFIERS2 (modifiers);
7666 else if ([type isEqualToString: NSFilenamesPboardType])
7669 NSEnumerator *fenum;
7672 if (!(files = [pb propertyListForType: type]))
7675 fenum = [files objectEnumerator];
7676 while ( (file = [fenum nextObject]) )
7678 emacs_event->kind = DRAG_N_DROP_EVENT;
7679 XSETINT (emacs_event->x, x);
7680 XSETINT (emacs_event->y, y);
7681 ns_input_file = append2 (ns_input_file,
7682 build_string ([file UTF8String]));
7683 emacs_event->modifiers = modifiers;
7684 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7685 EV_TRAILER (theEvent);
7689 else if ([type isEqualToString: NSURLPboardType])
7691 NSURL *url = [NSURL URLFromPasteboard: pb];
7692 if (url == nil) return NO;
7694 emacs_event->kind = DRAG_N_DROP_EVENT;
7695 XSETINT (emacs_event->x, x);
7696 XSETINT (emacs_event->y, y);
7697 emacs_event->modifiers = modifiers;
7698 emacs_event->arg = list2 (Qurl,
7699 build_string ([[url absoluteString]
7701 EV_TRAILER (theEvent);
7703 if ([url isFileURL] != NO)
7705 NSString *file = [url path];
7706 ns_input_file = append2 (ns_input_file,
7707 build_string ([file UTF8String]));
7711 else if ([type isEqualToString: NSStringPboardType]
7712 || [type isEqualToString: NSTabularTextPboardType])
7716 if (! (data = [pb stringForType: type]))
7719 emacs_event->kind = DRAG_N_DROP_EVENT;
7720 XSETINT (emacs_event->x, x);
7721 XSETINT (emacs_event->y, y);
7722 emacs_event->modifiers = modifiers;
7723 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7724 EV_TRAILER (theEvent);
7729 fprintf (stderr, "Invalid data type in dragging pasteboard");
7735 - (id) validRequestorForSendType: (NSString *)typeSent
7736 returnType: (NSString *)typeReturned
7738 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7739 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7740 && typeReturned == nil)
7742 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7746 return [super validRequestorForSendType: typeSent
7747 returnType: typeReturned];
7751 /* The next two methods are part of NSServicesRequests informal protocol,
7752 supposedly called when a services menu item is chosen from this app.
7753 But this should not happen because we override the services menu with our
7754 own entries which call ns-perform-service.
7755 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7756 So let's at least stub them out until further investigation can be done. */
7758 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7760 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7761 be written into the buffer in place of the existing selection..
7762 ordinary service calls go through functions defined in ns-win.el */
7766 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7768 NSArray *typesDeclared;
7771 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7773 /* We only support NSStringPboardType */
7774 if ([types containsObject:NSStringPboardType] == NO) {
7778 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7779 if (CONSP (val) && SYMBOLP (XCAR (val)))
7782 if (CONSP (val) && NILP (XCDR (val)))
7785 if (! STRINGP (val))
7788 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7789 [pb declareTypes:typesDeclared owner:nil];
7790 ns_string_to_pasteboard (pb, val);
7795 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7796 (gives a miniaturized version of the window); currently we use the latter for
7797 frames whose active buffer doesn't correspond to any file
7798 (e.g., '*scratch*') */
7799 - setMiniwindowImage: (BOOL) setMini
7801 id image = [[self window] miniwindowImage];
7802 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7804 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7805 about "AppleDockIconEnabled" notwithstanding, however the set message
7806 below has its effect nonetheless. */
7807 if (image != emacsframe->output_data.ns->miniimage)
7809 if (image && [image isKindOfClass: [EmacsImage class]])
7811 [[self window] setMiniwindowImage:
7812 setMini ? emacsframe->output_data.ns->miniimage : nil];
7819 - (void) setRows: (int) r andColumns: (int) c
7821 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7826 - (int) fullscreenState
7831 @end /* EmacsView */
7835 /* ==========================================================================
7837 EmacsWindow implementation
7839 ========================================================================== */
7841 @implementation EmacsWindow
7843 #ifdef NS_IMPL_COCOA
7844 - (id)accessibilityAttributeValue:(NSString *)attribute
7846 Lisp_Object str = Qnil;
7847 struct frame *f = SELECTED_FRAME ();
7848 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7850 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7852 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7853 return NSAccessibilityTextFieldRole;
7855 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7856 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7858 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7860 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7862 if (! NILP (BVAR (curbuf, mark_active)))
7863 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7867 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7868 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7869 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7871 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7872 str = make_uninit_multibyte_string (range, byte_range);
7874 str = make_uninit_string (range);
7875 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7876 Is this a problem? */
7877 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7884 if (CONSP (str) && SYMBOLP (XCAR (str)))
7887 if (CONSP (str) && NILP (XCDR (str)))
7892 const char *utfStr = SSDATA (str);
7893 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7898 return [super accessibilityAttributeValue:attribute];
7900 #endif /* NS_IMPL_COCOA */
7902 /* Constrain size and placement of a frame.
7904 By returning the original "frameRect", the frame is not
7905 constrained. This can lead to unwanted situations where, for
7906 example, the menu bar covers the frame.
7908 The default implementation (accessed using "super") constrains the
7909 frame to the visible area of SCREEN, minus the menu bar (if
7910 present) and the Dock. Note that default implementation also calls
7911 windowWillResize, with the frame it thinks should have. (This can
7912 make the frame exit maximized mode.)
7914 Note that this should work in situations where multiple monitors
7915 are present. Common configurations are side-by-side monitors and a
7916 monitor on top of another (e.g. when a laptop is placed under a
7918 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7920 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7921 NSTRACE_ARG_RECT (frameRect));
7923 #ifdef NS_IMPL_COCOA
7924 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7925 // If separate spaces is on, it is like each screen is independent. There is
7926 // no spanning of frames across screens.
7927 if ([NSScreen screensHaveSeparateSpaces])
7929 NSTRACE_MSG ("Screens have separate spaces");
7930 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7931 NSTRACE_RETURN_RECT (frameRect);
7937 return constrain_frame_rect(frameRect,
7938 [(EmacsView *)[self delegate] isFullscreen]);
7942 - (void)performZoom:(id)sender
7944 NSTRACE ("[EmacsWindow performZoom:]");
7946 return [super performZoom:sender];
7949 - (void)zoom:(id)sender
7951 NSTRACE ("[EmacsWindow zoom:]");
7953 ns_update_auto_hide_menu_bar();
7955 // Below are three zoom implementations. In the final commit, the
7956 // idea is that the last should be included.
7959 // Native zoom done using the standard zoom animation. Size of the
7960 // resulting frame reduced to accommodate the Dock and, if present,
7962 [super zoom:sender];
7965 // Native zoom done using the standard zoom animation, plus an
7966 // explicit resize to cover the full screen, except the menu-bar and
7967 // dock, if present.
7968 [super zoom:sender];
7970 // After the native zoom, resize the resulting frame to fill the
7971 // entire screen, except the menu-bar.
7973 // This works for all practical purposes. (The only minor oddity is
7974 // when transiting from full-height frame to a maximized, the
7975 // animation reduces the height of the frame slightly (to the 4
7976 // pixels needed to accommodate the Doc) before it snaps back into
7977 // full height. The user would need a very trained eye to spot
7979 NSScreen * screen = [self screen];
7982 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7984 NSTRACE_FSTYPE ("fullscreenState", fs_state);
7986 NSRect sr = [screen frame];
7987 struct EmacsMargins margins
7988 = ns_screen_margins_ignoring_hidden_dock(screen);
7990 NSRect wr = [self frame];
7991 NSTRACE_RECT ("Rect after zoom", wr);
7995 if (fs_state == FULLSCREEN_MAXIMIZED
7996 || fs_state == FULLSCREEN_HEIGHT)
7998 newWr.origin.y = sr.origin.y + margins.bottom;
7999 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8002 if (fs_state == FULLSCREEN_MAXIMIZED
8003 || fs_state == FULLSCREEN_WIDTH)
8005 newWr.origin.x = sr.origin.x + margins.left;
8006 newWr.size.width = sr.size.width - margins.right - margins.left;
8009 if (newWr.size.width != wr.size.width
8010 || newWr.size.height != wr.size.height
8011 || newWr.origin.x != wr.origin.x
8012 || newWr.origin.y != wr.origin.y)
8014 NSTRACE_MSG ("New frame different");
8015 [self setFrame: newWr display: NO];
8019 // Non-native zoom which is done instantaneously. The resulting
8020 // frame covers the entire screen, except the menu-bar and dock, if
8022 NSScreen * screen = [self screen];
8025 NSRect sr = [screen frame];
8026 struct EmacsMargins margins
8027 = ns_screen_margins_ignoring_hidden_dock(screen);
8029 sr.size.height -= (margins.top + margins.bottom);
8030 sr.size.width -= (margins.left + margins.right);
8031 sr.origin.x += margins.left;
8032 sr.origin.y += margins.bottom;
8034 sr = [[self delegate] windowWillUseStandardFrame:self
8036 [self setFrame: sr display: NO];
8041 - (void)setFrame:(NSRect)windowFrame
8042 display:(BOOL)displayViews
8044 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8045 NSTRACE_ARG_RECT (windowFrame), displayViews);
8047 [super setFrame:windowFrame display:displayViews];
8050 - (void)setFrame:(NSRect)windowFrame
8051 display:(BOOL)displayViews
8052 animate:(BOOL)performAnimation
8054 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8055 " display:%d performAnimation:%d]",
8056 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8058 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8061 - (void)setFrameTopLeftPoint:(NSPoint)point
8063 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8064 NSTRACE_ARG_POINT (point));
8066 [super setFrameTopLeftPoint:point];
8068 @end /* EmacsWindow */
8071 @implementation EmacsFSWindow
8073 - (BOOL)canBecomeKeyWindow
8078 - (BOOL)canBecomeMainWindow
8085 /* ==========================================================================
8087 EmacsScroller implementation
8089 ========================================================================== */
8092 @implementation EmacsScroller
8094 /* for repeat button push */
8095 #define SCROLL_BAR_FIRST_DELAY 0.5
8096 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8098 + (CGFloat) scrollerWidth
8100 /* TODO: if we want to allow variable widths, this is the place to do it,
8101 however neither GNUstep nor Cocoa support it very well */
8103 #if !defined (NS_IMPL_COCOA) || \
8104 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8105 r = [NSScroller scrollerWidth];
8107 r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
8108 scrollerStyle: NSScrollerStyleLegacy];
8114 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8116 NSTRACE ("[EmacsScroller initFrame: window:]");
8118 r.size.width = [EmacsScroller scrollerWidth];
8119 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8120 [self setContinuous: YES];
8121 [self setEnabled: YES];
8123 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8124 locked against the top and bottom edges, and right edge on OS X, where
8125 scrollers are on right. */
8126 #ifdef NS_IMPL_GNUSTEP
8127 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8129 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8132 window = XWINDOW (nwin);
8134 pixel_height = NSHeight (r);
8135 if (pixel_height == 0) pixel_height = 1;
8136 min_portion = 20 / pixel_height;
8138 frame = XFRAME (window->frame);
8139 if (FRAME_LIVE_P (frame))
8142 EmacsView *view = FRAME_NS_VIEW (frame);
8143 NSView *sview = [[view window] contentView];
8144 NSArray *subs = [sview subviews];
8146 /* disable optimization stopping redraw of other scrollbars */
8147 view->scrollbarsNeedingUpdate = 0;
8148 for (i =[subs count]-1; i >= 0; i--)
8149 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8150 view->scrollbarsNeedingUpdate++;
8151 [sview addSubview: self];
8154 /* [self setFrame: r]; */
8160 - (void)setFrame: (NSRect)newRect
8162 NSTRACE ("[EmacsScroller setFrame:]");
8164 /* block_input (); */
8165 pixel_height = NSHeight (newRect);
8166 if (pixel_height == 0) pixel_height = 1;
8167 min_portion = 20 / pixel_height;
8168 [super setFrame: newRect];
8169 /* unblock_input (); */
8175 NSTRACE ("[EmacsScroller dealloc]");
8177 wset_vertical_scroll_bar (window, Qnil);
8185 NSTRACE ("[EmacsScroller condemn]");
8193 NSTRACE ("[EmacsScroller reprieve]");
8201 NSTRACE ("[EmacsScroller judge]");
8202 bool ret = condemned;
8207 /* ensure other scrollbar updates after deletion */
8208 view = (EmacsView *)FRAME_NS_VIEW (frame);
8210 view->scrollbarsNeedingUpdate++;
8212 wset_vertical_scroll_bar (window, Qnil);
8214 [self removeFromSuperview];
8222 - (void)resetCursorRects
8224 NSRect visible = [self visibleRect];
8225 NSTRACE ("[EmacsScroller resetCursorRects]");
8227 if (!NSIsEmptyRect (visible))
8228 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8229 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8233 - (int) checkSamePosition: (int) position portion: (int) portion
8236 return em_position ==position && em_portion ==portion && em_whole ==whole
8237 && portion != whole; /* needed for resize empty buf */
8241 - setPosition: (int)position portion: (int)portion whole: (int)whole
8243 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8245 em_position = position;
8246 em_portion = portion;
8249 if (portion >= whole)
8251 #ifdef NS_IMPL_COCOA
8252 [self setKnobProportion: 1.0];
8253 [self setDoubleValue: 1.0];
8255 [self setFloatValue: 0.0 knobProportion: 1.0];
8262 portion = max ((float)whole*min_portion/pixel_height, portion);
8263 pos = (float)position / (whole - portion);
8264 por = (CGFloat)portion/whole;
8265 #ifdef NS_IMPL_COCOA
8266 [self setKnobProportion: por];
8267 [self setDoubleValue: pos];
8269 [self setFloatValue: pos knobProportion: por];
8276 /* set up emacs_event */
8277 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8281 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8286 emacs_event->part = last_hit_part;
8287 emacs_event->code = 0;
8288 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8289 XSETWINDOW (win, window);
8290 emacs_event->frame_or_window = win;
8291 emacs_event->timestamp = EV_TIMESTAMP (e);
8292 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8293 emacs_event->arg = Qnil;
8294 XSETINT (emacs_event->x, loc * pixel_height);
8295 XSETINT (emacs_event->y, pixel_height-20);
8299 n_emacs_events_pending++;
8300 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8303 hold_event (emacs_event);
8304 EVENT_INIT (*emacs_event);
8305 ns_send_appdefined (-1);
8309 /* called manually thru timer to implement repeated button action w/hold-down */
8310 - repeatScroll: (NSTimer *)scrollEntry
8312 NSEvent *e = [[self window] currentEvent];
8313 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8314 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8316 NSTRACE ("[EmacsScroller repeatScroll:]");
8318 /* clear timer if need be */
8319 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8321 [scroll_repeat_entry invalidate];
8322 [scroll_repeat_entry release];
8323 scroll_repeat_entry = nil;
8329 = [[NSTimer scheduledTimerWithTimeInterval:
8330 SCROLL_BAR_CONTINUOUS_DELAY
8332 selector: @selector (repeatScroll:)
8338 [self sendScrollEventAtLoc: 0 fromEvent: e];
8343 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8344 mouseDragged events without going into a modal loop. */
8345 - (void)mouseDown: (NSEvent *)e
8348 /* hitPart is only updated AFTER event is passed on */
8349 NSScrollerPart part = [self testPart: [e locationInWindow]];
8350 CGFloat inc = 0.0, loc, kloc, pos;
8353 NSTRACE ("[EmacsScroller mouseDown:]");
8357 case NSScrollerDecrementPage:
8358 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8359 case NSScrollerIncrementPage:
8360 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8361 case NSScrollerDecrementLine:
8362 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8363 case NSScrollerIncrementLine:
8364 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8365 case NSScrollerKnob:
8366 last_hit_part = scroll_bar_handle; break;
8367 case NSScrollerKnobSlot: /* GNUstep-only */
8368 last_hit_part = scroll_bar_move_ratio; break;
8369 default: /* NSScrollerNoPart? */
8370 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8377 pos = 0; /* ignored */
8379 /* set a timer to repeat, as we can't let superclass do this modally */
8381 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8383 selector: @selector (repeatScroll:)
8390 /* handle, or on GNUstep possibly slot */
8391 NSEvent *fake_event;
8393 /* compute float loc in slot and mouse offset on knob */
8394 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8396 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8402 else if (loc >= NSHeight (sr))
8404 loc = NSHeight (sr);
8412 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8414 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8416 last_mouse_offset = kloc;
8418 /* if knob, tell emacs a location offset by knob pos
8419 (to indicate top of handle) */
8420 if (part == NSScrollerKnob)
8421 pos = (loc - last_mouse_offset) / NSHeight (sr);
8423 /* else this is a slot click on GNUstep: go straight there */
8424 pos = loc / NSHeight (sr);
8426 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8427 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8428 location: [e locationInWindow]
8429 modifierFlags: [e modifierFlags]
8430 timestamp: [e timestamp]
8431 windowNumber: [e windowNumber]
8432 context: [e context]
8433 eventNumber: [e eventNumber]
8434 clickCount: [e clickCount]
8435 pressure: [e pressure]];
8436 [super mouseUp: fake_event];
8439 if (part != NSScrollerKnob)
8440 [self sendScrollEventAtLoc: pos fromEvent: e];
8444 /* Called as we manually track scroller drags, rather than superclass. */
8445 - (void)mouseDragged: (NSEvent *)e
8450 NSTRACE ("[EmacsScroller mouseDragged:]");
8452 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8454 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8460 else if (loc >= NSHeight (sr) + last_mouse_offset)
8462 loc = NSHeight (sr) + last_mouse_offset;
8465 pos = (loc - last_mouse_offset) / NSHeight (sr);
8466 [self sendScrollEventAtLoc: pos fromEvent: e];
8470 - (void)mouseUp: (NSEvent *)e
8472 NSTRACE ("[EmacsScroller mouseUp:]");
8474 if (scroll_repeat_entry)
8476 [scroll_repeat_entry invalidate];
8477 [scroll_repeat_entry release];
8478 scroll_repeat_entry = nil;
8480 last_hit_part = scroll_bar_above_handle;
8484 /* treat scrollwheel events in the bar as though they were in the main window */
8485 - (void) scrollWheel: (NSEvent *)theEvent
8487 NSTRACE ("[EmacsScroller scrollWheel:]");
8489 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8490 [view mouseDown: theEvent];
8493 @end /* EmacsScroller */
8496 #ifdef NS_IMPL_GNUSTEP
8497 /* Dummy class to get rid of startup warnings. */
8498 @implementation EmacsDocument
8504 /* ==========================================================================
8506 Font-related functions; these used to be in nsfaces.m
8508 ========================================================================== */
8512 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8514 struct font *font = XFONT_OBJECT (font_object);
8515 EmacsView *view = FRAME_NS_VIEW (f);
8516 int font_ascent, font_descent;
8519 fontset = fontset_from_font (font_object);
8520 FRAME_FONTSET (f) = fontset;
8522 if (FRAME_FONT (f) == font)
8523 /* This font is already set in frame F. There's nothing more to
8527 FRAME_FONT (f) = font;
8529 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8530 FRAME_COLUMN_WIDTH (f) = font->average_width;
8531 get_font_ascent_descent (font, &font_ascent, &font_descent);
8532 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8534 /* Compute the scroll bar width in character columns. */
8535 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8537 int wid = FRAME_COLUMN_WIDTH (f);
8538 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8539 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8543 int wid = FRAME_COLUMN_WIDTH (f);
8544 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8547 /* Compute the scroll bar height in character lines. */
8548 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8550 int height = FRAME_LINE_HEIGHT (f);
8551 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8552 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8556 int height = FRAME_LINE_HEIGHT (f);
8557 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8560 /* Now make the frame display the given font. */
8561 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8562 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8563 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8570 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8571 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8575 ns_xlfd_to_fontname (const char *xlfd)
8576 /* --------------------------------------------------------------------------
8577 Convert an X font name (XLFD) to an NS font name.
8578 Only family is used.
8579 The string returned is temporarily allocated.
8580 -------------------------------------------------------------------------- */
8582 char *name = xmalloc (180);
8586 if (!strncmp (xlfd, "--", 2))
8587 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8589 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8591 /* stopgap for malformed XLFD input */
8592 if (strlen (name) == 0)
8593 strcpy (name, "Monaco");
8595 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8596 also uppercase after '-' or ' ' */
8597 name[0] = c_toupper (name[0]);
8598 for (len =strlen (name), i =0; i<len; i++)
8604 name[i+1] = c_toupper (name[i+1]);
8606 else if (name[i] == '_')
8610 name[i+1] = c_toupper (name[i+1]);
8613 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8614 ret = [[NSString stringWithUTF8String: name] UTF8String];
8621 syms_of_nsterm (void)
8623 NSTRACE ("syms_of_nsterm");
8625 ns_antialias_threshold = 10.0;
8627 /* from 23+ we need to tell emacs what modifiers there are.. */
8628 DEFSYM (Qmodifier_value, "modifier-value");
8629 DEFSYM (Qalt, "alt");
8630 DEFSYM (Qhyper, "hyper");
8631 DEFSYM (Qmeta, "meta");
8632 DEFSYM (Qsuper, "super");
8633 DEFSYM (Qcontrol, "control");
8634 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8636 DEFSYM (Qfile, "file");
8637 DEFSYM (Qurl, "url");
8639 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8640 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8641 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8642 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8643 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8645 DEFVAR_LISP ("ns-input-file", ns_input_file,
8646 "The file specified in the last NS event.");
8647 ns_input_file =Qnil;
8649 DEFVAR_LISP ("ns-working-text", ns_working_text,
8650 "String for visualizing working composition sequence.");
8651 ns_working_text =Qnil;
8653 DEFVAR_LISP ("ns-input-font", ns_input_font,
8654 "The font specified in the last NS event.");
8655 ns_input_font =Qnil;
8657 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8658 "The fontsize specified in the last NS event.");
8659 ns_input_fontsize =Qnil;
8661 DEFVAR_LISP ("ns-input-line", ns_input_line,
8662 "The line specified in the last NS event.");
8663 ns_input_line =Qnil;
8665 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8666 "The service name specified in the last NS event.");
8667 ns_input_spi_name =Qnil;
8669 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8670 "The service argument specified in the last NS event.");
8671 ns_input_spi_arg =Qnil;
8673 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8674 "This variable describes the behavior of the alternate or option key.\n\
8675 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8676 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8677 at all, allowing it to be used at a lower level for accented character entry.");
8678 ns_alternate_modifier = Qmeta;
8680 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8681 "This variable describes the behavior of the right alternate or option key.\n\
8682 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8683 Set to left means be the same key as `ns-alternate-modifier'.\n\
8684 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8685 at all, allowing it to be used at a lower level for accented character entry.");
8686 ns_right_alternate_modifier = Qleft;
8688 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8689 "This variable describes the behavior of the command key.\n\
8690 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8691 ns_command_modifier = Qsuper;
8693 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8694 "This variable describes the behavior of the right command key.\n\
8695 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8696 Set to left means be the same key as `ns-command-modifier'.\n\
8697 Set to none means that the command / option key is not interpreted by Emacs\n\
8698 at all, allowing it to be used at a lower level for accented character entry.");
8699 ns_right_command_modifier = Qleft;
8701 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8702 "This variable describes the behavior of the control key.\n\
8703 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8704 ns_control_modifier = Qcontrol;
8706 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8707 "This variable describes the behavior of the right control key.\n\
8708 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8709 Set to left means be the same key as `ns-control-modifier'.\n\
8710 Set to none means that the control / option key is not interpreted by Emacs\n\
8711 at all, allowing it to be used at a lower level for accented character entry.");
8712 ns_right_control_modifier = Qleft;
8714 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8715 "This variable describes the behavior of the function key (on laptops).\n\
8716 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8717 Set to none means that the function key is not interpreted by Emacs at all,\n\
8718 allowing it to be used at a lower level for accented character entry.");
8719 ns_function_modifier = Qnone;
8721 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8722 "Non-nil (the default) means to render text antialiased.");
8723 ns_antialias_text = Qt;
8725 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8726 "Whether to confirm application quit using dialog.");
8727 ns_confirm_quit = Qnil;
8729 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8730 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8731 Only works on OSX 10.6 or later. */);
8732 ns_auto_hide_menu_bar = Qnil;
8734 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8735 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8736 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8737 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
8738 Default is t for OSX >= 10.7, nil otherwise. */);
8739 #ifdef HAVE_NATIVE_FS
8740 ns_use_native_fullscreen = YES;
8742 ns_use_native_fullscreen = NO;
8744 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8746 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8747 doc: /*Non-nil means use animation on non-native fullscreen.
8748 For native fullscreen, this does nothing.
8749 Default is nil. */);
8750 ns_use_fullscreen_animation = NO;
8752 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8753 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8754 Note that this does not apply to images.
8755 This variable is ignored on OSX < 10.7 and GNUstep. */);
8756 ns_use_srgb_colorspace = YES;
8758 /* TODO: move to common code */
8759 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8760 doc: /* Which toolkit scroll bars Emacs uses, if any.
8761 A value of nil means Emacs doesn't use toolkit scroll bars.
8762 With the X Window system, the value is a symbol describing the
8763 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8764 With MS Windows or Nextstep, the value is t. */);
8765 Vx_toolkit_scroll_bars = Qt;
8767 DEFVAR_BOOL ("x-use-underline-position-properties",
8768 x_use_underline_position_properties,
8769 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8770 A value of nil means ignore them. If you encounter fonts with bogus
8771 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8772 to 4.1, set this to nil. */);
8773 x_use_underline_position_properties = 0;
8775 DEFVAR_BOOL ("x-underline-at-descent-line",
8776 x_underline_at_descent_line,
8777 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8778 A value of nil means to draw the underline according to the value of the
8779 variable `x-use-underline-position-properties', which is usually at the
8780 baseline level. The default value is nil. */);
8781 x_underline_at_descent_line = 0;
8783 /* Tell Emacs about this window system. */
8784 Fprovide (Qns, Qnil);
8786 DEFSYM (Qcocoa, "cocoa");
8787 DEFSYM (Qgnustep, "gnustep");
8789 #ifdef NS_IMPL_COCOA
8790 Fprovide (Qcocoa, Qnil);
8793 Fprovide (Qgnustep, Qnil);