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 /* Set LANG to locale, but not if LANG is already set. */
600 setenv("LANG", [[locale localeIdentifier] UTF8String], 0);
602 @catch (NSException *e)
604 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
610 ns_release_object (void *obj)
611 /* --------------------------------------------------------------------------
612 Release an object (callable from C)
613 -------------------------------------------------------------------------- */
620 ns_retain_object (void *obj)
621 /* --------------------------------------------------------------------------
622 Retain an object (callable from C)
623 -------------------------------------------------------------------------- */
630 ns_alloc_autorelease_pool (void)
631 /* --------------------------------------------------------------------------
632 Allocate a pool for temporary objects (callable from C)
633 -------------------------------------------------------------------------- */
635 return [[NSAutoreleasePool alloc] init];
640 ns_release_autorelease_pool (void *pool)
641 /* --------------------------------------------------------------------------
642 Free a pool and temporary objects it refers to (callable from C)
643 -------------------------------------------------------------------------- */
645 ns_release_object (pool);
650 ns_menu_bar_should_be_hidden (void)
651 /* True, if the menu bar should be hidden. */
653 return !NILP (ns_auto_hide_menu_bar)
654 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
667 static struct EmacsMargins
668 ns_screen_margins (NSScreen *screen)
669 /* The parts of SCREEN used by the operating system. */
671 NSTRACE ("ns_screen_margins");
673 struct EmacsMargins margins;
675 NSRect screenFrame = [screen frame];
676 NSRect screenVisibleFrame = [screen visibleFrame];
678 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
679 menu bar, check this explicitly. */
680 if (ns_menu_bar_should_be_hidden())
686 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
687 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
688 + screenVisibleFrame.size.height);
690 margins.top = frameTop - visibleFrameTop;
694 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
695 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
696 + screenVisibleFrame.size.width);
697 margins.right = frameRight - visibleFrameRight;
700 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
701 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
703 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
713 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
714 assumed to contain a hidden dock. OS X currently use 4 pixels for
715 this, however, to be future compatible, a larger value is used. */
716 #define DOCK_IGNORE_LIMIT 6
718 static struct EmacsMargins
719 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
720 /* The parts of SCREEN used by the operating system, excluding the parts
721 reserved for an hidden dock. */
723 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
725 struct EmacsMargins margins = ns_screen_margins(screen);
727 /* OS X (currently) reserved 4 pixels along the edge where a hidden
728 dock is located. Unfortunately, it's not possible to find the
729 location and information about if the dock is hidden. Instead,
730 it is assumed that if the margin of an edge is less than
731 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
732 if (margins.left <= DOCK_IGNORE_LIMIT)
736 if (margins.right <= DOCK_IGNORE_LIMIT)
740 if (margins.top <= DOCK_IGNORE_LIMIT)
744 /* Note: This doesn't occur in current versions of OS X, but
745 included for completeness and future compatibility. */
746 if (margins.bottom <= DOCK_IGNORE_LIMIT)
751 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
762 ns_menu_bar_height (NSScreen *screen)
763 /* The height of the menu bar, if visible.
765 Note: Don't use this when fullscreen is enabled -- the screen
766 sometimes includes, sometimes excludes the menu bar area. */
768 struct EmacsMargins margins = ns_screen_margins(screen);
770 CGFloat res = margins.top;
772 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
778 /* ==========================================================================
780 Focus (clipping) and screen update
782 ========================================================================== */
785 // Window constraining
786 // -------------------
788 // To ensure that the windows are not placed under the menu bar, they
789 // are typically moved by the call-back constrainFrameRect. However,
790 // by overriding it, it's possible to inhibit this, leaving the window
791 // in it's original position.
793 // It's possible to hide the menu bar. However, technically, it's only
794 // possible to hide it when the application is active. To ensure that
795 // this work properly, the menu bar and window constraining are
796 // deferred until the application becomes active.
798 // Even though it's not possible to manually move a window above the
799 // top of the screen, it is allowed if it's done programmatically,
800 // when the menu is hidden. This allows the editable area to cover the
801 // full screen height.
806 // Use the following extra files:
809 // ;; Hide menu and place frame slightly above the top of the screen.
810 // (setq ns-auto-hide-menu-bar t)
811 // (set-frame-position (selected-frame) 0 -20)
815 // emacs -Q -l init.el
817 // Result: No menu bar, and the title bar should be above the screen.
823 // Result: Menu bar visible, frame placed immediately below the menu.
826 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
828 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
829 NSTRACE_ARG_RECT (frameRect));
831 // --------------------
832 // Collect information about the screen the frame is covering.
835 NSArray *screens = [NSScreen screens];
836 NSUInteger nr_screens = [screens count];
840 // The height of the menu bar, if present in any screen the frame is
842 int menu_bar_height = 0;
844 // A rectangle covering all the screen the frame is displayed in.
845 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
846 for (i = 0; i < nr_screens; ++i )
848 NSScreen *s = [screens objectAtIndex: i];
849 NSRect scrRect = [s frame];
851 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
852 i, NSTRACE_ARG_RECT (scrRect));
854 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
856 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
860 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
861 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
866 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
868 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
870 if (multiscreenRect.size.width == 0
871 || multiscreenRect.size.height == 0)
873 // Failed to find any monitor, give up.
874 NSTRACE_MSG ("multiscreenRect empty");
875 NSTRACE_RETURN_RECT (frameRect);
880 // --------------------
881 // Find a suitable placement.
884 if (ns_menu_bar_should_be_hidden())
886 // When the menu bar is hidden, the user may place part of the
887 // frame above the top of the screen, for example to hide the
890 // Hence, keep the original position.
894 // Ensure that the frame is below the menu bar, or below the top
897 // This assume that the menu bar is placed at the top in the
898 // rectangle that covers the monitors. (It doesn't have to be,
899 // but if it's not it's hard to do anything useful.)
900 CGFloat topOfWorkArea = (multiscreenRect.origin.y
901 + multiscreenRect.size.height
904 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
905 if (topOfFrame > topOfWorkArea)
907 frameRect.origin.y -= topOfFrame - topOfWorkArea;
908 NSTRACE_RECT ("After placement adjust", frameRect);
912 // Include the following section to restrict frame to the screens.
913 // (If so, update it to allow the frame to stretch down below the
916 // --------------------
917 // Ensure frame doesn't stretch below the screens.
920 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
924 frameRect.origin.y = multiscreenRect.origin.y;
925 frameRect.size.height -= diff;
929 NSTRACE_RETURN_RECT (frameRect);
935 ns_constrain_all_frames (void)
936 /* --------------------------------------------------------------------------
937 Ensure that the menu bar doesn't cover any frames.
938 -------------------------------------------------------------------------- */
940 Lisp_Object tail, frame;
942 NSTRACE ("ns_constrain_all_frames");
946 FOR_EACH_FRAME (tail, frame)
948 struct frame *f = XFRAME (frame);
951 EmacsView *view = FRAME_NS_VIEW (f);
953 if (![view isFullscreen])
956 setFrame:constrain_frame_rect([[view window] frame], false)
967 ns_update_auto_hide_menu_bar (void)
968 /* --------------------------------------------------------------------------
969 Show or hide the menu bar, based on user setting.
970 -------------------------------------------------------------------------- */
973 NSTRACE ("ns_update_auto_hide_menu_bar");
977 if (NSApp != nil && [NSApp isActive])
979 // Note, "setPresentationOptions" triggers an error unless the
980 // application is active.
981 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
983 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
985 NSApplicationPresentationOptions options
986 = NSApplicationPresentationDefault;
988 if (menu_bar_should_be_hidden)
989 options |= NSApplicationPresentationAutoHideMenuBar
990 | NSApplicationPresentationAutoHideDock;
992 [NSApp setPresentationOptions: options];
994 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
996 if (!ns_menu_bar_is_hidden)
998 ns_constrain_all_frames ();
1009 ns_update_begin (struct frame *f)
1010 /* --------------------------------------------------------------------------
1011 Prepare for a grouped sequence of drawing calls
1012 external (RIF) call; whole frame, called before update_window_begin
1013 -------------------------------------------------------------------------- */
1015 EmacsView *view = FRAME_NS_VIEW (f);
1016 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1018 ns_update_auto_hide_menu_bar ();
1020 #ifdef NS_IMPL_COCOA
1021 if ([view isFullscreen] && [view fsIsNative])
1023 // Fix reappearing tool bar in fullscreen for OSX 10.7
1024 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1025 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1026 if (! tbar_visible != ! [toolbar isVisible])
1027 [toolbar setVisible: tbar_visible];
1031 ns_updating_frame = f;
1034 /* drawRect may have been called for say the minibuffer, and then clip path
1035 is for the minibuffer. But the display engine may draw more because
1036 we have set the frame as garbaged. So reset clip path to the whole
1038 #ifdef NS_IMPL_COCOA
1041 NSRect r = [view frame];
1042 NSRect cr = [[view window] frame];
1043 /* If a large frame size is set, r may be larger than the window frame
1044 before constrained. In that case don't change the clip path, as we
1045 will clear in to the tool bar and title bar. */
1047 + FRAME_NS_TITLEBAR_HEIGHT (f)
1048 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1050 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1057 #ifdef NS_IMPL_GNUSTEP
1058 uRect = NSMakeRect (0, 0, 0, 0);
1064 ns_update_window_begin (struct window *w)
1065 /* --------------------------------------------------------------------------
1066 Prepare for a grouped sequence of drawing calls
1067 external (RIF) call; for one window, called after update_begin
1068 -------------------------------------------------------------------------- */
1070 struct frame *f = XFRAME (WINDOW_FRAME (w));
1071 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1073 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1074 w->output_cursor = w->cursor;
1078 if (f == hlinfo->mouse_face_mouse_frame)
1080 /* Don't do highlighting for mouse motion during the update. */
1081 hlinfo->mouse_face_defer = 1;
1083 /* If the frame needs to be redrawn,
1084 simply forget about any prior mouse highlighting. */
1085 if (FRAME_GARBAGED_P (f))
1086 hlinfo->mouse_face_window = Qnil;
1088 /* (further code for mouse faces ifdef'd out in other terms elided) */
1096 ns_update_window_end (struct window *w, bool cursor_on_p,
1097 bool mouse_face_overwritten_p)
1098 /* --------------------------------------------------------------------------
1099 Finished a grouped sequence of drawing calls
1100 external (RIF) call; for one window called before update_end
1101 -------------------------------------------------------------------------- */
1103 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1105 /* note: this fn is nearly identical in all terms */
1106 if (!w->pseudo_window_p)
1111 display_and_set_cursor (w, 1,
1112 w->output_cursor.hpos, w->output_cursor.vpos,
1113 w->output_cursor.x, w->output_cursor.y);
1115 if (draw_window_fringes (w, 1))
1117 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1118 x_draw_right_divider (w);
1120 x_draw_vertical_border (w);
1126 /* If a row with mouse-face was overwritten, arrange for
1127 frame_up_to_date to redisplay the mouse highlight. */
1128 if (mouse_face_overwritten_p)
1129 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1134 ns_update_end (struct frame *f)
1135 /* --------------------------------------------------------------------------
1136 Finished a grouped sequence of drawing calls
1137 external (RIF) call; for whole frame, called after update_window_end
1138 -------------------------------------------------------------------------- */
1140 EmacsView *view = FRAME_NS_VIEW (f);
1142 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1144 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1145 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1150 [[view window] flushWindow];
1153 ns_updating_frame = NULL;
1157 ns_focus (struct frame *f, NSRect *r, int n)
1158 /* --------------------------------------------------------------------------
1159 Internal: Focus on given frame. During small local updates this is used to
1160 draw, however during large updates, ns_update_begin and ns_update_end are
1161 called to wrap the whole thing, in which case these calls are stubbed out.
1162 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1163 the back end won't do this automatically, and will just end up flushing
1165 -------------------------------------------------------------------------- */
1167 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1170 NSTRACE_RECT ("r", *r);
1173 if (f != ns_updating_frame)
1175 NSView *view = FRAME_NS_VIEW (f);
1176 if (view != focus_view)
1178 if (focus_view != NULL)
1180 [focus_view unlockFocus];
1181 [[focus_view window] flushWindow];
1188 /*if (view) debug_lock++; */
1195 [[NSGraphicsContext currentContext] saveGraphicsState];
1197 NSRectClipList (r, 2);
1206 ns_unfocus (struct frame *f)
1207 /* --------------------------------------------------------------------------
1208 Internal: Remove focus on given frame
1209 -------------------------------------------------------------------------- */
1211 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1215 [[NSGraphicsContext currentContext] restoreGraphicsState];
1219 if (f != ns_updating_frame)
1221 if (focus_view != NULL)
1223 [focus_view unlockFocus];
1224 [[focus_view window] flushWindow];
1233 ns_clip_to_row (struct window *w, struct glyph_row *row,
1234 enum glyph_row_area area, BOOL gc)
1235 /* --------------------------------------------------------------------------
1236 Internal (but parallels other terms): Focus drawing on given row
1237 -------------------------------------------------------------------------- */
1239 struct frame *f = XFRAME (WINDOW_FRAME (w));
1241 int window_x, window_y, window_width;
1243 window_box (w, area, &window_x, &window_y, &window_width, 0);
1245 clip_rect.origin.x = window_x;
1246 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1247 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1248 clip_rect.size.width = window_width;
1249 clip_rect.size.height = row->visible_height;
1251 ns_focus (f, &clip_rect, 1);
1255 /* ==========================================================================
1257 Visible bell and beep.
1259 ========================================================================== */
1262 // This bell implementation shows the visual bell image asynchronously
1263 // from the rest of Emacs. This is done by adding a NSView to the
1264 // superview of the Emacs window and removing it using a timer.
1266 // Unfortunately, some Emacs operations, like scrolling, is done using
1267 // low-level primitives that copy the content of the window, including
1268 // the bell image. To some extent, this is handled by removing the
1269 // image prior to scrolling and marking that the window is in need for
1272 // To test this code, make sure that there is no artifacts of the bell
1273 // image in the following situations. Use a non-empty buffer (like the
1274 // tutorial) to ensure that a scroll is performed:
1276 // * Single-window: C-g C-v
1278 // * Side-by-windows: C-x 3 C-g C-v
1280 // * Windows above each other: C-x 2 C-g C-v
1282 @interface EmacsBell : NSImageView
1284 // Number of currently active bell:s.
1285 unsigned int nestCount;
1289 - (void)show:(NSView *)view;
1294 @implementation EmacsBell
1298 NSTRACE ("[EmacsBell init]");
1299 if ((self = [super init]))
1303 #ifdef NS_IMPL_GNUSTEP
1304 // GNUstep doesn't provide named images. This was reported in
1305 // 2011, see https://savannah.gnu.org/bugs/?33396
1307 // As a drop in replacement, a semitransparent gray square is used.
1308 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1309 [self.image lockFocus];
1310 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1311 NSRectFill(NSMakeRect(0, 0, 32, 32));
1312 [self.image unlockFocus];
1314 self.image = [NSImage imageNamed:NSImageNameCaution];
1315 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1316 self.image.size.height * 5)];
1322 - (void)show:(NSView *)view
1324 NSTRACE ("[EmacsBell show:]");
1325 NSTRACE_MSG ("nestCount: %u", nestCount);
1327 // Show the image, unless it's already shown.
1330 NSRect rect = [view bounds];
1332 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1333 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1335 [self setFrameOrigin:pos];
1336 [self setFrameSize:self.image.size];
1340 [[[view window] contentView] addSubview:self
1341 positioned:NSWindowAbove
1347 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1353 // Note: Trace output from this method isn't shown, reason unknown.
1354 // NSTRACE ("[EmacsBell hide]");
1359 // Remove the image once the last bell became inactive.
1369 NSTRACE ("[EmacsBell remove]");
1372 NSTRACE_MSG ("removeFromSuperview");
1373 [self removeFromSuperview];
1374 mView.needsDisplay = YES;
1382 static EmacsBell * bell_view = nil;
1385 ns_ring_bell (struct frame *f)
1386 /* --------------------------------------------------------------------------
1388 -------------------------------------------------------------------------- */
1390 NSTRACE ("ns_ring_bell");
1393 struct frame *frame = SELECTED_FRAME ();
1396 if (bell_view == nil)
1398 bell_view = [[EmacsBell alloc] init];
1404 view = FRAME_NS_VIEW (frame);
1407 [bell_view show:view];
1419 static void hide_bell ()
1420 /* --------------------------------------------------------------------------
1421 Ensure the bell is hidden.
1422 -------------------------------------------------------------------------- */
1424 NSTRACE ("hide_bell");
1426 if (bell_view != nil)
1433 /* ==========================================================================
1435 Frame / window manager related functions
1437 ========================================================================== */
1441 ns_raise_frame (struct frame *f)
1442 /* --------------------------------------------------------------------------
1443 Bring window to foreground and make it active
1444 -------------------------------------------------------------------------- */
1448 check_window_system (f);
1449 view = FRAME_NS_VIEW (f);
1451 if (FRAME_VISIBLE_P (f))
1452 [[view window] makeKeyAndOrderFront: NSApp];
1458 ns_lower_frame (struct frame *f)
1459 /* --------------------------------------------------------------------------
1461 -------------------------------------------------------------------------- */
1465 check_window_system (f);
1466 view = FRAME_NS_VIEW (f);
1468 [[view window] orderBack: NSApp];
1474 ns_frame_raise_lower (struct frame *f, bool raise)
1475 /* --------------------------------------------------------------------------
1477 -------------------------------------------------------------------------- */
1479 NSTRACE ("ns_frame_raise_lower");
1489 ns_frame_rehighlight (struct frame *frame)
1490 /* --------------------------------------------------------------------------
1491 External (hook): called on things like window switching within frame
1492 -------------------------------------------------------------------------- */
1494 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1495 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1497 NSTRACE ("ns_frame_rehighlight");
1498 if (dpyinfo->x_focus_frame)
1500 dpyinfo->x_highlight_frame
1501 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1502 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1503 : dpyinfo->x_focus_frame);
1504 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1506 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1507 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1511 dpyinfo->x_highlight_frame = 0;
1513 if (dpyinfo->x_highlight_frame &&
1514 dpyinfo->x_highlight_frame != old_highlight)
1518 x_update_cursor (old_highlight, 1);
1519 x_set_frame_alpha (old_highlight);
1521 if (dpyinfo->x_highlight_frame)
1523 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1524 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1531 x_make_frame_visible (struct frame *f)
1532 /* --------------------------------------------------------------------------
1533 External: Show the window (X11 semantics)
1534 -------------------------------------------------------------------------- */
1536 NSTRACE ("x_make_frame_visible");
1537 /* XXX: at some points in past this was not needed, as the only place that
1538 called this (frame.c:Fraise_frame ()) also called raise_lower;
1539 if this ends up the case again, comment this out again. */
1540 if (!FRAME_VISIBLE_P (f))
1542 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1544 SET_FRAME_VISIBLE (f, 1);
1547 /* Making a new frame from a fullscreen frame will make the new frame
1548 fullscreen also. So skip handleFS as this will print an error. */
1549 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1550 && [view isFullscreen])
1553 if (f->want_fullscreen != FULLSCREEN_NONE)
1564 x_make_frame_invisible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566 External: Hide the window (X11 semantics)
1567 -------------------------------------------------------------------------- */
1570 NSTRACE ("x_make_frame_invisible");
1571 check_window_system (f);
1572 view = FRAME_NS_VIEW (f);
1573 [[view window] orderOut: NSApp];
1574 SET_FRAME_VISIBLE (f, 0);
1575 SET_FRAME_ICONIFIED (f, 0);
1580 x_iconify_frame (struct frame *f)
1581 /* --------------------------------------------------------------------------
1582 External: Iconify window
1583 -------------------------------------------------------------------------- */
1586 struct ns_display_info *dpyinfo;
1588 NSTRACE ("x_iconify_frame");
1589 check_window_system (f);
1590 view = FRAME_NS_VIEW (f);
1591 dpyinfo = FRAME_DISPLAY_INFO (f);
1593 if (dpyinfo->x_highlight_frame == f)
1594 dpyinfo->x_highlight_frame = 0;
1596 if ([[view window] windowNumber] <= 0)
1598 /* the window is still deferred. Make it very small, bring it
1599 on screen and order it out. */
1600 NSRect s = { { 100, 100}, {0, 0} };
1602 t = [[view window] frame];
1603 [[view window] setFrame: s display: NO];
1604 [[view window] orderBack: NSApp];
1605 [[view window] orderOut: NSApp];
1606 [[view window] setFrame: t display: NO];
1608 [[view window] miniaturize: NSApp];
1611 /* Free X resources of frame F. */
1614 x_free_frame_resources (struct frame *f)
1617 struct ns_display_info *dpyinfo;
1618 Mouse_HLInfo *hlinfo;
1620 NSTRACE ("x_free_frame_resources");
1621 check_window_system (f);
1622 view = FRAME_NS_VIEW (f);
1623 dpyinfo = FRAME_DISPLAY_INFO (f);
1624 hlinfo = MOUSE_HL_INFO (f);
1626 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1630 free_frame_menubar (f);
1631 free_frame_faces (f);
1633 if (f == dpyinfo->x_focus_frame)
1634 dpyinfo->x_focus_frame = 0;
1635 if (f == dpyinfo->x_highlight_frame)
1636 dpyinfo->x_highlight_frame = 0;
1637 if (f == hlinfo->mouse_face_mouse_frame)
1638 reset_mouse_highlight (hlinfo);
1640 if (f->output_data.ns->miniimage != nil)
1641 [f->output_data.ns->miniimage release];
1643 [[view window] close];
1646 xfree (f->output_data.ns);
1652 x_destroy_window (struct frame *f)
1653 /* --------------------------------------------------------------------------
1654 External: Delete the window
1655 -------------------------------------------------------------------------- */
1657 NSTRACE ("x_destroy_window");
1658 check_window_system (f);
1659 x_free_frame_resources (f);
1665 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1666 /* --------------------------------------------------------------------------
1667 External: Position the window
1668 -------------------------------------------------------------------------- */
1670 NSView *view = FRAME_NS_VIEW (f);
1671 NSArray *screens = [NSScreen screens];
1672 NSScreen *fscreen = [screens objectAtIndex: 0];
1673 NSScreen *screen = [[view window] screen];
1675 NSTRACE ("x_set_offset");
1682 if (view != nil && screen && fscreen)
1684 f->left_pos = f->size_hint_flags & XNegative
1685 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1687 /* We use visibleFrame here to take menu bar into account.
1688 Ideally we should also adjust left/top with visibleFrame.origin. */
1690 f->top_pos = f->size_hint_flags & YNegative
1691 ? ([screen visibleFrame].size.height + f->top_pos
1692 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1693 - FRAME_TOOLBAR_HEIGHT (f))
1695 #ifdef NS_IMPL_GNUSTEP
1696 if (f->left_pos < 100)
1697 f->left_pos = 100; /* don't overlap menu */
1699 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1701 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1702 SCREENMAXBOUND ([fscreen frame].size.height
1704 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1705 [[view window] setFrameTopLeftPoint: pt];
1706 f->size_hint_flags &= ~(XNegative|YNegative);
1714 x_set_window_size (struct frame *f,
1715 bool change_gravity,
1719 /* --------------------------------------------------------------------------
1720 Adjust window pixel size based on given character grid size
1721 Impl is a bit more complex than other terms, need to do some
1723 -------------------------------------------------------------------------- */
1725 EmacsView *view = FRAME_NS_VIEW (f);
1726 NSWindow *window = [view window];
1727 NSRect wr = [window frame];
1728 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1729 int pixelwidth, pixelheight;
1730 int orig_height = wr.size.height;
1732 NSTRACE ("x_set_window_size");
1737 NSTRACE_RECT ("current", wr);
1738 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1739 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1745 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1746 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1750 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1751 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1754 /* If we have a toolbar, take its height into account. */
1755 if (tb && ! [view isFullscreen])
1757 /* NOTE: previously this would generate wrong result if toolbar not
1758 yet displayed and fixing toolbar_height=32 helped, but
1759 now (200903) seems no longer needed */
1760 FRAME_TOOLBAR_HEIGHT (f) =
1761 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1762 - FRAME_NS_TITLEBAR_HEIGHT (f);
1764 /* Only breaks things here, removed by martin 2015-09-30. */
1765 #ifdef NS_IMPL_GNUSTEP
1766 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1771 FRAME_TOOLBAR_HEIGHT (f) = 0;
1773 wr.size.width = pixelwidth + f->border_width;
1774 wr.size.height = pixelheight;
1775 if (! [view isFullscreen])
1776 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1777 + FRAME_TOOLBAR_HEIGHT (f);
1779 /* Do not try to constrain to this screen. We may have multiple
1780 screens, and want Emacs to span those. Constraining to screen
1781 prevents that, and that is not nice to the user. */
1782 if (f->output_data.ns->zooming)
1783 f->output_data.ns->zooming = 0;
1785 wr.origin.y += orig_height - wr.size.height;
1787 frame_size_history_add
1788 (f, Qx_set_window_size_1, width, height,
1789 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1790 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1791 make_number (f->border_width),
1792 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1793 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1795 [window setFrame: wr display: YES];
1797 /* This is a trick to compensate for Emacs' managing the scrollbar area
1798 as a fixed number of standard character columns. Instead of leaving
1799 blank space for the extra, we chopped it off above. Now for
1800 left-hand scrollbars, we shift all rendering to the left by the
1801 difference between the real width and Emacs' imagined one. For
1802 right-hand bars, don't worry about it since the extra is never used.
1803 (Obviously doesn't work for vertically split windows tho..) */
1805 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1806 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1807 - NS_SCROLL_BAR_WIDTH (f), 0)
1808 : NSMakePoint (0, 0);
1810 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1811 [view setBoundsOrigin: origin];
1814 [view updateFrameSize: NO];
1820 ns_fullscreen_hook (struct frame *f)
1822 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1824 NSTRACE ("ns_fullscreen_hook");
1826 if (!FRAME_VISIBLE_P (f))
1829 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1831 /* Old style fs don't initiate correctly if created from
1832 init/default-frame alist, so use a timer (not nice...).
1834 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1835 selector: @selector (handleFS)
1836 userInfo: nil repeats: NO];
1845 /* ==========================================================================
1849 ========================================================================== */
1853 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1855 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1856 if (idx < 1 || idx >= color_table->avail)
1858 return color_table->colors[idx];
1863 ns_index_color (NSColor *color, struct frame *f)
1865 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1869 if (!color_table->colors)
1871 color_table->size = NS_COLOR_CAPACITY;
1872 color_table->avail = 1; /* skip idx=0 as marker */
1873 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1874 color_table->colors[0] = nil;
1875 color_table->empty_indices = [[NSMutableSet alloc] init];
1878 /* Do we already have this color? */
1879 for (i = 1; i < color_table->avail; i++)
1880 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1883 if ([color_table->empty_indices count] > 0)
1885 NSNumber *index = [color_table->empty_indices anyObject];
1886 [color_table->empty_indices removeObject: index];
1887 idx = [index unsignedLongValue];
1891 if (color_table->avail == color_table->size)
1892 color_table->colors =
1893 xpalloc (color_table->colors, &color_table->size, 1,
1894 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1895 idx = color_table->avail++;
1898 color_table->colors[idx] = color;
1900 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1906 ns_free_indexed_color (unsigned long idx, struct frame *f)
1908 struct ns_color_table *color_table;
1915 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1917 if (idx <= 0 || idx >= color_table->size) {
1918 message1 ("ns_free_indexed_color: Color index out of range.\n");
1922 index = [NSNumber numberWithUnsignedInt: idx];
1923 if ([color_table->empty_indices containsObject: index]) {
1924 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1928 color = color_table->colors[idx];
1930 color_table->colors[idx] = nil;
1931 [color_table->empty_indices addObject: index];
1932 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1937 ns_get_color (const char *name, NSColor **col)
1938 /* --------------------------------------------------------------------------
1940 -------------------------------------------------------------------------- */
1941 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1942 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1943 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1946 static char hex[20];
1948 float r = -1.0, g, b;
1949 NSString *nsname = [NSString stringWithUTF8String: name];
1951 NSTRACE ("ns_get_color(%s, **)", name);
1955 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1957 #ifdef NS_IMPL_COCOA
1958 NSString *defname = [[NSUserDefaults standardUserDefaults]
1959 stringForKey: @"AppleHighlightColor"];
1964 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1966 *col = [new colorUsingDefaultColorSpace];
1971 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1973 name = [nsname UTF8String];
1975 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1977 /* NOTE: OSX applications normally don't set foreground selection, but
1978 text may be unreadable if we don't.
1980 if ((new = [NSColor selectedTextColor]) != nil)
1982 *col = [new colorUsingDefaultColorSpace];
1987 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1988 name = [nsname UTF8String];
1991 /* First, check for some sort of numeric specification. */
1994 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1996 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1997 [scanner scanFloat: &r];
1998 [scanner scanFloat: &g];
1999 [scanner scanFloat: &b];
2001 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2002 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2003 else if (name[0] == '#') /* An old X11 format; convert to newer */
2005 int len = (strlen(name) - 1);
2006 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2008 scaling = strlen(name+start) / 3;
2009 for (i = 0; i < 3; i++)
2010 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2011 name + start + i * scaling);
2012 hex[3 * (scaling + 1) - 1] = '\0';
2018 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2019 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2029 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2034 /* Otherwise, color is expected to be from a list */
2036 NSEnumerator *lenum, *cenum;
2040 #ifdef NS_IMPL_GNUSTEP
2041 /* XXX: who is wrong, the requestor or the implementation? */
2042 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2044 nsname = @"highlightColor";
2047 lenum = [[NSColorList availableColorLists] objectEnumerator];
2048 while ( (clist = [lenum nextObject]) && new == nil)
2050 cenum = [[clist allKeys] objectEnumerator];
2051 while ( (name = [cenum nextObject]) && new == nil )
2053 if ([name compare: nsname
2054 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2055 new = [clist colorWithKey: name];
2061 *col = [new colorUsingDefaultColorSpace];
2068 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2069 /* --------------------------------------------------------------------------
2070 Convert a Lisp string object to a NS color
2071 -------------------------------------------------------------------------- */
2073 NSTRACE ("ns_lisp_to_color");
2074 if (STRINGP (color))
2075 return ns_get_color (SSDATA (color), col);
2076 else if (SYMBOLP (color))
2077 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2083 ns_color_to_lisp (NSColor *col)
2084 /* --------------------------------------------------------------------------
2085 Convert a color to a lisp string with the RGB equivalent
2086 -------------------------------------------------------------------------- */
2088 EmacsCGFloat red, green, blue, alpha, gray;
2091 NSTRACE ("ns_color_to_lisp");
2094 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
2096 if ((str =[[col colorNameComponent] UTF8String]))
2099 return build_string ((char *)str);
2102 [[col colorUsingDefaultColorSpace]
2103 getRed: &red green: &green blue: &blue alpha: &alpha];
2104 if (red == green && red == blue)
2106 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
2107 getWhite: &gray alpha: &alpha];
2108 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2109 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
2111 return build_string (buf);
2114 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2115 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2118 return build_string (buf);
2123 ns_query_color(void *col, XColor *color_def, int setPixel)
2124 /* --------------------------------------------------------------------------
2125 Get ARGB values out of NSColor col and put them into color_def.
2126 If setPixel, set the pixel to a concatenated version.
2127 and set color_def pixel to the resulting index.
2128 -------------------------------------------------------------------------- */
2130 EmacsCGFloat r, g, b, a;
2132 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2133 color_def->red = r * 65535;
2134 color_def->green = g * 65535;
2135 color_def->blue = b * 65535;
2137 if (setPixel == YES)
2139 = ARGB_TO_ULONG((int)(a*255),
2140 (int)(r*255), (int)(g*255), (int)(b*255));
2145 ns_defined_color (struct frame *f,
2150 /* --------------------------------------------------------------------------
2151 Return true if named color found, and set color_def rgb accordingly.
2152 If makeIndex and alloc are nonzero put the color in the color_table,
2153 and set color_def pixel to the resulting index.
2154 If makeIndex is zero, set color_def pixel to ARGB.
2155 Return false if not found
2156 -------------------------------------------------------------------------- */
2159 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2162 if (ns_get_color (name, &col) != 0) /* Color not found */
2167 if (makeIndex && alloc)
2168 color_def->pixel = ns_index_color (col, f);
2169 ns_query_color (col, color_def, !makeIndex);
2176 x_set_frame_alpha (struct frame *f)
2177 /* --------------------------------------------------------------------------
2178 change the entire-frame transparency
2179 -------------------------------------------------------------------------- */
2181 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2183 double alpha_min = 1.0;
2185 NSTRACE ("x_set_frame_alpha");
2187 if (dpyinfo->x_highlight_frame == f)
2188 alpha = f->alpha[0];
2190 alpha = f->alpha[1];
2192 if (FLOATP (Vframe_alpha_lower_limit))
2193 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2194 else if (INTEGERP (Vframe_alpha_lower_limit))
2195 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2199 else if (1.0 < alpha)
2201 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2204 #ifdef NS_IMPL_COCOA
2206 EmacsView *view = FRAME_NS_VIEW (f);
2207 [[view window] setAlphaValue: alpha];
2213 /* ==========================================================================
2217 ========================================================================== */
2221 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2222 /* --------------------------------------------------------------------------
2223 Programmatically reposition mouse pointer in pixel coordinates
2224 -------------------------------------------------------------------------- */
2226 NSTRACE ("frame_set_mouse_pixel_position");
2229 /* FIXME: this does not work, and what about GNUstep? */
2230 #ifdef NS_IMPL_COCOA
2231 [FRAME_NS_VIEW (f) lockFocus];
2232 PSsetmouse ((float)pix_x, (float)pix_y);
2233 [FRAME_NS_VIEW (f) unlockFocus];
2239 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2240 /* ------------------------------------------------------------------------
2241 Called by EmacsView on mouseMovement events. Passes on
2242 to emacs mainstream code if we moved off of a rect of interest
2243 known as last_mouse_glyph.
2244 ------------------------------------------------------------------------ */
2246 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2249 // NSTRACE ("note_mouse_movement");
2251 dpyinfo->last_mouse_motion_frame = frame;
2252 r = &dpyinfo->last_mouse_glyph;
2254 /* Note, this doesn't get called for enter/leave, since we don't have a
2255 position. Those are taken care of in the corresponding NSView methods. */
2257 /* has movement gone beyond last rect we were tracking? */
2258 if (x < r->origin.x || x >= r->origin.x + r->size.width
2259 || y < r->origin.y || y >= r->origin.y + r->size.height)
2261 ns_update_begin (frame);
2262 frame->mouse_moved = 1;
2263 note_mouse_highlight (frame, x, y);
2264 remember_mouse_glyph (frame, x, y, r);
2265 ns_update_end (frame);
2274 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2275 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2277 /* --------------------------------------------------------------------------
2278 External (hook): inform emacs about mouse position and hit parts.
2279 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2280 x & y should be position in the scrollbar (the whole bar, not the handle)
2281 and length of scrollbar respectively
2282 -------------------------------------------------------------------------- */
2286 Lisp_Object frame, tail;
2288 struct ns_display_info *dpyinfo;
2290 NSTRACE ("ns_mouse_position");
2294 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2298 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2302 /* Clear the mouse-moved flag for every frame on this display. */
2303 FOR_EACH_FRAME (tail, frame)
2304 if (FRAME_NS_P (XFRAME (frame))
2305 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2306 XFRAME (frame)->mouse_moved = 0;
2308 dpyinfo->last_mouse_scroll_bar = nil;
2309 if (dpyinfo->last_mouse_frame
2310 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2311 f = dpyinfo->last_mouse_frame;
2313 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2315 if (f && FRAME_NS_P (f))
2317 view = FRAME_NS_VIEW (*fp);
2319 position = [[view window] mouseLocationOutsideOfEventStream];
2320 position = [view convertPoint: position fromView: nil];
2321 remember_mouse_glyph (f, position.x, position.y,
2322 &dpyinfo->last_mouse_glyph);
2323 NSTRACE_POINT ("position", position);
2325 if (bar_window) *bar_window = Qnil;
2326 if (part) *part = scroll_bar_above_handle;
2328 if (x) XSETINT (*x, lrint (position.x));
2329 if (y) XSETINT (*y, lrint (position.y));
2331 *time = dpyinfo->last_mouse_movement_time;
2340 ns_frame_up_to_date (struct frame *f)
2341 /* --------------------------------------------------------------------------
2342 External (hook): Fix up mouse highlighting right after a full update.
2343 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2344 -------------------------------------------------------------------------- */
2346 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2350 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2351 if (f == hlinfo->mouse_face_mouse_frame)
2355 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2356 hlinfo->mouse_face_mouse_x,
2357 hlinfo->mouse_face_mouse_y);
2366 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2367 /* --------------------------------------------------------------------------
2368 External (RIF): set frame mouse pointer type.
2369 -------------------------------------------------------------------------- */
2371 NSTRACE ("ns_define_frame_cursor");
2372 if (FRAME_POINTER_TYPE (f) != cursor)
2374 EmacsView *view = FRAME_NS_VIEW (f);
2375 FRAME_POINTER_TYPE (f) = cursor;
2376 [[view window] invalidateCursorRectsForView: view];
2377 /* Redisplay assumes this function also draws the changed frame
2378 cursor, but this function doesn't, so do it explicitly. */
2379 x_update_cursor (f, 1);
2385 /* ==========================================================================
2389 ========================================================================== */
2393 ns_convert_key (unsigned code)
2394 /* --------------------------------------------------------------------------
2395 Internal call used by NSView-keyDown.
2396 -------------------------------------------------------------------------- */
2398 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2400 /* An array would be faster, but less easy to read. */
2401 for (keysym = 0; keysym < last_keysym; keysym += 2)
2402 if (code == convert_ns_to_X_keysym[keysym])
2403 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2405 /* if decide to use keyCode and Carbon table, use this line:
2406 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2411 x_get_keysym_name (int keysym)
2412 /* --------------------------------------------------------------------------
2413 Called by keyboard.c. Not sure if the return val is important, except
2415 -------------------------------------------------------------------------- */
2417 static char value[16];
2418 NSTRACE ("x_get_keysym_name");
2419 sprintf (value, "%d", keysym);
2425 /* ==========================================================================
2427 Block drawing operations
2429 ========================================================================== */
2433 ns_redraw_scroll_bars (struct frame *f)
2437 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2438 NSTRACE ("ns_redraw_scroll_bars");
2439 for (i =[subviews count]-1; i >= 0; i--)
2441 view = [subviews objectAtIndex: i];
2442 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2449 ns_clear_frame (struct frame *f)
2450 /* --------------------------------------------------------------------------
2451 External (hook): Erase the entire frame
2452 -------------------------------------------------------------------------- */
2454 NSView *view = FRAME_NS_VIEW (f);
2457 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2459 /* comes on initial frame because we have
2460 after-make-frame-functions = select-frame */
2461 if (!FRAME_DEFAULT_FACE (f))
2464 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2469 ns_focus (f, &r, 1);
2470 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2474 /* as of 2006/11 or so this is now needed */
2475 ns_redraw_scroll_bars (f);
2481 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2482 /* --------------------------------------------------------------------------
2483 External (RIF): Clear section of frame
2484 -------------------------------------------------------------------------- */
2486 NSRect r = NSMakeRect (x, y, width, height);
2487 NSView *view = FRAME_NS_VIEW (f);
2488 struct face *face = FRAME_DEFAULT_FACE (f);
2493 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2495 r = NSIntersectionRect (r, [view frame]);
2496 ns_focus (f, &r, 1);
2497 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2506 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2508 NSTRACE ("ns_copy_bits");
2510 if (FRAME_NS_VIEW (f))
2512 hide_bell(); // Ensure the bell image isn't scrolled.
2514 ns_focus (f, &dest, 1);
2515 [FRAME_NS_VIEW (f) scrollRect: src
2516 by: NSMakeSize (dest.origin.x - src.origin.x,
2517 dest.origin.y - src.origin.y)];
2523 ns_scroll_run (struct window *w, struct run *run)
2524 /* --------------------------------------------------------------------------
2525 External (RIF): Insert or delete n lines at line vpos
2526 -------------------------------------------------------------------------- */
2528 struct frame *f = XFRAME (w->frame);
2529 int x, y, width, height, from_y, to_y, bottom_y;
2531 NSTRACE ("ns_scroll_run");
2533 /* begin copy from other terms */
2534 /* Get frame-relative bounding box of the text display area of W,
2535 without mode lines. Include in this box the left and right
2537 window_box (w, ANY_AREA, &x, &y, &width, &height);
2539 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2540 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2541 bottom_y = y + height;
2545 /* Scrolling up. Make sure we don't copy part of the mode
2546 line at the bottom. */
2547 if (from_y + run->height > bottom_y)
2548 height = bottom_y - from_y;
2550 height = run->height;
2554 /* Scrolling down. Make sure we don't copy over the mode line.
2556 if (to_y + run->height > bottom_y)
2557 height = bottom_y - to_y;
2559 height = run->height;
2561 /* end copy from other terms */
2571 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2572 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2574 ns_copy_bits (f, srcRect , dstRect);
2582 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2583 /* --------------------------------------------------------------------------
2584 External (RIF): preparatory to fringe update after text was updated
2585 -------------------------------------------------------------------------- */
2590 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2592 /* begin copy from other terms */
2595 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2596 desired_row->redraw_fringe_bitmaps_p = 1;
2598 /* When a window has disappeared, make sure that no rest of
2599 full-width rows stays visible in the internal border. */
2600 if (windows_or_buffers_changed
2601 && desired_row->full_width_p
2602 && (f = XFRAME (w->frame),
2603 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2605 && (height = desired_row->visible_height,
2608 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2611 ns_clear_frame_area (f, 0, y, width, height);
2612 ns_clear_frame_area (f,
2613 FRAME_PIXEL_WIDTH (f) - width,
2621 ns_shift_glyphs_for_insert (struct frame *f,
2622 int x, int y, int width, int height,
2624 /* --------------------------------------------------------------------------
2625 External (RIF): copy an area horizontally, don't worry about clearing src
2626 -------------------------------------------------------------------------- */
2628 NSRect srcRect = NSMakeRect (x, y, width, height);
2629 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2631 NSTRACE ("ns_shift_glyphs_for_insert");
2633 ns_copy_bits (f, srcRect, dstRect);
2638 /* ==========================================================================
2640 Character encoding and metrics
2642 ========================================================================== */
2646 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2647 /* --------------------------------------------------------------------------
2648 External (RIF); compute left/right overhang of whole string and set in s
2649 -------------------------------------------------------------------------- */
2651 struct font *font = s->font;
2655 struct font_metrics metrics;
2656 unsigned int codes[2];
2657 codes[0] = *(s->char2b);
2658 codes[1] = *(s->char2b + s->nchars - 1);
2660 font->driver->text_extents (font, codes, 2, &metrics);
2661 s->left_overhang = -metrics.lbearing;
2663 = metrics.rbearing > metrics.width
2664 ? metrics.rbearing - metrics.width : 0;
2668 s->left_overhang = 0;
2669 if (EQ (font->driver->type, Qns))
2670 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2671 FONT_HEIGHT (font) * 0.2 : 0;
2673 s->right_overhang = 0;
2679 /* ==========================================================================
2681 Fringe and cursor drawing
2683 ========================================================================== */
2686 extern int max_used_fringe_bitmap;
2688 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2689 struct draw_fringe_bitmap_params *p)
2690 /* --------------------------------------------------------------------------
2691 External (RIF); fringe-related
2692 -------------------------------------------------------------------------- */
2694 /* Fringe bitmaps comes in two variants, normal and periodic. A
2695 periodic bitmap is used to create a continuous pattern. Since a
2696 bitmap is rendered one text line at a time, the start offset (dh)
2697 of the bitmap varies. Concretely, this is used for the empty
2700 For a bitmap, "h + dh" is the full height and is always
2701 invariant. For a normal bitmap "dh" is zero.
2703 For example, when the period is three and the full height is 72
2704 the following combinations exists:
2710 struct frame *f = XFRAME (WINDOW_FRAME (w));
2711 struct face *face = p->face;
2712 static EmacsImage **bimgs = NULL;
2713 static int nBimgs = 0;
2715 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2716 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2717 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2719 /* grow bimgs if needed */
2720 if (nBimgs < max_used_fringe_bitmap)
2722 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2723 memset (bimgs + nBimgs, 0,
2724 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2725 nBimgs = max_used_fringe_bitmap;
2728 /* Must clip because of partially visible lines. */
2729 ns_clip_to_row (w, row, ANY_AREA, YES);
2733 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2735 if (bx >= 0 && nx > 0)
2737 NSRect r = NSMakeRect (bx, by, nx, ny);
2739 [ns_lookup_indexed_color (face->background, f) set];
2746 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2747 EmacsImage *img = bimgs[p->which - 1];
2751 // Note: For "periodic" images, allocate one EmacsImage for
2752 // the base image, and use it for all dh:s.
2753 unsigned short *bits = p->bits;
2754 int full_height = p->h + p->dh;
2756 unsigned char *cbits = xmalloc (full_height);
2758 for (i = 0; i < full_height; i++)
2760 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2763 bimgs[p->which - 1] = img;
2767 NSTRACE_RECT ("r", r);
2770 /* Since we composite the bitmap instead of just blitting it, we need
2771 to erase the whole background. */
2772 [ns_lookup_indexed_color(face->background, f) set];
2778 bm_color = ns_lookup_indexed_color(face->foreground, f);
2779 else if (p->overlay_p)
2780 bm_color = ns_lookup_indexed_color(face->background, f);
2782 bm_color = f->output_data.ns->cursor_color;
2783 [img setXBMColor: bm_color];
2786 #ifdef NS_IMPL_COCOA
2787 // Note: For periodic images, the full image height is "h + hd".
2788 // By using the height h, a suitable part of the image is used.
2789 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2791 NSTRACE_RECT ("fromRect", fromRect);
2795 operation: NSCompositeSourceOver
2801 NSPoint pt = r.origin;
2803 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2812 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2813 int x, int y, enum text_cursor_kinds cursor_type,
2814 int cursor_width, bool on_p, bool active_p)
2815 /* --------------------------------------------------------------------------
2816 External call (RIF): draw cursor.
2817 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2818 -------------------------------------------------------------------------- */
2821 int fx, fy, h, cursor_height;
2822 struct frame *f = WINDOW_XFRAME (w);
2823 struct glyph *phys_cursor_glyph;
2824 struct glyph *cursor_glyph;
2826 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2828 /* If cursor is out of bounds, don't draw garbage. This can happen
2829 in mini-buffer windows when switching between echo area glyphs
2832 NSTRACE ("ns_draw_window_cursor");
2837 w->phys_cursor_type = cursor_type;
2838 w->phys_cursor_on_p = on_p;
2840 if (cursor_type == NO_CURSOR)
2842 w->phys_cursor_width = 0;
2846 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2848 if (glyph_row->exact_window_width_line_p
2849 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2851 glyph_row->cursor_in_fringe_p = 1;
2852 draw_fringe_bitmap (w, glyph_row, 0);
2857 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2858 (other terminals do it the other way round). We must set
2859 w->phys_cursor_width to the cursor width. For bar cursors, that
2860 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2861 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2863 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2864 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2865 if (cursor_type == BAR_CURSOR)
2867 if (cursor_width < 1)
2868 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2869 w->phys_cursor_width = cursor_width;
2871 /* If we have an HBAR, "cursor_width" MAY specify height. */
2872 else if (cursor_type == HBAR_CURSOR)
2874 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2875 if (cursor_height > glyph_row->height)
2876 cursor_height = glyph_row->height;
2877 if (h > cursor_height) // Cursor smaller than line height, move down
2878 fy += h - cursor_height;
2882 r.origin.x = fx, r.origin.y = fy;
2884 r.size.width = w->phys_cursor_width;
2886 /* TODO: only needed in rare cases with last-resort font in HELLO..
2887 should we do this more efficiently? */
2888 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2891 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2892 if (face && NS_FACE_BACKGROUND (face)
2893 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2895 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2896 hollow_color = FRAME_CURSOR_COLOR (f);
2899 [FRAME_CURSOR_COLOR (f) set];
2901 #ifdef NS_IMPL_COCOA
2902 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2903 atomic. Cleaner ways of doing this should be investigated.
2904 One way would be to set a global variable DRAWING_CURSOR
2905 when making the call to draw_phys..(), don't focus in that
2906 case, then move the ns_unfocus() here after that call. */
2907 NSDisableScreenUpdates ();
2910 switch (cursor_type)
2912 case DEFAULT_CURSOR:
2915 case FILLED_BOX_CURSOR:
2918 case HOLLOW_BOX_CURSOR:
2921 NSRectFill (NSInsetRect (r, 1, 1));
2922 [FRAME_CURSOR_COLOR (f) set];
2929 /* If the character under cursor is R2L, draw the bar cursor
2930 on the right of its glyph, rather than on the left. */
2931 cursor_glyph = get_phys_cursor_glyph (w);
2932 if ((cursor_glyph->resolved_level & 1) != 0)
2933 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2940 /* draw the character under the cursor */
2941 if (cursor_type != NO_CURSOR)
2942 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2944 #ifdef NS_IMPL_COCOA
2945 NSEnableScreenUpdates ();
2952 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2953 /* --------------------------------------------------------------------------
2954 External (RIF): Draw a vertical line.
2955 -------------------------------------------------------------------------- */
2957 struct frame *f = XFRAME (WINDOW_FRAME (w));
2959 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2961 NSTRACE ("ns_draw_vertical_window_border");
2963 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2965 [ns_lookup_indexed_color(face->foreground, f) set];
2967 ns_focus (f, &r, 1);
2974 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2975 /* --------------------------------------------------------------------------
2976 External (RIF): Draw a window divider.
2977 -------------------------------------------------------------------------- */
2979 struct frame *f = XFRAME (WINDOW_FRAME (w));
2981 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2983 NSTRACE ("ns_draw_window_divider");
2985 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2987 [ns_lookup_indexed_color(face->foreground, f) set];
2989 ns_focus (f, &r, 1);
2995 ns_show_hourglass (struct frame *f)
2997 /* TODO: add NSProgressIndicator to all frames. */
3001 ns_hide_hourglass (struct frame *f)
3003 /* TODO: remove NSProgressIndicator from all frames. */
3006 /* ==========================================================================
3008 Glyph drawing operations
3010 ========================================================================== */
3013 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3014 /* --------------------------------------------------------------------------
3015 Wrapper utility to account for internal border width on full-width lines,
3016 and allow top full-width rows to hit the frame top. nr should be pointer
3017 to two successive NSRects. Number of rects actually used is returned.
3018 -------------------------------------------------------------------------- */
3020 int n = get_glyph_string_clip_rects (s, nr, 2);
3024 /* --------------------------------------------------------------------
3025 Draw a wavy line under glyph string s. The wave fills wave_height
3032 wave_height = 3 | * * * *
3033 --------------------------------------------------------------------- */
3036 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3038 int wave_height = 3, wave_length = 2;
3039 int y, dx, dy, odd, xmax;
3044 dy = wave_height - 1;
3045 y = s->ybase - wave_height + 3;
3048 /* Find and set clipping rectangle */
3049 waveClip = NSMakeRect (x, y, width, wave_height);
3050 [[NSGraphicsContext currentContext] saveGraphicsState];
3051 NSRectClip (waveClip);
3053 /* Draw the waves */
3054 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3056 odd = (int)(a.x/dx) % 2;
3057 a.y = b.y = y + 0.5;
3066 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3067 a.x = b.x, a.y = b.y;
3068 b.x += dx, b.y = y + 0.5 + odd*dy;
3072 /* Restore previous clipping rectangle(s) */
3073 [[NSGraphicsContext currentContext] restoreGraphicsState];
3079 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3080 NSColor *defaultCol, CGFloat width, CGFloat x)
3081 /* --------------------------------------------------------------------------
3082 Draw underline, overline, and strike-through on glyph string s.
3083 -------------------------------------------------------------------------- */
3085 if (s->for_overlaps)
3089 if (face->underline_p)
3091 if (s->face->underline_type == FACE_UNDER_WAVE)
3093 if (face->underline_defaulted_p)
3096 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3098 ns_draw_underwave (s, width, x);
3100 else if (s->face->underline_type == FACE_UNDER_LINE)
3104 unsigned long thickness, position;
3106 /* If the prev was underlined, match its appearance. */
3107 if (s->prev && s->prev->face->underline_p
3108 && s->prev->face->underline_type == FACE_UNDER_LINE
3109 && s->prev->underline_thickness > 0)
3111 thickness = s->prev->underline_thickness;
3112 position = s->prev->underline_position;
3117 unsigned long descent;
3120 descent = s->y + s->height - s->ybase;
3122 /* Use underline thickness of font, defaulting to 1. */
3123 thickness = (font && font->underline_thickness > 0)
3124 ? font->underline_thickness : 1;
3126 /* Determine the offset of underlining from the baseline. */
3127 if (x_underline_at_descent_line)
3128 position = descent - thickness;
3129 else if (x_use_underline_position_properties
3130 && font && font->underline_position >= 0)
3131 position = font->underline_position;
3133 position = lround (font->descent / 2);
3135 position = underline_minimum_offset;
3137 position = max (position, underline_minimum_offset);
3139 /* Ensure underlining is not cropped. */
3140 if (descent <= position)
3142 position = descent - 1;
3145 else if (descent < position + thickness)
3149 s->underline_thickness = thickness;
3150 s->underline_position = position;
3152 r = NSMakeRect (x, s->ybase + position, width, thickness);
3154 if (face->underline_defaulted_p)
3157 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3161 /* Do overline. We follow other terms in using a thickness of 1
3162 and ignoring overline_margin. */
3163 if (face->overline_p)
3166 r = NSMakeRect (x, s->y, width, 1);
3168 if (face->overline_color_defaulted_p)
3171 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3175 /* Do strike-through. We follow other terms for thickness and
3176 vertical position.*/
3177 if (face->strike_through_p)
3182 dy = lrint ((s->height - 1) / 2);
3183 r = NSMakeRect (x, s->y + dy, width, 1);
3185 if (face->strike_through_color_defaulted_p)
3188 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3194 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3195 char left_p, char right_p)
3196 /* --------------------------------------------------------------------------
3197 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3198 Note we can't just use an NSDrawRect command, because of the possibility
3199 of some sides not being drawn, and because the rect will be filled.
3200 -------------------------------------------------------------------------- */
3206 s.size.height = thickness;
3208 s.origin.y += r.size.height - thickness;
3211 s.size.height = r.size.height;
3212 s.origin.y = r.origin.y;
3214 /* left, right (optional) */
3215 s.size.width = thickness;
3220 s.origin.x += r.size.width - thickness;
3227 ns_draw_relief (NSRect r, int thickness, char raised_p,
3228 char top_p, char bottom_p, char left_p, char right_p,
3229 struct glyph_string *s)
3230 /* --------------------------------------------------------------------------
3231 Draw a relief rect inside r, optionally leaving some sides open.
3232 Note we can't just use an NSDrawBezel command, because of the possibility
3233 of some sides not being drawn, and because the rect will be filled.
3234 -------------------------------------------------------------------------- */
3236 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3237 NSColor *newBaseCol = nil;
3240 NSTRACE ("ns_draw_relief");
3244 if (s->face->use_box_color_for_shadows_p)
3246 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3248 /* else if (s->first_glyph->type == IMAGE_GLYPH
3250 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3252 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3256 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3259 if (newBaseCol == nil)
3260 newBaseCol = [NSColor grayColor];
3262 if (newBaseCol != baseCol) /* TODO: better check */
3265 baseCol = [newBaseCol retain];
3267 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3269 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3272 [(raised_p ? lightCol : darkCol) set];
3274 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3277 sr.size.height = thickness;
3278 if (top_p) NSRectFill (sr);
3281 sr.size.height = r.size.height;
3282 sr.size.width = thickness;
3283 if (left_p) NSRectFill (sr);
3285 [(raised_p ? darkCol : lightCol) set];
3288 sr.size.width = r.size.width;
3289 sr.size.height = thickness;
3290 sr.origin.y += r.size.height - thickness;
3291 if (bottom_p) NSRectFill (sr);
3294 sr.size.height = r.size.height;
3295 sr.origin.y = r.origin.y;
3296 sr.size.width = thickness;
3297 sr.origin.x += r.size.width - thickness;
3298 if (right_p) NSRectFill (sr);
3303 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3304 /* --------------------------------------------------------------------------
3305 Function modeled after x_draw_glyph_string_box ().
3306 Sets up parameters for drawing.
3307 -------------------------------------------------------------------------- */
3309 int right_x, last_x;
3310 char left_p, right_p;
3311 struct glyph *last_glyph;
3316 if (s->hl == DRAW_MOUSE_FACE)
3318 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3320 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3325 thickness = face->box_line_width;
3327 NSTRACE ("ns_dumpglyphs_box_or_relief");
3329 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3330 ? WINDOW_RIGHT_EDGE_X (s->w)
3331 : window_box_right (s->w, s->area));
3332 last_glyph = (s->cmp || s->img
3333 ? s->first_glyph : s->first_glyph + s->nchars-1);
3335 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3336 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3338 left_p = (s->first_glyph->left_box_line_p
3339 || (s->hl == DRAW_MOUSE_FACE
3340 && (s->prev == NULL || s->prev->hl != s->hl)));
3341 right_p = (last_glyph->right_box_line_p
3342 || (s->hl == DRAW_MOUSE_FACE
3343 && (s->next == NULL || s->next->hl != s->hl)));
3345 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3347 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3348 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3350 ns_draw_box (r, abs (thickness),
3351 ns_lookup_indexed_color (face->box_color, s->f),
3356 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3357 1, 1, left_p, right_p, s);
3363 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3364 /* --------------------------------------------------------------------------
3365 Modeled after x_draw_glyph_string_background, which draws BG in
3366 certain cases. Others are left to the text rendering routine.
3367 -------------------------------------------------------------------------- */
3369 NSTRACE ("ns_maybe_dumpglyphs_background");
3371 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3373 int box_line_width = max (s->face->box_line_width, 0);
3374 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3375 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3376 dimensions, since the actual glyphs might be much
3377 smaller. So in that case we always clear the rectangle
3378 with background color. */
3379 || FONT_TOO_HIGH (s->font)
3380 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3383 if (s->hl == DRAW_MOUSE_FACE)
3385 face = FACE_FROM_ID (s->f,
3386 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3388 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3391 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3393 [(NS_FACE_BACKGROUND (face) != 0
3394 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3395 : FRAME_BACKGROUND_COLOR (s->f)) set];
3398 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3399 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3402 if (s->hl != DRAW_CURSOR)
3404 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3405 s->background_width,
3406 s->height-2*box_line_width);
3410 s->background_filled_p = 1;
3417 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3418 /* --------------------------------------------------------------------------
3419 Renders an image and associated borders.
3420 -------------------------------------------------------------------------- */
3422 EmacsImage *img = s->img->pixmap;
3423 int box_line_vwidth = max (s->face->box_line_width, 0);
3424 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3425 int bg_x, bg_y, bg_height;
3432 NSTRACE ("ns_dumpglyphs_image");
3434 if (s->face->box != FACE_NO_BOX
3435 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3436 x += abs (s->face->box_line_width);
3439 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3440 bg_height = s->height;
3441 /* other terms have this, but was causing problems w/tabbar mode */
3442 /* - 2 * box_line_vwidth; */
3444 if (s->slice.x == 0) x += s->img->hmargin;
3445 if (s->slice.y == 0) y += s->img->vmargin;
3447 /* Draw BG: if we need larger area than image itself cleared, do that,
3448 otherwise, since we composite the image under NS (instead of mucking
3449 with its background color), we must clear just the image area. */
3450 if (s->hl == DRAW_MOUSE_FACE)
3452 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3454 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3457 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3459 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3461 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3462 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3464 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3465 s->background_filled_p = 1;
3469 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3474 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3477 #ifdef NS_IMPL_COCOA
3478 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3479 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3480 s->slice.width, s->slice.height);
3483 operation: NSCompositeSourceOver
3488 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3489 operation: NSCompositeSourceOver];
3493 if (s->hl == DRAW_CURSOR)
3495 [FRAME_CURSOR_COLOR (s->f) set];
3496 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3497 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3499 /* Currently on NS img->mask is always 0. Since
3500 get_window_cursor_type specifies a hollow box cursor when on
3501 a non-masked image we never reach this clause. But we put it
3502 in in anticipation of better support for image masks on
3504 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3508 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3511 /* Draw underline, overline, strike-through. */
3512 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3514 /* Draw relief, if requested */
3515 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3517 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3519 th = tool_bar_button_relief >= 0 ?
3520 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3521 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3525 th = abs (s->img->relief);
3526 raised_p = (s->img->relief > 0);
3529 r.origin.x = x - th;
3530 r.origin.y = y - th;
3531 r.size.width = s->slice.width + 2*th-1;
3532 r.size.height = s->slice.height + 2*th-1;
3533 ns_draw_relief (r, th, raised_p,
3535 s->slice.y + s->slice.height == s->img->height,
3537 s->slice.x + s->slice.width == s->img->width, s);
3540 /* If there is no mask, the background won't be seen,
3541 so draw a rectangle on the image for the cursor.
3542 Do this for all images, getting transparency right is not reliable. */
3543 if (s->hl == DRAW_CURSOR)
3545 int thickness = abs (s->img->relief);
3546 if (thickness == 0) thickness = 1;
3547 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3553 ns_dumpglyphs_stretch (struct glyph_string *s)
3558 NSColor *fgCol, *bgCol;
3560 if (!s->background_filled_p)
3562 n = ns_get_glyph_string_clip_rect (s, r);
3563 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3565 ns_focus (s->f, r, n);
3567 if (s->hl == DRAW_MOUSE_FACE)
3569 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3571 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3574 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3576 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3577 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3579 for (i = 0; i < n; ++i)
3581 if (!s->row->full_width_p)
3583 int overrun, leftoverrun;
3585 /* truncate to avoid overwriting fringe and/or scrollbar */
3586 overrun = max (0, (s->x + s->background_width)
3587 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3588 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3589 r[i].size.width -= overrun;
3591 /* truncate to avoid overwriting to left of the window box */
3592 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3593 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3595 if (leftoverrun > 0)
3597 r[i].origin.x += leftoverrun;
3598 r[i].size.width -= leftoverrun;
3601 /* XXX: Try to work between problem where a stretch glyph on
3602 a partially-visible bottom row will clear part of the
3603 modeline, and another where list-buffers headers and similar
3604 rows erroneously have visible_height set to 0. Not sure
3605 where this is coming from as other terms seem not to show. */
3606 r[i].size.height = min (s->height, s->row->visible_height);
3611 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3612 overwriting cursor (usually when cursor on a tab) */
3613 if (s->hl == DRAW_CURSOR)
3618 width = s->w->phys_cursor_width;
3619 r[i].size.width -= width;
3620 r[i].origin.x += width;
3624 /* Draw overlining, etc. on the cursor. */
3625 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3626 ns_draw_text_decoration (s, face, bgCol, width, x);
3628 ns_draw_text_decoration (s, face, fgCol, width, x);
3635 /* Draw overlining, etc. on the stretch glyph (or the part
3636 of the stretch glyph after the cursor). */
3637 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3641 s->background_filled_p = 1;
3647 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3650 struct font *font = s->font;
3652 /* If first glyph of S has a left box line, start drawing the text
3653 of S to the right of that box line. */
3654 if (s->face && s->face->box != FACE_NO_BOX
3655 && s->first_glyph->left_box_line_p)
3656 x = s->x + eabs (s->face->box_line_width);
3660 /* S is a glyph string for a composition. S->cmp_from is the index
3661 of the first character drawn for glyphs of this composition.
3662 S->cmp_from == 0 means we are drawing the very first character of
3663 this composition. */
3665 /* Draw a rectangle for the composition if the font for the very
3666 first character of the composition could not be loaded. */
3667 if (s->font_not_found_p)
3669 if (s->cmp_from == 0)
3671 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3672 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3675 else if (! s->first_glyph->u.cmp.automatic)
3679 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3680 /* TAB in a composition means display glyphs with padding
3681 space on the left or right. */
3682 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3684 int xx = x + s->cmp->offsets[j * 2];
3685 int yy = y - s->cmp->offsets[j * 2 + 1];
3687 font->driver->draw (s, j, j + 1, xx, yy, false);
3688 if (s->face->overstrike)
3689 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3694 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3699 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3701 glyph = LGSTRING_GLYPH (gstring, i);
3702 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3703 width += LGLYPH_WIDTH (glyph);
3706 int xoff, yoff, wadjust;
3710 font->driver->draw (s, j, i, x, y, false);
3711 if (s->face->overstrike)
3712 font->driver->draw (s, j, i, x + 1, y, false);
3715 xoff = LGLYPH_XOFF (glyph);
3716 yoff = LGLYPH_YOFF (glyph);
3717 wadjust = LGLYPH_WADJUST (glyph);
3718 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3719 if (s->face->overstrike)
3720 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3729 font->driver->draw (s, j, i, x, y, false);
3730 if (s->face->overstrike)
3731 font->driver->draw (s, j, i, x + 1, y, false);
3737 ns_draw_glyph_string (struct glyph_string *s)
3738 /* --------------------------------------------------------------------------
3739 External (RIF): Main draw-text call.
3740 -------------------------------------------------------------------------- */
3742 /* TODO (optimize): focus for box and contents draw */
3745 char box_drawn_p = 0;
3746 struct font *font = s->face->font;
3747 if (! font) font = FRAME_FONT (s->f);
3749 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3751 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3754 struct glyph_string *next;
3756 for (width = 0, next = s->next;
3757 next && width < s->right_overhang;
3758 width += next->width, next = next->next)
3759 if (next->first_glyph->type != IMAGE_GLYPH)
3761 if (next->first_glyph->type != STRETCH_GLYPH)
3763 n = ns_get_glyph_string_clip_rect (s->next, r);
3764 ns_focus (s->f, r, n);
3765 ns_maybe_dumpglyphs_background (s->next, 1);
3770 ns_dumpglyphs_stretch (s->next);
3772 next->num_clips = 0;
3776 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3777 && (s->first_glyph->type == CHAR_GLYPH
3778 || s->first_glyph->type == COMPOSITE_GLYPH))
3780 n = ns_get_glyph_string_clip_rect (s, r);
3781 ns_focus (s->f, r, n);
3782 ns_maybe_dumpglyphs_background (s, 1);
3783 ns_dumpglyphs_box_or_relief (s);
3788 switch (s->first_glyph->type)
3792 n = ns_get_glyph_string_clip_rect (s, r);
3793 ns_focus (s->f, r, n);
3794 ns_dumpglyphs_image (s, r[0]);
3799 ns_dumpglyphs_stretch (s);
3803 case COMPOSITE_GLYPH:
3804 n = ns_get_glyph_string_clip_rect (s, r);
3805 ns_focus (s->f, r, n);
3807 if (s->for_overlaps || (s->cmp_from > 0
3808 && ! s->first_glyph->u.cmp.automatic))
3809 s->background_filled_p = 1;
3811 ns_maybe_dumpglyphs_background
3812 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3814 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3815 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3816 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3817 NS_DUMPGLYPH_NORMAL));
3819 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3821 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3822 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3823 NS_FACE_FOREGROUND (s->face) = tmp;
3827 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3830 ns_draw_composite_glyph_string_foreground (s);
3833 (s, s->cmp_from, s->nchars, s->x, s->ybase,
3834 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3835 || flags == NS_DUMPGLYPH_MOUSEFACE);
3839 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3840 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3842 : FRAME_FOREGROUND_COLOR (s->f));
3845 /* Draw underline, overline, strike-through. */
3846 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3849 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3851 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3852 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3853 NS_FACE_FOREGROUND (s->face) = tmp;
3859 case GLYPHLESS_GLYPH:
3860 n = ns_get_glyph_string_clip_rect (s, r);
3861 ns_focus (s->f, r, n);
3863 if (s->for_overlaps || (s->cmp_from > 0
3864 && ! s->first_glyph->u.cmp.automatic))
3865 s->background_filled_p = 1;
3867 ns_maybe_dumpglyphs_background
3868 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3870 /* Not yet implemented. */
3879 /* Draw box if not done already. */
3880 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3882 n = ns_get_glyph_string_clip_rect (s, r);
3883 ns_focus (s->f, r, n);
3884 ns_dumpglyphs_box_or_relief (s);
3893 /* ==========================================================================
3897 ========================================================================== */
3901 ns_send_appdefined (int value)
3902 /* --------------------------------------------------------------------------
3903 Internal: post an appdefined event which EmacsApp-sendEvent will
3904 recognize and take as a command to halt the event loop.
3905 -------------------------------------------------------------------------- */
3907 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3909 #ifdef NS_IMPL_GNUSTEP
3910 // GNUstep needs postEvent to happen on the main thread.
3911 if (! [[NSThread currentThread] isMainThread])
3913 EmacsApp *app = (EmacsApp *)NSApp;
3914 app->nextappdefined = value;
3915 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3922 /* Only post this event if we haven't already posted one. This will end
3923 the [NXApp run] main loop after having processed all events queued at
3926 #ifdef NS_IMPL_COCOA
3927 if (! send_appdefined)
3929 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3930 in certain situations (rapid incoming events).
3931 So check if we have one, if not add one. */
3932 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3933 untilDate:[NSDate distantPast]
3934 inMode:NSDefaultRunLoopMode
3936 if (! appev) send_appdefined = YES;
3940 if (send_appdefined)
3944 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3945 send_appdefined = NO;
3947 /* Don't need wakeup timer any more */
3950 [timed_entry invalidate];
3951 [timed_entry release];
3955 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3956 location: NSMakePoint (0, 0)
3959 windowNumber: [[NSApp mainWindow] windowNumber]
3960 context: [NSApp context]
3965 /* Post an application defined event on the event queue. When this is
3966 received the [NXApp run] will return, thus having processed all
3967 events which are currently queued. */
3968 [NSApp postEvent: nxev atStart: NO];
3972 #ifdef HAVE_NATIVE_FS
3976 Lisp_Object frame, tail;
3978 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3981 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3983 FOR_EACH_FRAME (tail, frame)
3985 struct frame *f = XFRAME (frame);
3988 EmacsView *view = FRAME_NS_VIEW (f);
3989 [view updateCollectionBehavior];
3995 /* GNUstep does not have cancelTracking. */
3996 #ifdef NS_IMPL_COCOA
3997 /* Check if menu open should be canceled or continued as normal. */
3999 ns_check_menu_open (NSMenu *menu)
4001 /* Click in menu bar? */
4002 NSArray *a = [[NSApp mainMenu] itemArray];
4006 if (menu == nil) // Menu tracking ended.
4008 if (menu_will_open_state == MENU_OPENING)
4009 menu_will_open_state = MENU_NONE;
4013 for (i = 0; ! found && i < [a count]; i++)
4014 found = menu == [[a objectAtIndex:i] submenu];
4017 if (menu_will_open_state == MENU_NONE && emacs_event)
4019 NSEvent *theEvent = [NSApp currentEvent];
4020 struct frame *emacsframe = SELECTED_FRAME ();
4022 [menu cancelTracking];
4023 menu_will_open_state = MENU_PENDING;
4024 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4025 EV_TRAILER (theEvent);
4027 CGEventRef ourEvent = CGEventCreate (NULL);
4028 menu_mouse_point = CGEventGetLocation (ourEvent);
4029 CFRelease (ourEvent);
4031 else if (menu_will_open_state == MENU_OPENING)
4033 menu_will_open_state = MENU_NONE;
4038 /* Redo saved menu click if state is MENU_PENDING. */
4040 ns_check_pending_open_menu ()
4042 if (menu_will_open_state == MENU_PENDING)
4044 CGEventSourceRef source
4045 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4047 CGEventRef event = CGEventCreateMouseEvent (source,
4048 kCGEventLeftMouseDown,
4050 kCGMouseButtonLeft);
4051 CGEventSetType (event, kCGEventLeftMouseDown);
4052 CGEventPost (kCGHIDEventTap, event);
4056 menu_will_open_state = MENU_OPENING;
4059 #endif /* NS_IMPL_COCOA */
4062 unwind_apploopnr (Lisp_Object not_used)
4065 n_emacs_events_pending = 0;
4066 ns_finish_events ();
4071 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4072 /* --------------------------------------------------------------------------
4073 External (hook): Post an event to ourself and keep reading events until
4074 we read it back again. In effect process all events which were waiting.
4075 From 21+ we have to manage the event buffer ourselves.
4076 -------------------------------------------------------------------------- */
4078 struct input_event ev;
4081 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4083 #ifdef HAVE_NATIVE_FS
4087 if ([NSApp modalWindow] != nil)
4090 if (hold_event_q.nr > 0)
4093 for (i = 0; i < hold_event_q.nr; ++i)
4094 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4095 hold_event_q.nr = 0;
4100 n_emacs_events_pending = 0;
4101 ns_init_events (&ev);
4102 q_event_ptr = hold_quit;
4104 /* we manage autorelease pools by allocate/reallocate each time around
4105 the loop; strict nesting is occasionally violated but seems not to
4106 matter.. earlier methods using full nesting caused major memory leaks */
4107 [outerpool release];
4108 outerpool = [[NSAutoreleasePool alloc] init];
4110 /* If have pending open-file requests, attend to the next one of those. */
4111 if (ns_pending_files && [ns_pending_files count] != 0
4112 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4114 [ns_pending_files removeObjectAtIndex: 0];
4116 /* Deal with pending service requests. */
4117 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4119 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4120 withArg: [ns_pending_service_args objectAtIndex: 0]])
4122 [ns_pending_service_names removeObjectAtIndex: 0];
4123 [ns_pending_service_args removeObjectAtIndex: 0];
4127 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4128 /* Run and wait for events. We must always send one NX_APPDEFINED event
4129 to ourself, otherwise [NXApp run] will never exit. */
4130 send_appdefined = YES;
4131 ns_send_appdefined (-1);
4133 if (++apploopnr != 1)
4137 record_unwind_protect (unwind_apploopnr, Qt);
4139 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4142 nevents = n_emacs_events_pending;
4143 n_emacs_events_pending = 0;
4144 ns_finish_events ();
4153 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4154 fd_set *exceptfds, struct timespec const *timeout,
4155 sigset_t const *sigmask)
4156 /* --------------------------------------------------------------------------
4157 Replacement for select, checking for events
4158 -------------------------------------------------------------------------- */
4162 struct input_event event;
4165 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4167 #ifdef HAVE_NATIVE_FS
4171 if (hold_event_q.nr > 0)
4173 /* We already have events pending. */
4179 for (k = 0; k < nfds+1; k++)
4181 if (readfds && FD_ISSET(k, readfds)) ++nr;
4182 if (writefds && FD_ISSET(k, writefds)) ++nr;
4186 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4187 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4189 [outerpool release];
4190 outerpool = [[NSAutoreleasePool alloc] init];
4193 send_appdefined = YES;
4196 pthread_mutex_lock (&select_mutex);
4201 select_readfds = *readfds;
4202 select_valid += SELECT_HAVE_READ;
4206 select_writefds = *writefds;
4207 select_valid += SELECT_HAVE_WRITE;
4212 select_timeout = *timeout;
4213 select_valid += SELECT_HAVE_TMO;
4216 pthread_mutex_unlock (&select_mutex);
4218 /* Inform fd_handler that select should be called */
4220 emacs_write_sig (selfds[1], &c, 1);
4222 else if (nr == 0 && timeout)
4224 /* No file descriptor, just a timeout, no need to wake fd_handler */
4225 double time = timespectod (*timeout);
4226 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4229 @selector (timeout_handler:)
4234 else /* No timeout and no file descriptors, can this happen? */
4236 /* Send appdefined so we exit from the loop */
4237 ns_send_appdefined (-1);
4241 ns_init_events (&event);
4242 if (++apploopnr != 1)
4248 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4249 record_unwind_protect (unwind_apploopnr, Qt);
4251 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
4254 ns_finish_events ();
4255 if (nr > 0 && readfds)
4258 emacs_write_sig (selfds[1], &c, 1);
4262 t = last_appdefined_event_data;
4264 if (t != NO_APPDEFINED_DATA)
4266 last_appdefined_event_data = NO_APPDEFINED_DATA;
4270 /* The NX_APPDEFINED event we received was a timeout. */
4275 /* The NX_APPDEFINED event we received was the result of
4276 at least one real input event arriving. */
4282 /* Received back from select () in fd_handler; copy the results */
4283 pthread_mutex_lock (&select_mutex);
4284 if (readfds) *readfds = select_readfds;
4285 if (writefds) *writefds = select_writefds;
4286 pthread_mutex_unlock (&select_mutex);
4301 /* ==========================================================================
4305 ========================================================================== */
4309 ns_set_vertical_scroll_bar (struct window *window,
4310 int portion, int whole, int position)
4311 /* --------------------------------------------------------------------------
4312 External (hook): Update or add scrollbar
4313 -------------------------------------------------------------------------- */
4317 struct frame *f = XFRAME (WINDOW_FRAME (window));
4318 EmacsView *view = FRAME_NS_VIEW (f);
4320 int window_y, window_height;
4321 int top, left, height, width;
4322 BOOL update_p = YES;
4324 /* optimization; display engine sends WAY too many of these.. */
4325 if (!NILP (window->vertical_scroll_bar))
4327 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4328 if ([bar checkSamePosition: position portion: portion whole: whole])
4330 if (view->scrollbarsNeedingUpdate == 0)
4332 if (!windows_or_buffers_changed)
4336 view->scrollbarsNeedingUpdate--;
4341 NSTRACE ("ns_set_vertical_scroll_bar");
4343 /* Get dimensions. */
4344 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4346 height = window_height;
4347 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4348 left = WINDOW_SCROLL_BAR_AREA_X (window);
4350 r = NSMakeRect (left, top, width, height);
4351 /* the parent view is flipped, so we need to flip y value */
4353 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4355 XSETWINDOW (win, window);
4358 /* we want at least 5 lines to display a scrollbar */
4359 if (WINDOW_TOTAL_LINES (window) < 5)
4361 if (!NILP (window->vertical_scroll_bar))
4363 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4364 [bar removeFromSuperview];
4365 wset_vertical_scroll_bar (window, Qnil);
4368 ns_clear_frame_area (f, left, top, width, height);
4373 if (NILP (window->vertical_scroll_bar))
4375 if (width > 0 && height > 0)
4376 ns_clear_frame_area (f, left, top, width, height);
4378 bar = [[EmacsScroller alloc] initFrame: r window: win];
4379 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4385 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4386 oldRect = [bar frame];
4387 r.size.width = oldRect.size.width;
4388 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4390 if (oldRect.origin.x != r.origin.x)
4391 ns_clear_frame_area (f, left, top, width, height);
4397 [bar setPosition: position portion: portion whole: whole];
4403 ns_set_horizontal_scroll_bar (struct window *window,
4404 int portion, int whole, int position)
4405 /* --------------------------------------------------------------------------
4406 External (hook): Update or add scrollbar
4407 -------------------------------------------------------------------------- */
4411 struct frame *f = XFRAME (WINDOW_FRAME (window));
4412 EmacsView *view = FRAME_NS_VIEW (f);
4414 int top, height, left, width;
4415 int window_x, window_width;
4416 BOOL update_p = YES;
4418 /* optimization; display engine sends WAY too many of these.. */
4419 if (!NILP (window->horizontal_scroll_bar))
4421 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4422 if ([bar checkSamePosition: position portion: portion whole: whole])
4424 if (view->scrollbarsNeedingUpdate == 0)
4426 if (!windows_or_buffers_changed)
4430 view->scrollbarsNeedingUpdate--;
4435 NSTRACE ("ns_set_horizontal_scroll_bar");
4437 /* Get dimensions. */
4438 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4440 width = window_width;
4441 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4442 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4444 r = NSMakeRect (left, top, width, height);
4445 /* the parent view is flipped, so we need to flip y value */
4447 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4448 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4450 XSETWINDOW (win, window);
4453 if (WINDOW_TOTAL_COLS (window) < 5)
4455 if (!NILP (window->horizontal_scroll_bar))
4457 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4458 [bar removeFromSuperview];
4459 wset_horizontal_scroll_bar (window, Qnil);
4461 ns_clear_frame_area (f, left, top, width, height);
4466 if (NILP (window->horizontal_scroll_bar))
4468 if (width > 0 && height > 0)
4469 ns_clear_frame_area (f, left, top, width, height);
4471 bar = [[EmacsScroller alloc] initFrame: r window: win];
4472 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4478 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4479 oldRect = [bar frame];
4480 r.size.width = oldRect.size.width;
4481 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4483 if (oldRect.origin.x != r.origin.x)
4484 ns_clear_frame_area (f, left, top, width, height);
4491 [bar setPosition: position portion: portion whole: whole];
4497 ns_condemn_scroll_bars (struct frame *f)
4498 /* --------------------------------------------------------------------------
4499 External (hook): arrange for all frame's scrollbars to be removed
4500 at next call to judge_scroll_bars, except for those redeemed.
4501 -------------------------------------------------------------------------- */
4505 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4507 NSTRACE ("ns_condemn_scroll_bars");
4509 for (i =[subviews count]-1; i >= 0; i--)
4511 view = [subviews objectAtIndex: i];
4512 if ([view isKindOfClass: [EmacsScroller class]])
4519 ns_redeem_scroll_bar (struct window *window)
4520 /* --------------------------------------------------------------------------
4521 External (hook): arrange to spare this window's scrollbar
4522 at next call to judge_scroll_bars.
4523 -------------------------------------------------------------------------- */
4526 NSTRACE ("ns_redeem_scroll_bar");
4527 if (!NILP (window->vertical_scroll_bar))
4529 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4533 if (!NILP (window->horizontal_scroll_bar))
4535 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4542 ns_judge_scroll_bars (struct frame *f)
4543 /* --------------------------------------------------------------------------
4544 External (hook): destroy all scrollbars on frame that weren't
4545 redeemed after call to condemn_scroll_bars.
4546 -------------------------------------------------------------------------- */
4550 EmacsView *eview = FRAME_NS_VIEW (f);
4551 NSArray *subviews = [[eview superview] subviews];
4554 NSTRACE ("ns_judge_scroll_bars");
4555 for (i = [subviews count]-1; i >= 0; --i)
4557 view = [subviews objectAtIndex: i];
4558 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4564 [eview updateFrameSize: NO];
4567 /* ==========================================================================
4571 ========================================================================== */
4574 x_display_pixel_height (struct ns_display_info *dpyinfo)
4576 NSArray *screens = [NSScreen screens];
4577 NSEnumerator *enumerator = [screens objectEnumerator];
4582 while ((screen = [enumerator nextObject]) != nil)
4583 frame = NSUnionRect (frame, [screen frame]);
4585 return NSHeight (frame);
4589 x_display_pixel_width (struct ns_display_info *dpyinfo)
4591 NSArray *screens = [NSScreen screens];
4592 NSEnumerator *enumerator = [screens objectEnumerator];
4597 while ((screen = [enumerator nextObject]) != nil)
4598 frame = NSUnionRect (frame, [screen frame]);
4600 return NSWidth (frame);
4604 static Lisp_Object ns_string_to_lispmod (const char *s)
4605 /* --------------------------------------------------------------------------
4606 Convert modifier name to lisp symbol
4607 -------------------------------------------------------------------------- */
4609 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4611 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4613 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4615 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4617 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4619 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4627 ns_default (const char *parameter, Lisp_Object *result,
4628 Lisp_Object yesval, Lisp_Object noval,
4629 BOOL is_float, BOOL is_modstring)
4630 /* --------------------------------------------------------------------------
4631 Check a parameter value in user's preferences
4632 -------------------------------------------------------------------------- */
4634 const char *value = ns_get_defaults_value (parameter);
4640 if (c_strcasecmp (value, "YES") == 0)
4642 else if (c_strcasecmp (value, "NO") == 0)
4644 else if (is_float && (f = strtod (value, &pos), pos != value))
4645 *result = make_float (f);
4646 else if (is_modstring && value)
4647 *result = ns_string_to_lispmod (value);
4648 else fprintf (stderr,
4649 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4655 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4656 /* --------------------------------------------------------------------------
4657 Initialize global info and storage for display.
4658 -------------------------------------------------------------------------- */
4660 NSScreen *screen = [NSScreen mainScreen];
4661 NSWindowDepth depth = [screen depth];
4663 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4664 dpyinfo->resy = 72.27;
4665 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4666 NSColorSpaceFromDepth (depth)]
4667 && ![NSCalibratedWhiteColorSpace isEqualToString:
4668 NSColorSpaceFromDepth (depth)];
4669 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4670 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4671 dpyinfo->color_table->colors = NULL;
4672 dpyinfo->root_window = 42; /* a placeholder.. */
4673 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4674 dpyinfo->n_fonts = 0;
4675 dpyinfo->smallest_font_height = 1;
4676 dpyinfo->smallest_char_width = 1;
4678 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4682 /* This and next define (many of the) public functions in this file. */
4683 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4684 with using despite presence in the "system dependent" redisplay
4685 interface. In addition, many of the ns_ methods have code that is
4686 shared with all terms, indicating need for further refactoring. */
4687 extern frame_parm_handler ns_frame_parm_handlers[];
4688 static struct redisplay_interface ns_redisplay_interface =
4690 ns_frame_parm_handlers,
4694 x_clear_end_of_line,
4696 ns_after_update_window_line,
4697 ns_update_window_begin,
4698 ns_update_window_end,
4699 0, /* flush_display */
4700 x_clear_window_mouse_face,
4701 x_get_glyph_overhangs,
4702 x_fix_overlapping_area,
4703 ns_draw_fringe_bitmap,
4704 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4705 0, /* destroy_fringe_bitmap */
4706 ns_compute_glyph_string_overhangs,
4707 ns_draw_glyph_string,
4708 ns_define_frame_cursor,
4709 ns_clear_frame_area,
4710 ns_draw_window_cursor,
4711 ns_draw_vertical_window_border,
4712 ns_draw_window_divider,
4713 ns_shift_glyphs_for_insert,
4720 ns_delete_display (struct ns_display_info *dpyinfo)
4726 /* This function is called when the last frame on a display is deleted. */
4728 ns_delete_terminal (struct terminal *terminal)
4730 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4732 NSTRACE ("ns_delete_terminal");
4734 /* Protect against recursive calls. delete_frame in
4735 delete_terminal calls us back when it deletes our last frame. */
4736 if (!terminal->name)
4741 x_destroy_all_bitmaps (dpyinfo);
4742 ns_delete_display (dpyinfo);
4747 static struct terminal *
4748 ns_create_terminal (struct ns_display_info *dpyinfo)
4749 /* --------------------------------------------------------------------------
4750 Set up use of NS before we make the first connection.
4751 -------------------------------------------------------------------------- */
4753 struct terminal *terminal;
4755 NSTRACE ("ns_create_terminal");
4757 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4759 terminal->display_info.ns = dpyinfo;
4760 dpyinfo->terminal = terminal;
4762 terminal->clear_frame_hook = ns_clear_frame;
4763 terminal->ring_bell_hook = ns_ring_bell;
4764 terminal->update_begin_hook = ns_update_begin;
4765 terminal->update_end_hook = ns_update_end;
4766 terminal->read_socket_hook = ns_read_socket;
4767 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4768 terminal->mouse_position_hook = ns_mouse_position;
4769 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4770 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4771 terminal->fullscreen_hook = ns_fullscreen_hook;
4772 terminal->menu_show_hook = ns_menu_show;
4773 terminal->popup_dialog_hook = ns_popup_dialog;
4774 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4775 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4776 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4777 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4778 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4779 terminal->delete_frame_hook = x_destroy_window;
4780 terminal->delete_terminal_hook = ns_delete_terminal;
4781 /* Other hooks are NULL by default. */
4787 struct ns_display_info *
4788 ns_term_init (Lisp_Object display_name)
4789 /* --------------------------------------------------------------------------
4790 Start the Application and get things rolling.
4791 -------------------------------------------------------------------------- */
4793 struct terminal *terminal;
4794 struct ns_display_info *dpyinfo;
4795 static int ns_initialized = 0;
4798 if (ns_initialized) return x_display_list;
4803 NSTRACE ("ns_term_init");
4805 [outerpool release];
4806 outerpool = [[NSAutoreleasePool alloc] init];
4808 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4809 /*GSDebugAllocationActive (YES); */
4813 Fset_input_interrupt_mode (Qnil);
4815 if (selfds[0] == -1)
4817 if (emacs_pipe (selfds) != 0)
4819 fprintf (stderr, "Failed to create pipe: %s\n",
4820 emacs_strerror (errno));
4824 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4825 FD_ZERO (&select_readfds);
4826 FD_ZERO (&select_writefds);
4827 pthread_mutex_init (&select_mutex, NULL);
4830 ns_pending_files = [[NSMutableArray alloc] init];
4831 ns_pending_service_names = [[NSMutableArray alloc] init];
4832 ns_pending_service_args = [[NSMutableArray alloc] init];
4834 /* Start app and create the main menu, window, view.
4835 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4836 The view will then ask the NSApp to stop and return to Emacs. */
4837 [EmacsApp sharedApplication];
4840 [NSApp setDelegate: NSApp];
4842 /* Start the select thread. */
4843 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4847 /* debugging: log all notifications */
4848 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4849 selector: @selector (logNotification:)
4850 name: nil object: nil]; */
4852 dpyinfo = xzalloc (sizeof *dpyinfo);
4854 ns_initialize_display_info (dpyinfo);
4855 terminal = ns_create_terminal (dpyinfo);
4857 terminal->kboard = allocate_kboard (Qns);
4858 /* Don't let the initial kboard remain current longer than necessary.
4859 That would cause problems if a file loaded on startup tries to
4860 prompt in the mini-buffer. */
4861 if (current_kboard == initial_kboard)
4862 current_kboard = terminal->kboard;
4863 terminal->kboard->reference_count++;
4865 dpyinfo->next = x_display_list;
4866 x_display_list = dpyinfo;
4868 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4870 terminal->name = xlispstrdup (display_name);
4874 if (!inhibit_x_resources)
4876 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4879 /* this is a standard variable */
4880 ns_default ("AppleAntiAliasingThreshold", &tmp,
4881 make_float (10.0), make_float (6.0), YES, NO);
4882 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4885 NSTRACE_MSG ("Colors");
4888 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4892 Lisp_Object color_file, color_map, color;
4896 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4897 Fsymbol_value (intern ("data-directory")));
4899 color_map = Fx_load_color_file (color_file);
4900 if (NILP (color_map))
4901 fatal ("Could not read %s.\n", SDATA (color_file));
4903 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4904 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4906 color = XCAR (color_map);
4907 name = SSDATA (XCAR (color));
4908 c = XINT (XCDR (color));
4910 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4911 green: GREEN_FROM_ULONG (c) / 255.0
4912 blue: BLUE_FROM_ULONG (c) / 255.0
4914 forKey: [NSString stringWithUTF8String: name]];
4916 [cl writeToFile: nil];
4920 NSTRACE_MSG ("Versions");
4923 #ifdef NS_IMPL_GNUSTEP
4924 Vwindow_system_version = build_string (gnustep_base_version);
4926 /*PSnextrelease (128, c); */
4927 char c[DBL_BUFSIZE_BOUND];
4928 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4929 Vwindow_system_version = make_unibyte_string (c, len);
4933 delete_keyboard_wait_descriptor (0);
4935 ns_app_name = [[NSProcessInfo processInfo] processName];
4937 /* Set up OS X app menu */
4939 NSTRACE_MSG ("Menu init");
4941 #ifdef NS_IMPL_COCOA
4945 /* set up the application menu */
4946 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4947 [svcsMenu setAutoenablesItems: NO];
4948 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4949 [appMenu setAutoenablesItems: NO];
4950 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4951 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4953 [appMenu insertItemWithTitle: @"About Emacs"
4954 action: @selector (orderFrontStandardAboutPanel:)
4957 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4958 [appMenu insertItemWithTitle: @"Preferences..."
4959 action: @selector (showPreferencesWindow:)
4962 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4963 item = [appMenu insertItemWithTitle: @"Services"
4964 action: @selector (menuDown:)
4967 [appMenu setSubmenu: svcsMenu forItem: item];
4968 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4969 [appMenu insertItemWithTitle: @"Hide Emacs"
4970 action: @selector (hide:)
4973 item = [appMenu insertItemWithTitle: @"Hide Others"
4974 action: @selector (hideOtherApplications:)
4977 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4978 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4979 [appMenu insertItemWithTitle: @"Quit Emacs"
4980 action: @selector (terminate:)
4984 item = [mainMenu insertItemWithTitle: ns_app_name
4985 action: @selector (menuDown:)
4988 [mainMenu setSubmenu: appMenu forItem: item];
4989 [dockMenu insertItemWithTitle: @"New Frame"
4990 action: @selector (newFrame:)
4994 [NSApp setMainMenu: mainMenu];
4995 [NSApp setAppleMenu: appMenu];
4996 [NSApp setServicesMenu: svcsMenu];
4997 /* Needed at least on Cocoa, to get dock menu to show windows */
4998 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5000 [[NSNotificationCenter defaultCenter]
5001 addObserver: mainMenu
5002 selector: @selector (trackingNotification:)
5003 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5004 [[NSNotificationCenter defaultCenter]
5005 addObserver: mainMenu
5006 selector: @selector (trackingNotification:)
5007 name: NSMenuDidEndTrackingNotification object: mainMenu];
5009 #endif /* MAC OS X menu setup */
5011 /* Register our external input/output types, used for determining
5012 applicable services and also drag/drop eligibility. */
5014 NSTRACE_MSG ("Input/output types");
5016 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5017 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5019 ns_drag_types = [[NSArray arrayWithObjects:
5021 NSTabularTextPboardType,
5022 NSFilenamesPboardType,
5023 NSURLPboardType, nil] retain];
5025 /* If fullscreen is in init/default-frame-alist, focus isn't set
5026 right for fullscreen windows, so set this. */
5027 [NSApp activateIgnoringOtherApps:YES];
5029 NSTRACE_MSG ("Call NSApp run");
5032 ns_do_open_file = YES;
5034 #ifdef NS_IMPL_GNUSTEP
5035 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5036 We must re-catch it so subprocess works. */
5037 catch_child_signal ();
5040 NSTRACE_MSG ("ns_term_init done");
5049 ns_term_shutdown (int sig)
5051 [[NSUserDefaults standardUserDefaults] synchronize];
5053 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5054 if (STRINGP (Vauto_save_list_file_name))
5055 unlink (SSDATA (Vauto_save_list_file_name));
5057 if (sig == 0 || sig == SIGTERM)
5059 [NSApp terminate: NSApp];
5061 else // force a stack trace to happen
5068 /* ==========================================================================
5070 EmacsApp implementation
5072 ========================================================================== */
5075 @implementation EmacsApp
5079 NSTRACE ("[EmacsApp init]");
5081 if ((self = [super init]))
5083 #ifdef NS_IMPL_COCOA
5084 self->isFirst = YES;
5086 #ifdef NS_IMPL_GNUSTEP
5087 self->applicationDidFinishLaunchingCalled = NO;
5094 #ifdef NS_IMPL_COCOA
5097 NSTRACE ("[EmacsApp run]");
5099 #ifndef NSAppKitVersionNumber10_9
5100 #define NSAppKitVersionNumber10_9 1265
5103 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5109 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5111 if (isFirst) [self finishLaunching];
5114 shouldKeepRunning = YES;
5118 pool = [[NSAutoreleasePool alloc] init];
5121 [self nextEventMatchingMask:NSAnyEventMask
5122 untilDate:[NSDate distantFuture]
5123 inMode:NSDefaultRunLoopMode
5126 [self sendEvent:event];
5127 [self updateWindows];
5128 } while (shouldKeepRunning);
5133 - (void)stop: (id)sender
5135 NSTRACE ("[EmacsApp stop:]");
5137 shouldKeepRunning = NO;
5138 // Stop possible dialog also. Noop if no dialog present.
5139 // The file dialog still leaks 7k - 10k on 10.9 though.
5140 [super stop:sender];
5142 #endif /* NS_IMPL_COCOA */
5144 - (void)logNotification: (NSNotification *)notification
5146 NSTRACE ("[EmacsApp logNotification:]");
5148 const char *name = [[notification name] UTF8String];
5149 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5150 && !strstr (name, "WindowNumber"))
5151 NSLog (@"notification: '%@'", [notification name]);
5155 - (void)sendEvent: (NSEvent *)theEvent
5156 /* --------------------------------------------------------------------------
5157 Called when NSApp is running for each event received. Used to stop
5158 the loop when we choose, since there's no way to just run one iteration.
5159 -------------------------------------------------------------------------- */
5161 int type = [theEvent type];
5162 NSWindow *window = [theEvent window];
5164 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5165 NSTRACE_MSG ("Type: %d", type);
5167 #ifdef NS_IMPL_GNUSTEP
5168 // Keyboard events aren't propagated to file dialogs for some reason.
5169 if ([NSApp modalWindow] != nil &&
5170 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5172 [[NSApp modalWindow] sendEvent: theEvent];
5177 if (represented_filename != nil && represented_frame)
5179 NSString *fstr = represented_filename;
5180 NSView *view = FRAME_NS_VIEW (represented_frame);
5181 #ifdef NS_IMPL_COCOA
5182 /* work around a bug observed on 10.3 and later where
5183 setTitleWithRepresentedFilename does not clear out previous state
5184 if given filename does not exist */
5185 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5186 [[view window] setRepresentedFilename: @""];
5188 [[view window] setRepresentedFilename: fstr];
5189 [represented_filename release];
5190 represented_filename = nil;
5191 represented_frame = NULL;
5194 if (type == NSApplicationDefined)
5196 switch ([theEvent data2])
5198 #ifdef NS_IMPL_COCOA
5199 case NSAPP_DATA2_RUNASSCRIPT:
5204 case NSAPP_DATA2_RUNFILEDIALOG:
5205 ns_run_file_dialog ();
5211 if (type == NSCursorUpdate && window == nil)
5213 fprintf (stderr, "Dropping external cursor update event.\n");
5217 if (type == NSApplicationDefined)
5219 /* Events posted by ns_send_appdefined interrupt the run loop here.
5220 But, if a modal window is up, an appdefined can still come through,
5221 (e.g., from a makeKeyWindow event) but stopping self also stops the
5222 modal loop. Just defer it until later. */
5223 if ([NSApp modalWindow] == nil)
5225 last_appdefined_event_data = [theEvent data1];
5230 send_appdefined = YES;
5235 #ifdef NS_IMPL_COCOA
5236 /* If no dialog and none of our frames have focus and it is a move, skip it.
5237 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5238 such as Wifi, sound, date or similar.
5239 This prevents "spooky" highlighting in the frame under the menu. */
5240 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5242 struct ns_display_info *di;
5243 BOOL has_focus = NO;
5244 for (di = x_display_list; ! has_focus && di; di = di->next)
5245 has_focus = di->x_focus_frame != 0;
5251 NSTRACE_UNSILENCE();
5253 [super sendEvent: theEvent];
5257 - (void)showPreferencesWindow: (id)sender
5259 struct frame *emacsframe = SELECTED_FRAME ();
5260 NSEvent *theEvent = [NSApp currentEvent];
5264 emacs_event->kind = NS_NONKEY_EVENT;
5265 emacs_event->code = KEY_NS_SHOW_PREFS;
5266 emacs_event->modifiers = 0;
5267 EV_TRAILER (theEvent);
5271 - (void)newFrame: (id)sender
5273 NSTRACE ("[EmacsApp newFrame:]");
5275 struct frame *emacsframe = SELECTED_FRAME ();
5276 NSEvent *theEvent = [NSApp currentEvent];
5280 emacs_event->kind = NS_NONKEY_EVENT;
5281 emacs_event->code = KEY_NS_NEW_FRAME;
5282 emacs_event->modifiers = 0;
5283 EV_TRAILER (theEvent);
5287 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5288 - (BOOL) openFile: (NSString *)fileName
5290 NSTRACE ("[EmacsApp openFile:]");
5292 struct frame *emacsframe = SELECTED_FRAME ();
5293 NSEvent *theEvent = [NSApp currentEvent];
5298 emacs_event->kind = NS_NONKEY_EVENT;
5299 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5300 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5301 ns_input_line = Qnil; /* can be start or cons start,end */
5302 emacs_event->modifiers =0;
5303 EV_TRAILER (theEvent);
5309 /* **************************************************************************
5311 EmacsApp delegate implementation
5313 ************************************************************************** */
5315 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5316 /* --------------------------------------------------------------------------
5317 When application is loaded, terminate event loop in ns_term_init
5318 -------------------------------------------------------------------------- */
5320 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5322 #ifdef NS_IMPL_GNUSTEP
5323 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5325 [NSApp setServicesProvider: NSApp];
5327 [self antialiasThresholdDidChange:nil];
5328 #ifdef NS_IMPL_COCOA
5329 [[NSNotificationCenter defaultCenter]
5331 selector:@selector(antialiasThresholdDidChange:)
5332 name:NSAntialiasThresholdChangedNotification
5336 ns_send_appdefined (-2);
5339 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5341 #ifdef NS_IMPL_COCOA
5342 macfont_update_antialias_threshold ();
5347 /* Termination sequences:
5350 MenuBar | File | Exit:
5351 Select Quit from App menubar:
5353 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5356 Select Quit from Dock menu:
5359 Cancel -> Nothing else
5363 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5368 - (void) terminate: (id)sender
5370 NSTRACE ("[EmacsApp terminate:]");
5372 struct frame *emacsframe = SELECTED_FRAME ();
5377 emacs_event->kind = NS_NONKEY_EVENT;
5378 emacs_event->code = KEY_NS_POWER_OFF;
5379 emacs_event->arg = Qt; /* mark as non-key event */
5380 EV_TRAILER ((id)nil);
5384 runAlertPanel(NSString *title,
5385 NSString *msgFormat,
5386 NSString *defaultButton,
5387 NSString *alternateButton)
5389 #if !defined (NS_IMPL_COCOA) || \
5390 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5391 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5392 == NSAlertDefaultReturn;
5394 NSAlert *alert = [[NSAlert alloc] init];
5395 [alert setAlertStyle: NSCriticalAlertStyle];
5396 [alert setMessageText: msgFormat];
5397 [alert addButtonWithTitle: defaultButton];
5398 [alert addButtonWithTitle: alternateButton];
5399 NSInteger ret = [alert runModal];
5401 return ret == NSAlertFirstButtonReturn;
5406 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5408 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5412 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5413 return NSTerminateNow;
5415 ret = runAlertPanel(ns_app_name,
5416 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5417 @"Save Buffers and Exit", @"Cancel");
5420 return NSTerminateNow;
5422 return NSTerminateCancel;
5423 return NSTerminateNow; /* just in case */
5427 not_in_argv (NSString *arg)
5430 const char *a = [arg UTF8String];
5431 for (k = 1; k < initial_argc; ++k)
5432 if (strcmp (a, initial_argv[k]) == 0) return 0;
5436 /* Notification from the Workspace to open a file */
5437 - (BOOL)application: sender openFile: (NSString *)file
5439 if (ns_do_open_file || not_in_argv (file))
5440 [ns_pending_files addObject: file];
5445 /* Open a file as a temporary file */
5446 - (BOOL)application: sender openTempFile: (NSString *)file
5448 if (ns_do_open_file || not_in_argv (file))
5449 [ns_pending_files addObject: file];
5454 /* Notification from the Workspace to open a file noninteractively (?) */
5455 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5457 if (ns_do_open_file || not_in_argv (file))
5458 [ns_pending_files addObject: file];
5462 /* Notification from the Workspace to open multiple files */
5463 - (void)application: sender openFiles: (NSArray *)fileList
5465 NSEnumerator *files = [fileList objectEnumerator];
5467 /* Don't open files from the command line unconditionally,
5468 Cocoa parses the command line wrong, --option value tries to open value
5469 if --option is the last option. */
5470 while ((file = [files nextObject]) != nil)
5471 if (ns_do_open_file || not_in_argv (file))
5472 [ns_pending_files addObject: file];
5474 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5479 /* Handle dock menu requests. */
5480 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5486 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5487 - (void)applicationWillBecomeActive: (NSNotification *)notification
5489 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5490 //ns_app_active=YES;
5493 - (void)applicationDidBecomeActive: (NSNotification *)notification
5495 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5497 #ifdef NS_IMPL_GNUSTEP
5498 if (! applicationDidFinishLaunchingCalled)
5499 [self applicationDidFinishLaunching:notification];
5501 //ns_app_active=YES;
5503 ns_update_auto_hide_menu_bar ();
5504 // No constraining takes place when the application is not active.
5505 ns_constrain_all_frames ();
5507 - (void)applicationDidResignActive: (NSNotification *)notification
5509 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5512 ns_send_appdefined (-1);
5517 /* ==========================================================================
5519 EmacsApp aux handlers for managing event loop
5521 ========================================================================== */
5524 - (void)timeout_handler: (NSTimer *)timedEntry
5525 /* --------------------------------------------------------------------------
5526 The timeout specified to ns_select has passed.
5527 -------------------------------------------------------------------------- */
5529 /*NSTRACE ("timeout_handler"); */
5530 ns_send_appdefined (-2);
5533 #ifdef NS_IMPL_GNUSTEP
5534 - (void)sendFromMainThread:(id)unused
5536 ns_send_appdefined (nextappdefined);
5540 - (void)fd_handler:(id)unused
5541 /* --------------------------------------------------------------------------
5542 Check data waiting on file descriptors and terminate if so
5543 -------------------------------------------------------------------------- */
5546 int waiting = 1, nfds;
5549 fd_set readfds, writefds, *wfds;
5550 struct timespec timeout, *tmo;
5551 NSAutoreleasePool *pool = nil;
5553 /* NSTRACE ("fd_handler"); */
5558 pool = [[NSAutoreleasePool alloc] init];
5564 FD_SET (selfds[0], &fds);
5565 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5566 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5571 pthread_mutex_lock (&select_mutex);
5574 if (select_valid & SELECT_HAVE_READ)
5575 readfds = select_readfds;
5579 if (select_valid & SELECT_HAVE_WRITE)
5581 writefds = select_writefds;
5586 if (select_valid & SELECT_HAVE_TMO)
5588 timeout = select_timeout;
5594 pthread_mutex_unlock (&select_mutex);
5596 FD_SET (selfds[0], &readfds);
5597 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5599 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5602 ns_send_appdefined (-2);
5603 else if (result > 0)
5605 if (FD_ISSET (selfds[0], &readfds))
5607 if (read (selfds[0], &c, 1) == 1 && c == 's')
5612 pthread_mutex_lock (&select_mutex);
5613 if (select_valid & SELECT_HAVE_READ)
5614 select_readfds = readfds;
5615 if (select_valid & SELECT_HAVE_WRITE)
5616 select_writefds = writefds;
5617 if (select_valid & SELECT_HAVE_TMO)
5618 select_timeout = timeout;
5619 pthread_mutex_unlock (&select_mutex);
5621 ns_send_appdefined (result);
5631 /* ==========================================================================
5635 ========================================================================== */
5637 /* called from system: queue for next pass through event loop */
5638 - (void)requestService: (NSPasteboard *)pboard
5639 userData: (NSString *)userData
5640 error: (NSString **)error
5642 [ns_pending_service_names addObject: userData];
5643 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5644 SSDATA (ns_string_from_pasteboard (pboard))]];
5648 /* called from ns_read_socket to clear queue */
5649 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5651 struct frame *emacsframe = SELECTED_FRAME ();
5652 NSEvent *theEvent = [NSApp currentEvent];
5654 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5659 emacs_event->kind = NS_NONKEY_EVENT;
5660 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5661 ns_input_spi_name = build_string ([name UTF8String]);
5662 ns_input_spi_arg = build_string ([arg UTF8String]);
5663 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5664 EV_TRAILER (theEvent);
5674 /* ==========================================================================
5676 EmacsView implementation
5678 ========================================================================== */
5681 @implementation EmacsView
5683 /* needed to inform when window closed from LISP */
5684 - (void) setWindowClosing: (BOOL)closing
5686 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5688 windowClosing = closing;
5694 NSTRACE ("[EmacsView dealloc]");
5696 if (fs_state == FULLSCREEN_BOTH)
5697 [nonfs_window release];
5702 /* called on font panel selection */
5703 - (void)changeFont: (id)sender
5705 NSEvent *e = [[self window] currentEvent];
5706 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5707 struct font *font = face->font;
5712 NSTRACE ("[EmacsView changeFont:]");
5717 #ifdef NS_IMPL_GNUSTEP
5718 nsfont = ((struct nsfont_info *)font)->nsfont;
5720 #ifdef NS_IMPL_COCOA
5721 nsfont = (NSFont *) macfont_get_nsctfont (font);
5724 if ((newFont = [sender convertFont: nsfont]))
5726 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5728 emacs_event->kind = NS_NONKEY_EVENT;
5729 emacs_event->modifiers = 0;
5730 emacs_event->code = KEY_NS_CHANGE_FONT;
5732 size = [newFont pointSize];
5733 ns_input_fontsize = make_number (lrint (size));
5734 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5740 - (BOOL)acceptsFirstResponder
5742 NSTRACE ("[EmacsView acceptsFirstResponder]");
5747 - (void)resetCursorRects
5749 NSRect visible = [self visibleRect];
5750 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5751 NSTRACE ("[EmacsView resetCursorRects]");
5753 if (currentCursor == nil)
5754 currentCursor = [NSCursor arrowCursor];
5756 if (!NSIsEmptyRect (visible))
5757 [self addCursorRect: visible cursor: currentCursor];
5758 [currentCursor setOnMouseEntered: YES];
5763 /*****************************************************************************/
5764 /* Keyboard handling. */
5767 - (void)keyDown: (NSEvent *)theEvent
5769 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5771 unsigned fnKeysym = 0;
5772 static NSMutableArray *nsEvArray;
5774 unsigned int flags = [theEvent modifierFlags];
5776 NSTRACE ("[EmacsView keyDown:]");
5778 /* Rhapsody and OS X give up and down events for the arrow keys */
5779 if (ns_fake_keydown == YES)
5780 ns_fake_keydown = NO;
5781 else if ([theEvent type] != NSKeyDown)
5787 if (![[self window] isKeyWindow]
5788 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5789 /* we must avoid an infinite loop here. */
5790 && (EmacsView *)[[theEvent window] delegate] != self)
5792 /* XXX: There is an occasional condition in which, when Emacs display
5793 updates a different frame from the current one, and temporarily
5794 selects it, then processes some interrupt-driven input
5795 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5796 for some reason that window has its first responder set to the NSView
5797 most recently updated (I guess), which is not the correct one. */
5798 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5802 if (nsEvArray == nil)
5803 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5805 [NSCursor setHiddenUntilMouseMoves: YES];
5807 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5809 clear_mouse_face (hlinfo);
5810 hlinfo->mouse_face_hidden = 1;
5813 if (!processingCompose)
5815 /* When using screen sharing, no left or right information is sent,
5816 so use Left key in those cases. */
5817 int is_left_key, is_right_key;
5819 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5820 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5822 /* (Carbon way: [theEvent keyCode]) */
5824 /* is it a "function key"? */
5825 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5826 flag set (this is probably a bug in the OS).
5828 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5830 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5834 fnKeysym = ns_convert_key (code);
5839 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5840 because Emacs treats Delete and KP-Delete same (in simple.el). */
5841 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5842 #ifdef NS_IMPL_GNUSTEP
5843 /* GNUstep uses incompatible keycodes, even for those that are
5844 supposed to be hardware independent. Just check for delete.
5845 Keypad delete does not have keysym 0xFFFF.
5846 See http://savannah.gnu.org/bugs/?25395
5848 || (fnKeysym == 0xFFFF && code == 127)
5851 code = 0xFF08; /* backspace */
5856 /* are there modifiers? */
5857 emacs_event->modifiers = 0;
5859 if (flags & NSHelpKeyMask)
5860 emacs_event->modifiers |= hyper_modifier;
5862 if (flags & NSShiftKeyMask)
5863 emacs_event->modifiers |= shift_modifier;
5865 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5866 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5867 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5870 emacs_event->modifiers |= parse_solitary_modifier
5871 (EQ (ns_right_command_modifier, Qleft)
5872 ? ns_command_modifier
5873 : ns_right_command_modifier);
5877 emacs_event->modifiers |= parse_solitary_modifier
5878 (ns_command_modifier);
5880 /* if super (default), take input manager's word so things like
5881 dvorak / qwerty layout work */
5882 if (EQ (ns_command_modifier, Qsuper)
5884 && [[theEvent characters] length] != 0)
5886 /* XXX: the code we get will be unshifted, so if we have
5887 a shift modifier, must convert ourselves */
5888 if (!(flags & NSShiftKeyMask))
5889 code = [[theEvent characters] characterAtIndex: 0];
5891 /* this is ugly and also requires linking w/Carbon framework
5892 (for LMGetKbdType) so for now leave this rare (?) case
5893 undealt with.. in future look into CGEvent methods */
5896 long smv = GetScriptManagerVariable (smKeyScript);
5897 Handle uchrHandle = GetResource
5898 ('uchr', GetScriptVariable (smv, smScriptKeys));
5900 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5901 [[theEvent characters] characterAtIndex: 0],
5902 kUCKeyActionDisplay,
5903 (flags & ~NSCommandKeyMask) >> 8,
5904 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5905 &dummy, 1, &dummy, &code);
5912 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5913 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5914 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5917 emacs_event->modifiers |= parse_solitary_modifier
5918 (EQ (ns_right_control_modifier, Qleft)
5919 ? ns_control_modifier
5920 : ns_right_control_modifier);
5923 emacs_event->modifiers |= parse_solitary_modifier
5924 (ns_control_modifier);
5926 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5927 emacs_event->modifiers |=
5928 parse_solitary_modifier (ns_function_modifier);
5930 left_is_none = NILP (ns_alternate_modifier)
5931 || EQ (ns_alternate_modifier, Qnone);
5933 is_right_key = (flags & NSRightAlternateKeyMask)
5934 == NSRightAlternateKeyMask;
5935 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5937 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5941 if ((NILP (ns_right_alternate_modifier)
5942 || EQ (ns_right_alternate_modifier, Qnone)
5943 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5945 { /* accept pre-interp alt comb */
5946 if ([[theEvent characters] length] > 0)
5947 code = [[theEvent characters] characterAtIndex: 0];
5948 /*HACK: clear lone shift modifier to stop next if from firing */
5949 if (emacs_event->modifiers == shift_modifier)
5950 emacs_event->modifiers = 0;
5953 emacs_event->modifiers |= parse_solitary_modifier
5954 (EQ (ns_right_alternate_modifier, Qleft)
5955 ? ns_alternate_modifier
5956 : ns_right_alternate_modifier);
5959 if (is_left_key) /* default = meta */
5961 if (left_is_none && !fnKeysym)
5962 { /* accept pre-interp alt comb */
5963 if ([[theEvent characters] length] > 0)
5964 code = [[theEvent characters] characterAtIndex: 0];
5965 /*HACK: clear lone shift modifier to stop next if from firing */
5966 if (emacs_event->modifiers == shift_modifier)
5967 emacs_event->modifiers = 0;
5970 emacs_event->modifiers |=
5971 parse_solitary_modifier (ns_alternate_modifier);
5975 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5976 code, fnKeysym, flags, emacs_event->modifiers);
5978 /* if it was a function key or had modifiers, pass it directly to emacs */
5979 if (fnKeysym || (emacs_event->modifiers
5980 && (emacs_event->modifiers != shift_modifier)
5981 && [[theEvent charactersIgnoringModifiers] length] > 0))
5982 /*[[theEvent characters] length] */
5984 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5986 code |= (1<<28)|(3<<16);
5987 else if (code == 0x7f)
5988 code |= (1<<28)|(3<<16);
5990 emacs_event->kind = code > 0xFF
5991 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5993 emacs_event->code = code;
5994 EV_TRAILER (theEvent);
5995 processingCompose = NO;
6001 if (NS_KEYLOG && !processingCompose)
6002 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6004 processingCompose = YES;
6005 [nsEvArray addObject: theEvent];
6006 [self interpretKeyEvents: nsEvArray];
6007 [nsEvArray removeObject: theEvent];
6011 #ifdef NS_IMPL_COCOA
6012 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
6013 decided not to send key-down for.
6014 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
6015 This only applies on Tiger and earlier.
6016 If it matches one of these, send it on to keyDown. */
6017 -(void)keyUp: (NSEvent *)theEvent
6019 int flags = [theEvent modifierFlags];
6020 int code = [theEvent keyCode];
6022 NSTRACE ("[EmacsView keyUp:]");
6024 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
6025 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
6028 fprintf (stderr, "keyUp: passed test");
6029 ns_fake_keydown = YES;
6030 [self keyDown: theEvent];
6036 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6039 /* <NSTextInput>: called when done composing;
6040 NOTE: also called when we delete over working text, followed immed.
6041 by doCommandBySelector: deleteBackward: */
6042 - (void)insertText: (id)aString
6045 int len = [(NSString *)aString length];
6048 NSTRACE ("[EmacsView insertText:]");
6051 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6052 processingCompose = NO;
6057 /* first, clear any working text */
6058 if (workingText != nil)
6059 [self deleteWorkingText];
6061 /* now insert the string as keystrokes */
6062 for (i =0; i<len; i++)
6064 code = [aString characterAtIndex: i];
6065 /* TODO: still need this? */
6067 code = '~'; /* 0x7E */
6068 if (code != 32) /* Space */
6069 emacs_event->modifiers = 0;
6071 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6072 emacs_event->code = code;
6073 EV_TRAILER ((id)nil);
6078 /* <NSTextInput>: inserts display of composing characters */
6079 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6081 NSString *str = [aString respondsToSelector: @selector (string)] ?
6082 [aString string] : aString;
6084 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6087 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6088 str, (unsigned long)[str length],
6089 (unsigned long)selRange.length,
6090 (unsigned long)selRange.location);
6092 if (workingText != nil)
6093 [self deleteWorkingText];
6094 if ([str length] == 0)
6100 processingCompose = YES;
6101 workingText = [str copy];
6102 ns_working_text = build_string ([workingText UTF8String]);
6104 emacs_event->kind = NS_TEXT_EVENT;
6105 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6106 EV_TRAILER ((id)nil);
6110 /* delete display of composing characters [not in <NSTextInput>] */
6111 - (void)deleteWorkingText
6113 NSTRACE ("[EmacsView deleteWorkingText]");
6115 if (workingText == nil)
6118 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6119 [workingText release];
6121 processingCompose = NO;
6126 emacs_event->kind = NS_TEXT_EVENT;
6127 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6128 EV_TRAILER ((id)nil);
6132 - (BOOL)hasMarkedText
6134 NSTRACE ("[EmacsView hasMarkedText]");
6136 return workingText != nil;
6140 - (NSRange)markedRange
6142 NSTRACE ("[EmacsView markedRange]");
6144 NSRange rng = workingText != nil
6145 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6147 NSLog (@"markedRange request");
6154 NSTRACE ("[EmacsView unmarkText]");
6157 NSLog (@"unmark (accept) text");
6158 [self deleteWorkingText];
6159 processingCompose = NO;
6163 /* used to position char selection windows, etc. */
6164 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6168 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6170 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6173 NSLog (@"firstRectForCharRange request");
6175 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6176 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6177 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6178 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6179 +FRAME_LINE_HEIGHT (emacsframe));
6181 pt = [self convertPoint: pt toView: nil];
6182 pt = [[self window] convertBaseToScreen: pt];
6188 - (NSInteger)conversationIdentifier
6190 return (NSInteger)self;
6194 - (void)doCommandBySelector: (SEL)aSelector
6196 NSTRACE ("[EmacsView doCommandBySelector:]");
6199 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6201 processingCompose = NO;
6202 if (aSelector == @selector (deleteBackward:))
6204 /* happens when user backspaces over an ongoing composition:
6205 throw a 'delete' into the event queue */
6208 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6209 emacs_event->code = 0xFF08;
6210 EV_TRAILER ((id)nil);
6214 - (NSArray *)validAttributesForMarkedText
6216 static NSArray *arr = nil;
6217 if (arr == nil) arr = [NSArray new];
6218 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6222 - (NSRange)selectedRange
6225 NSLog (@"selectedRange request");
6226 return NSMakeRange (NSNotFound, 0);
6229 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6230 GNUSTEP_GUI_MINOR_VERSION > 22
6231 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6233 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6237 NSLog (@"characterIndexForPoint request");
6241 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6243 static NSAttributedString *str = nil;
6244 if (str == nil) str = [NSAttributedString new];
6246 NSLog (@"attributedSubstringFromRange request");
6250 /* End <NSTextInput> impl. */
6251 /*****************************************************************************/
6254 /* This is what happens when the user presses a mouse button. */
6255 - (void)mouseDown: (NSEvent *)theEvent
6257 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6258 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6260 NSTRACE ("[EmacsView mouseDown:]");
6262 [self deleteWorkingText];
6267 dpyinfo->last_mouse_frame = emacsframe;
6268 /* appears to be needed to prevent spurious movement events generated on
6270 emacsframe->mouse_moved = 0;
6272 if ([theEvent type] == NSScrollWheel)
6274 CGFloat delta = [theEvent deltaY];
6275 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6278 delta = [theEvent deltaX];
6281 NSTRACE_MSG ("deltaIsZero");
6284 emacs_event->kind = HORIZ_WHEEL_EVENT;
6287 emacs_event->kind = WHEEL_EVENT;
6289 emacs_event->code = 0;
6290 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6291 ((delta > 0) ? up_modifier : down_modifier);
6295 emacs_event->kind = MOUSE_CLICK_EVENT;
6296 emacs_event->code = EV_BUTTON (theEvent);
6297 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6298 | EV_UDMODIFIERS (theEvent);
6300 XSETINT (emacs_event->x, lrint (p.x));
6301 XSETINT (emacs_event->y, lrint (p.y));
6302 EV_TRAILER (theEvent);
6306 - (void)rightMouseDown: (NSEvent *)theEvent
6308 NSTRACE ("[EmacsView rightMouseDown:]");
6309 [self mouseDown: theEvent];
6313 - (void)otherMouseDown: (NSEvent *)theEvent
6315 NSTRACE ("[EmacsView otherMouseDown:]");
6316 [self mouseDown: theEvent];
6320 - (void)mouseUp: (NSEvent *)theEvent
6322 NSTRACE ("[EmacsView mouseUp:]");
6323 [self mouseDown: theEvent];
6327 - (void)rightMouseUp: (NSEvent *)theEvent
6329 NSTRACE ("[EmacsView rightMouseUp:]");
6330 [self mouseDown: theEvent];
6334 - (void)otherMouseUp: (NSEvent *)theEvent
6336 NSTRACE ("[EmacsView otherMouseUp:]");
6337 [self mouseDown: theEvent];
6341 - (void) scrollWheel: (NSEvent *)theEvent
6343 NSTRACE ("[EmacsView scrollWheel:]");
6344 [self mouseDown: theEvent];
6348 /* Tell emacs the mouse has moved. */
6349 - (void)mouseMoved: (NSEvent *)e
6351 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6352 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6356 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6358 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6359 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6360 dpyinfo->last_mouse_motion_x = pt.x;
6361 dpyinfo->last_mouse_motion_y = pt.y;
6363 /* update any mouse face */
6364 if (hlinfo->mouse_face_hidden)
6366 hlinfo->mouse_face_hidden = 0;
6367 clear_mouse_face (hlinfo);
6370 /* tooltip handling */
6371 previous_help_echo_string = help_echo_string;
6372 help_echo_string = Qnil;
6374 if (!NILP (Vmouse_autoselect_window))
6376 NSTRACE_MSG ("mouse_autoselect_window");
6377 static Lisp_Object last_mouse_window;
6379 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6381 if (WINDOWP (window)
6382 && !EQ (window, last_mouse_window)
6383 && !EQ (window, selected_window)
6384 && (focus_follows_mouse
6385 || (EQ (XWINDOW (window)->frame,
6386 XWINDOW (selected_window)->frame))))
6388 NSTRACE_MSG ("in_window");
6389 emacs_event->kind = SELECT_WINDOW_EVENT;
6390 emacs_event->frame_or_window = window;
6393 /* Remember the last window where we saw the mouse. */
6394 last_mouse_window = window;
6397 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6398 help_echo_string = previous_help_echo_string;
6400 XSETFRAME (frame, emacsframe);
6401 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6403 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6404 (note_mouse_highlight), which is called through the
6405 note_mouse_movement () call above */
6406 any_help_event_p = YES;
6407 gen_help_event (help_echo_string, frame, help_echo_window,
6408 help_echo_object, help_echo_pos);
6411 if (emacsframe->mouse_moved && send_appdefined)
6412 ns_send_appdefined (-1);
6416 - (void)mouseDragged: (NSEvent *)e
6418 NSTRACE ("[EmacsView mouseDragged:]");
6419 [self mouseMoved: e];
6423 - (void)rightMouseDragged: (NSEvent *)e
6425 NSTRACE ("[EmacsView rightMouseDragged:]");
6426 [self mouseMoved: e];
6430 - (void)otherMouseDragged: (NSEvent *)e
6432 NSTRACE ("[EmacsView otherMouseDragged:]");
6433 [self mouseMoved: e];
6437 - (BOOL)windowShouldClose: (id)sender
6439 NSEvent *e =[[self window] currentEvent];
6441 NSTRACE ("[EmacsView windowShouldClose:]");
6442 windowClosing = YES;
6445 emacs_event->kind = DELETE_WINDOW_EVENT;
6446 emacs_event->modifiers = 0;
6447 emacs_event->code = 0;
6449 /* Don't close this window, let this be done from lisp code. */
6453 - (void) updateFrameSize: (BOOL) delay;
6455 NSWindow *window = [self window];
6456 NSRect wr = [window frame];
6458 int oldc = cols, oldr = rows;
6459 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6460 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6463 NSTRACE ("[EmacsView updateFrameSize:]");
6464 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6465 NSTRACE_RECT ("Original frame", wr);
6466 NSTRACE_MSG ("Original columns: %d", cols);
6467 NSTRACE_MSG ("Original rows: %d", rows);
6469 if (! [self isFullscreen])
6471 #ifdef NS_IMPL_GNUSTEP
6472 // GNUstep does not always update the tool bar height. Force it.
6473 if (toolbar && [toolbar isVisible])
6474 update_frame_tool_bar (emacsframe);
6477 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6478 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6481 if (wait_for_tool_bar)
6483 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6485 NSTRACE_MSG ("Waiting for toolbar");
6488 wait_for_tool_bar = NO;
6491 neww = (int)wr.size.width - emacsframe->border_width;
6492 newh = (int)wr.size.height - extra;
6494 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6495 NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6497 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6498 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6500 if (cols < MINWIDTH)
6503 if (rows < MINHEIGHT)
6506 NSTRACE_MSG ("New columns: %d", cols);
6507 NSTRACE_MSG ("New rows: %d", rows);
6509 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6511 NSView *view = FRAME_NS_VIEW (emacsframe);
6513 change_frame_size (emacsframe,
6514 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6515 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6517 SET_FRAME_GARBAGED (emacsframe);
6518 cancel_mouse_face (emacsframe);
6520 wr = NSMakeRect (0, 0, neww, newh);
6522 [view setFrame: wr];
6524 // to do: consider using [NSNotificationCenter postNotificationName:].
6525 [self windowDidMove: // Update top/left.
6526 [NSNotification notificationWithName:NSWindowDidMoveNotification
6527 object:[view window]]];
6531 NSTRACE_MSG ("No change");
6535 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6536 /* normalize frame to gridded text size */
6540 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6541 NSTRACE_ARG_SIZE (frameSize));
6542 NSTRACE_RECT ("[sender frame]", [sender frame]);
6543 NSTRACE_FSTYPE ("fs_state", fs_state);
6545 if (fs_state == FULLSCREEN_MAXIMIZED
6546 && (maximized_width != (int)frameSize.width
6547 || maximized_height != (int)frameSize.height))
6548 [self setFSValue: FULLSCREEN_NONE];
6549 else if (fs_state == FULLSCREEN_WIDTH
6550 && maximized_width != (int)frameSize.width)
6551 [self setFSValue: FULLSCREEN_NONE];
6552 else if (fs_state == FULLSCREEN_HEIGHT
6553 && maximized_height != (int)frameSize.height)
6554 [self setFSValue: FULLSCREEN_NONE];
6556 if (fs_state == FULLSCREEN_NONE)
6557 maximized_width = maximized_height = -1;
6559 if (! [self isFullscreen])
6561 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6562 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6565 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6566 if (cols < MINWIDTH)
6569 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6570 frameSize.height - extra);
6571 if (rows < MINHEIGHT)
6573 #ifdef NS_IMPL_COCOA
6575 /* this sets window title to have size in it; the wm does this under GS */
6576 NSRect r = [[self window] frame];
6577 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6585 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6588 NSWindow *window = [self window];
6591 char *t = strdup ([[[self window] title] UTF8String]);
6592 char *pos = strstr (t, " — ");
6597 size_title = xmalloc (strlen (old_title) + 40);
6598 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6599 [window setTitle: [NSString stringWithUTF8String: size_title]];
6604 #endif /* NS_IMPL_COCOA */
6606 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6608 /* Restrict the new size to the text gird.
6610 Don't restrict the width if the user only adjusted the height, and
6611 vice versa. (Without this, the frame would shrink, and move
6612 slightly, if the window was resized by dragging one of its
6614 if (!frame_resize_pixelwise)
6616 NSRect r = [[self window] frame];
6618 if (r.size.width != frameSize.width)
6621 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6624 if (r.size.height != frameSize.height)
6627 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6631 NSTRACE_RETURN_SIZE (frameSize);
6637 - (void)windowDidResize: (NSNotification *)notification
6639 NSTRACE ("[EmacsView windowDidResize:]");
6640 if (!FRAME_LIVE_P (emacsframe))
6642 NSTRACE_MSG ("Ignored (frame dead)");
6645 if (emacsframe->output_data.ns->in_animation)
6647 NSTRACE_MSG ("Ignored (in animation)");
6651 if (! [self fsIsNative])
6653 NSWindow *theWindow = [notification object];
6654 /* We can get notification on the non-FS window when in
6656 if ([self window] != theWindow) return;
6659 NSTRACE_RECT ("frame", [[notification object] frame]);
6661 #ifdef NS_IMPL_GNUSTEP
6662 NSWindow *theWindow = [notification object];
6664 /* In GNUstep, at least currently, it's possible to get a didResize
6665 without getting a willResize.. therefore we need to act as if we got
6666 the willResize now */
6667 NSSize sz = [theWindow frame].size;
6668 sz = [self windowWillResize: theWindow toSize: sz];
6669 #endif /* NS_IMPL_GNUSTEP */
6671 if (cols > 0 && rows > 0)
6673 [self updateFrameSize: YES];
6676 ns_send_appdefined (-1);
6679 #ifdef NS_IMPL_COCOA
6680 - (void)viewDidEndLiveResize
6682 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6684 [super viewDidEndLiveResize];
6687 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6691 maximizing_resize = NO;
6693 #endif /* NS_IMPL_COCOA */
6696 - (void)windowDidBecomeKey: (NSNotification *)notification
6697 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6699 [self windowDidBecomeKey];
6703 - (void)windowDidBecomeKey /* for direct calls */
6705 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6706 struct frame *old_focus = dpyinfo->x_focus_frame;
6708 NSTRACE ("[EmacsView windowDidBecomeKey]");
6710 if (emacsframe != old_focus)
6711 dpyinfo->x_focus_frame = emacsframe;
6713 ns_frame_rehighlight (emacsframe);
6717 emacs_event->kind = FOCUS_IN_EVENT;
6718 EV_TRAILER ((id)nil);
6723 - (void)windowDidResignKey: (NSNotification *)notification
6724 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6726 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6727 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6728 NSTRACE ("[EmacsView windowDidResignKey:]");
6731 dpyinfo->x_focus_frame = 0;
6733 emacsframe->mouse_moved = 0;
6734 ns_frame_rehighlight (emacsframe);
6736 /* FIXME: for some reason needed on second and subsequent clicks away
6737 from sole-frame Emacs to get hollow box to show */
6738 if (!windowClosing && [[self window] isVisible] == YES)
6740 x_update_cursor (emacsframe, 1);
6741 x_set_frame_alpha (emacsframe);
6744 if (any_help_event_p)
6747 XSETFRAME (frame, emacsframe);
6748 help_echo_string = Qnil;
6749 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6752 if (emacs_event && is_focus_frame)
6754 [self deleteWorkingText];
6755 emacs_event->kind = FOCUS_OUT_EVENT;
6756 EV_TRAILER ((id)nil);
6761 - (void)windowWillMiniaturize: sender
6763 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6767 - (void)setFrame:(NSRect)frameRect;
6769 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6770 NSTRACE_ARG_RECT (frameRect));
6772 [super setFrame:(NSRect)frameRect];
6788 - initFrameFromEmacs: (struct frame *)f
6796 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6797 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6800 processingCompose = NO;
6801 scrollbarsNeedingUpdate = 0;
6802 fs_state = FULLSCREEN_NONE;
6803 fs_before_fs = next_maximized = -1;
6804 #ifdef HAVE_NATIVE_FS
6805 fs_is_native = ns_use_native_fullscreen;
6809 maximized_width = maximized_height = -1;
6812 ns_userRect = NSMakeRect (0, 0, 0, 0);
6813 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6814 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6815 [self initWithFrame: r];
6816 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6818 FRAME_NS_VIEW (f) = self;
6820 #ifdef NS_IMPL_COCOA
6822 maximizing_resize = NO;
6825 win = [[EmacsWindow alloc]
6826 initWithContentRect: r
6827 styleMask: (NSResizableWindowMask |
6828 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6829 NSTitledWindowMask |
6831 NSMiniaturizableWindowMask |
6832 NSClosableWindowMask)
6833 backing: NSBackingStoreBuffered
6836 #ifdef HAVE_NATIVE_FS
6837 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6841 bwidth = f->border_width = wr.size.width - r.size.width;
6842 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6844 [win setAcceptsMouseMovedEvents: YES];
6845 [win setDelegate: self];
6846 #if !defined (NS_IMPL_COCOA) || \
6847 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6848 [win useOptimizedDrawing: YES];
6851 [[win contentView] addSubview: self];
6854 [self registerForDraggedTypes: ns_drag_types];
6857 name = [NSString stringWithUTF8String:
6858 NILP (tem) ? "Emacs" : SSDATA (tem)];
6859 [win setTitle: name];
6861 /* toolbar support */
6862 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6863 [NSString stringWithFormat: @"Emacs Frame %d",
6865 [win setToolbar: toolbar];
6866 [toolbar setVisible: NO];
6868 /* Don't set frame garbaged until tool bar is up to date?
6869 This avoids an extra clear and redraw (flicker) at frame creation. */
6870 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6871 else wait_for_tool_bar = NO;
6874 #ifdef NS_IMPL_COCOA
6876 NSButton *toggleButton;
6877 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6878 [toggleButton setTarget: self];
6879 [toggleButton setAction: @selector (toggleToolbar: )];
6882 FRAME_TOOLBAR_HEIGHT (f) = 0;
6886 [win setMiniwindowTitle:
6887 [NSString stringWithUTF8String: SSDATA (tem)]];
6890 NSScreen *screen = [win screen];
6894 NSPoint pt = NSMakePoint
6895 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6896 IN_BOUND (-SCREENMAX,
6897 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6899 [win setFrameTopLeftPoint: pt];
6901 NSTRACE_RECT ("new frame", [win frame]);
6905 [win makeFirstResponder: self];
6907 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6908 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6909 [win setBackgroundColor: col];
6910 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6911 [win setOpaque: NO];
6913 #if !defined (NS_IMPL_COCOA) || \
6914 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6915 [self allocateGState];
6917 [NSApp registerServicesMenuSendTypes: ns_send_types
6925 - (void)windowDidMove: sender
6927 NSWindow *win = [self window];
6928 NSRect r = [win frame];
6929 NSArray *screens = [NSScreen screens];
6930 NSScreen *screen = [screens objectAtIndex: 0];
6932 NSTRACE ("[EmacsView windowDidMove:]");
6934 if (!emacsframe->output_data.ns)
6938 emacsframe->left_pos = r.origin.x;
6939 emacsframe->top_pos =
6940 [screen frame].size.height - (r.origin.y + r.size.height);
6945 /* Called AFTER method below, but before our windowWillResize call there leads
6946 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6947 location so set_window_size moves the frame. */
6948 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6950 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6951 NSTRACE_FMT_RETURN "YES"),
6952 NSTRACE_ARG_RECT (newFrame));
6954 emacsframe->output_data.ns->zooming = 1;
6959 /* Override to do something slightly nonstandard, but nice. First click on
6960 zoom button will zoom vertically. Second will zoom completely. Third
6961 returns to original. */
6962 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6963 defaultFrame:(NSRect)defaultFrame
6965 // TODO: Rename to "currentFrame" and assign "result" properly in
6967 NSRect result = [sender frame];
6969 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6970 NSTRACE_FMT_RECT "]"),
6971 NSTRACE_ARG_RECT (defaultFrame));
6972 NSTRACE_FSTYPE ("fs_state", fs_state);
6973 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6974 NSTRACE_FSTYPE ("next_maximized", next_maximized);
6975 NSTRACE_RECT ("ns_userRect", ns_userRect);
6976 NSTRACE_RECT ("[sender frame]", [sender frame]);
6978 if (fs_before_fs != -1) /* Entering fullscreen */
6980 NSTRACE_MSG ("Entering fullscreen");
6981 result = defaultFrame;
6985 // Save the window size and position (frame) before the resize.
6986 if (fs_state != FULLSCREEN_MAXIMIZED
6987 && fs_state != FULLSCREEN_WIDTH)
6989 ns_userRect.size.width = result.size.width;
6990 ns_userRect.origin.x = result.origin.x;
6993 if (fs_state != FULLSCREEN_MAXIMIZED
6994 && fs_state != FULLSCREEN_HEIGHT)
6996 ns_userRect.size.height = result.size.height;
6997 ns_userRect.origin.y = result.origin.y;
7000 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7002 if (next_maximized == FULLSCREEN_HEIGHT
7003 || (next_maximized == -1
7004 && abs ((int)(defaultFrame.size.height - result.size.height))
7005 > FRAME_LINE_HEIGHT (emacsframe)))
7008 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7009 maximized_height = result.size.height = defaultFrame.size.height;
7010 maximized_width = -1;
7011 result.origin.y = defaultFrame.origin.y;
7012 if (ns_userRect.size.height != 0)
7014 result.origin.x = ns_userRect.origin.x;
7015 result.size.width = ns_userRect.size.width;
7017 [self setFSValue: FULLSCREEN_HEIGHT];
7018 #ifdef NS_IMPL_COCOA
7019 maximizing_resize = YES;
7022 else if (next_maximized == FULLSCREEN_WIDTH)
7024 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7025 maximized_width = result.size.width = defaultFrame.size.width;
7026 maximized_height = -1;
7027 result.origin.x = defaultFrame.origin.x;
7028 if (ns_userRect.size.width != 0)
7030 result.origin.y = ns_userRect.origin.y;
7031 result.size.height = ns_userRect.size.height;
7033 [self setFSValue: FULLSCREEN_WIDTH];
7035 else if (next_maximized == FULLSCREEN_MAXIMIZED
7036 || (next_maximized == -1
7037 && abs ((int)(defaultFrame.size.width - result.size.width))
7038 > FRAME_COLUMN_WIDTH (emacsframe)))
7040 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7042 result = defaultFrame; /* second click */
7043 maximized_width = result.size.width;
7044 maximized_height = result.size.height;
7045 [self setFSValue: FULLSCREEN_MAXIMIZED];
7046 #ifdef NS_IMPL_COCOA
7047 maximizing_resize = YES;
7053 NSTRACE_MSG ("Restore");
7054 result = ns_userRect.size.height ? ns_userRect : result;
7055 NSTRACE_RECT ("restore (2)", result);
7056 ns_userRect = NSMakeRect (0, 0, 0, 0);
7057 #ifdef NS_IMPL_COCOA
7058 maximizing_resize = fs_state != FULLSCREEN_NONE;
7060 [self setFSValue: FULLSCREEN_NONE];
7061 maximized_width = maximized_height = -1;
7065 if (fs_before_fs == -1) next_maximized = -1;
7067 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7068 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7069 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7070 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7072 [self windowWillResize: sender toSize: result.size];
7074 NSTRACE_RETURN_RECT (result);
7080 - (void)windowDidDeminiaturize: sender
7082 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7083 if (!emacsframe->output_data.ns)
7086 SET_FRAME_ICONIFIED (emacsframe, 0);
7087 SET_FRAME_VISIBLE (emacsframe, 1);
7088 windows_or_buffers_changed = 63;
7092 emacs_event->kind = DEICONIFY_EVENT;
7093 EV_TRAILER ((id)nil);
7098 - (void)windowDidExpose: sender
7100 NSTRACE ("[EmacsView windowDidExpose:]");
7101 if (!emacsframe->output_data.ns)
7104 SET_FRAME_VISIBLE (emacsframe, 1);
7105 SET_FRAME_GARBAGED (emacsframe);
7107 if (send_appdefined)
7108 ns_send_appdefined (-1);
7112 - (void)windowDidMiniaturize: sender
7114 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7115 if (!emacsframe->output_data.ns)
7118 SET_FRAME_ICONIFIED (emacsframe, 1);
7119 SET_FRAME_VISIBLE (emacsframe, 0);
7123 emacs_event->kind = ICONIFY_EVENT;
7124 EV_TRAILER ((id)nil);
7128 #ifdef HAVE_NATIVE_FS
7129 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7130 willUseFullScreenPresentationOptions:
7131 (NSApplicationPresentationOptions)proposedOptions
7133 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7137 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7139 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7140 [self windowWillEnterFullScreen];
7142 - (void)windowWillEnterFullScreen /* provided for direct calls */
7144 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7145 fs_before_fs = fs_state;
7148 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7150 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7151 [self windowDidEnterFullScreen];
7154 - (void)windowDidEnterFullScreen /* provided for direct calls */
7156 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7157 [self setFSValue: FULLSCREEN_BOTH];
7158 if (! [self fsIsNative])
7160 [self windowDidBecomeKey];
7161 [nonfs_window orderOut:self];
7165 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7166 #ifdef NS_IMPL_COCOA
7167 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7168 unsigned val = (unsigned)[NSApp presentationOptions];
7170 // OSX 10.7 bug fix, the menu won't appear without this.
7171 // val is non-zero on other OSX versions.
7174 NSApplicationPresentationOptions options
7175 = NSApplicationPresentationAutoHideDock
7176 | NSApplicationPresentationAutoHideMenuBar
7177 | NSApplicationPresentationFullScreen
7178 | NSApplicationPresentationAutoHideToolbar;
7180 [NSApp setPresentationOptions: options];
7184 [toolbar setVisible:tbar_visible];
7188 - (void)windowWillExitFullScreen:(NSNotification *)notification
7190 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7191 [self windowWillExitFullScreen];
7194 - (void)windowWillExitFullScreen /* provided for direct calls */
7196 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7197 if (!FRAME_LIVE_P (emacsframe))
7199 NSTRACE_MSG ("Ignored (frame dead)");
7202 if (next_maximized != -1)
7203 fs_before_fs = next_maximized;
7206 - (void)windowDidExitFullScreen:(NSNotification *)notification
7208 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7209 [self windowDidExitFullScreen];
7212 - (void)windowDidExitFullScreen /* provided for direct calls */
7214 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7215 if (!FRAME_LIVE_P (emacsframe))
7217 NSTRACE_MSG ("Ignored (frame dead)");
7220 [self setFSValue: fs_before_fs];
7222 #ifdef HAVE_NATIVE_FS
7223 [self updateCollectionBehavior];
7225 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7227 [toolbar setVisible:YES];
7228 update_frame_tool_bar (emacsframe);
7229 [self updateFrameSize:YES];
7230 [[self window] display];
7233 [toolbar setVisible:NO];
7235 if (next_maximized != -1)
7236 [[self window] performZoom:self];
7241 return fs_is_native;
7244 - (BOOL)isFullscreen
7250 res = (nonfs_window != nil);
7254 #ifdef HAVE_NATIVE_FS
7255 res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7261 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7267 #ifdef HAVE_NATIVE_FS
7268 - (void)updateCollectionBehavior
7270 NSTRACE ("[EmacsView updateCollectionBehavior]");
7272 if (! [self isFullscreen])
7274 NSWindow *win = [self window];
7275 NSWindowCollectionBehavior b = [win collectionBehavior];
7276 if (ns_use_native_fullscreen)
7277 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7279 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7281 [win setCollectionBehavior: b];
7282 fs_is_native = ns_use_native_fullscreen;
7287 - (void)toggleFullScreen: (id)sender
7295 NSTRACE ("[EmacsView toggleFullScreen:]");
7299 #ifdef HAVE_NATIVE_FS
7300 [[self window] toggleFullScreen:sender];
7306 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7309 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7310 (FRAME_DEFAULT_FACE (f)),
7313 if (fs_state != FULLSCREEN_BOTH)
7315 NSScreen *screen = [w screen];
7317 #if defined (NS_IMPL_COCOA) && \
7318 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7319 /* Hide ghost menu bar on secondary monitor? */
7320 if (! onFirstScreen)
7321 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7323 /* Hide dock and menubar if we are on the primary screen. */
7326 #ifdef NS_IMPL_COCOA
7327 NSApplicationPresentationOptions options
7328 = NSApplicationPresentationAutoHideDock
7329 | NSApplicationPresentationAutoHideMenuBar;
7331 [NSApp setPresentationOptions: options];
7333 [NSMenu setMenuBarVisible:NO];
7337 fw = [[EmacsFSWindow alloc]
7338 initWithContentRect:[w contentRectForFrameRect:wr]
7339 styleMask:NSBorderlessWindowMask
7340 backing:NSBackingStoreBuffered
7344 [fw setContentView:[w contentView]];
7345 [fw setTitle:[w title]];
7346 [fw setDelegate:self];
7347 [fw setAcceptsMouseMovedEvents: YES];
7348 #if !defined (NS_IMPL_COCOA) || \
7349 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7350 [fw useOptimizedDrawing: YES];
7352 [fw setBackgroundColor: col];
7353 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7356 f->border_width = 0;
7357 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7358 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7359 FRAME_TOOLBAR_HEIGHT (f) = 0;
7363 [self windowWillEnterFullScreen];
7364 [fw makeKeyAndOrderFront:NSApp];
7365 [fw makeFirstResponder:self];
7367 r = [fw frameRectForContentRect:[screen frame]];
7368 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7369 [self windowDidEnterFullScreen];
7380 #ifdef NS_IMPL_COCOA
7381 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7383 [NSMenu setMenuBarVisible:YES];
7387 [w setContentView:[fw contentView]];
7388 [w setBackgroundColor: col];
7389 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7392 f->border_width = bwidth;
7393 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7394 if (FRAME_EXTERNAL_TOOL_BAR (f))
7395 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7397 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7399 [self windowWillExitFullScreen];
7400 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7402 [w makeKeyAndOrderFront:NSApp];
7403 [self windowDidExitFullScreen];
7404 [self updateFrameSize:YES];
7410 NSTRACE ("[EmacsView handleFS]");
7412 if (fs_state != emacsframe->want_fullscreen)
7414 if (fs_state == FULLSCREEN_BOTH)
7416 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7417 [self toggleFullScreen:self];
7420 switch (emacsframe->want_fullscreen)
7422 case FULLSCREEN_BOTH:
7423 NSTRACE_MSG ("FULLSCREEN_BOTH");
7424 [self toggleFullScreen:self];
7426 case FULLSCREEN_WIDTH:
7427 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7428 next_maximized = FULLSCREEN_WIDTH;
7429 if (fs_state != FULLSCREEN_BOTH)
7430 [[self window] performZoom:self];
7432 case FULLSCREEN_HEIGHT:
7433 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7434 next_maximized = FULLSCREEN_HEIGHT;
7435 if (fs_state != FULLSCREEN_BOTH)
7436 [[self window] performZoom:self];
7438 case FULLSCREEN_MAXIMIZED:
7439 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7440 next_maximized = FULLSCREEN_MAXIMIZED;
7441 if (fs_state != FULLSCREEN_BOTH)
7442 [[self window] performZoom:self];
7444 case FULLSCREEN_NONE:
7445 NSTRACE_MSG ("FULLSCREEN_NONE");
7446 if (fs_state != FULLSCREEN_BOTH)
7448 next_maximized = FULLSCREEN_NONE;
7449 [[self window] performZoom:self];
7454 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7459 - (void) setFSValue: (int)value
7461 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7462 NSTRACE_ARG_FSTYPE(value));
7464 Lisp_Object lval = Qnil;
7467 case FULLSCREEN_BOTH:
7470 case FULLSCREEN_WIDTH:
7473 case FULLSCREEN_HEIGHT:
7476 case FULLSCREEN_MAXIMIZED:
7480 store_frame_param (emacsframe, Qfullscreen, lval);
7484 - (void)mouseEntered: (NSEvent *)theEvent
7486 NSTRACE ("[EmacsView mouseEntered:]");
7488 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7489 = EV_TIMESTAMP (theEvent);
7493 - (void)mouseExited: (NSEvent *)theEvent
7495 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7497 NSTRACE ("[EmacsView mouseExited:]");
7502 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7503 = EV_TIMESTAMP (theEvent);
7505 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7507 clear_mouse_face (hlinfo);
7508 hlinfo->mouse_face_mouse_frame = 0;
7515 NSTRACE ("[EmacsView menuDown:]");
7516 if (context_menu_value == -1)
7517 context_menu_value = [sender tag];
7520 NSInteger tag = [sender tag];
7521 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7522 emacsframe->menu_bar_vector,
7526 ns_send_appdefined (-1);
7531 - (EmacsToolbar *)toolbar
7537 /* this gets called on toolbar button click */
7538 - toolbarClicked: (id)item
7541 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7543 NSTRACE ("[EmacsView toolbarClicked:]");
7548 /* send first event (for some reason two needed) */
7549 theEvent = [[self window] currentEvent];
7550 emacs_event->kind = TOOL_BAR_EVENT;
7551 XSETFRAME (emacs_event->arg, emacsframe);
7552 EV_TRAILER (theEvent);
7554 emacs_event->kind = TOOL_BAR_EVENT;
7555 /* XSETINT (emacs_event->code, 0); */
7556 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7557 idx + TOOL_BAR_ITEM_KEY);
7558 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7559 EV_TRAILER (theEvent);
7564 - toggleToolbar: (id)sender
7566 NSTRACE ("[EmacsView toggleToolbar:]");
7571 emacs_event->kind = NS_NONKEY_EVENT;
7572 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7573 EV_TRAILER ((id)nil);
7578 - (void)drawRect: (NSRect)rect
7580 int x = NSMinX (rect), y = NSMinY (rect);
7581 int width = NSWidth (rect), height = NSHeight (rect);
7583 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7584 NSTRACE_ARG_RECT(rect));
7586 if (!emacsframe || !emacsframe->output_data.ns)
7589 ns_clear_frame_area (emacsframe, x, y, width, height);
7591 expose_frame (emacsframe, x, y, width, height);
7595 drawRect: may be called (at least in OS X 10.5) for invisible
7596 views as well for some reason. Thus, do not infer visibility
7599 emacsframe->async_visible = 1;
7600 emacsframe->async_iconified = 0;
7605 /* NSDraggingDestination protocol methods. Actually this is not really a
7606 protocol, but a category of Object. O well... */
7608 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7610 NSTRACE ("[EmacsView draggingEntered:]");
7611 return NSDragOperationGeneric;
7615 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7621 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7626 NSEvent *theEvent = [[self window] currentEvent];
7628 NSDragOperation op = [sender draggingSourceOperationMask];
7631 NSTRACE ("[EmacsView performDragOperation:]");
7636 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7637 x = lrint (position.x); y = lrint (position.y);
7639 pb = [sender draggingPasteboard];
7640 type = [pb availableTypeFromArray: ns_drag_types];
7642 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7643 // URL drags contain all operations (0xf), don't allow all to be set.
7646 if (op & NSDragOperationLink)
7647 modifiers |= NSControlKeyMask;
7648 if (op & NSDragOperationCopy)
7649 modifiers |= NSAlternateKeyMask;
7650 if (op & NSDragOperationGeneric)
7651 modifiers |= NSCommandKeyMask;
7654 modifiers = EV_MODIFIERS2 (modifiers);
7659 else if ([type isEqualToString: NSFilenamesPboardType])
7662 NSEnumerator *fenum;
7665 if (!(files = [pb propertyListForType: type]))
7668 fenum = [files objectEnumerator];
7669 while ( (file = [fenum nextObject]) )
7671 emacs_event->kind = DRAG_N_DROP_EVENT;
7672 XSETINT (emacs_event->x, x);
7673 XSETINT (emacs_event->y, y);
7674 ns_input_file = append2 (ns_input_file,
7675 build_string ([file UTF8String]));
7676 emacs_event->modifiers = modifiers;
7677 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7678 EV_TRAILER (theEvent);
7682 else if ([type isEqualToString: NSURLPboardType])
7684 NSURL *url = [NSURL URLFromPasteboard: pb];
7685 if (url == nil) return NO;
7687 emacs_event->kind = DRAG_N_DROP_EVENT;
7688 XSETINT (emacs_event->x, x);
7689 XSETINT (emacs_event->y, y);
7690 emacs_event->modifiers = modifiers;
7691 emacs_event->arg = list2 (Qurl,
7692 build_string ([[url absoluteString]
7694 EV_TRAILER (theEvent);
7696 if ([url isFileURL] != NO)
7698 NSString *file = [url path];
7699 ns_input_file = append2 (ns_input_file,
7700 build_string ([file UTF8String]));
7704 else if ([type isEqualToString: NSStringPboardType]
7705 || [type isEqualToString: NSTabularTextPboardType])
7709 if (! (data = [pb stringForType: type]))
7712 emacs_event->kind = DRAG_N_DROP_EVENT;
7713 XSETINT (emacs_event->x, x);
7714 XSETINT (emacs_event->y, y);
7715 emacs_event->modifiers = modifiers;
7716 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7717 EV_TRAILER (theEvent);
7722 fprintf (stderr, "Invalid data type in dragging pasteboard");
7728 - (id) validRequestorForSendType: (NSString *)typeSent
7729 returnType: (NSString *)typeReturned
7731 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7732 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7733 && typeReturned == nil)
7735 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7739 return [super validRequestorForSendType: typeSent
7740 returnType: typeReturned];
7744 /* The next two methods are part of NSServicesRequests informal protocol,
7745 supposedly called when a services menu item is chosen from this app.
7746 But this should not happen because we override the services menu with our
7747 own entries which call ns-perform-service.
7748 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7749 So let's at least stub them out until further investigation can be done. */
7751 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7753 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7754 be written into the buffer in place of the existing selection..
7755 ordinary service calls go through functions defined in ns-win.el */
7759 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7761 NSArray *typesDeclared;
7764 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7766 /* We only support NSStringPboardType */
7767 if ([types containsObject:NSStringPboardType] == NO) {
7771 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7772 if (CONSP (val) && SYMBOLP (XCAR (val)))
7775 if (CONSP (val) && NILP (XCDR (val)))
7778 if (! STRINGP (val))
7781 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7782 [pb declareTypes:typesDeclared owner:nil];
7783 ns_string_to_pasteboard (pb, val);
7788 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7789 (gives a miniaturized version of the window); currently we use the latter for
7790 frames whose active buffer doesn't correspond to any file
7791 (e.g., '*scratch*') */
7792 - setMiniwindowImage: (BOOL) setMini
7794 id image = [[self window] miniwindowImage];
7795 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7797 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7798 about "AppleDockIconEnabled" notwithstanding, however the set message
7799 below has its effect nonetheless. */
7800 if (image != emacsframe->output_data.ns->miniimage)
7802 if (image && [image isKindOfClass: [EmacsImage class]])
7804 [[self window] setMiniwindowImage:
7805 setMini ? emacsframe->output_data.ns->miniimage : nil];
7812 - (void) setRows: (int) r andColumns: (int) c
7814 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7819 - (int) fullscreenState
7824 @end /* EmacsView */
7828 /* ==========================================================================
7830 EmacsWindow implementation
7832 ========================================================================== */
7834 @implementation EmacsWindow
7836 #ifdef NS_IMPL_COCOA
7837 - (id)accessibilityAttributeValue:(NSString *)attribute
7839 Lisp_Object str = Qnil;
7840 struct frame *f = SELECTED_FRAME ();
7841 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7843 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7845 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7846 return NSAccessibilityTextFieldRole;
7848 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7849 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7851 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7853 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7855 if (! NILP (BVAR (curbuf, mark_active)))
7856 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7860 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7861 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7862 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7864 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7865 str = make_uninit_multibyte_string (range, byte_range);
7867 str = make_uninit_string (range);
7868 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7869 Is this a problem? */
7870 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7877 if (CONSP (str) && SYMBOLP (XCAR (str)))
7880 if (CONSP (str) && NILP (XCDR (str)))
7885 const char *utfStr = SSDATA (str);
7886 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7891 return [super accessibilityAttributeValue:attribute];
7893 #endif /* NS_IMPL_COCOA */
7895 /* Constrain size and placement of a frame.
7897 By returning the original "frameRect", the frame is not
7898 constrained. This can lead to unwanted situations where, for
7899 example, the menu bar covers the frame.
7901 The default implementation (accessed using "super") constrains the
7902 frame to the visible area of SCREEN, minus the menu bar (if
7903 present) and the Dock. Note that default implementation also calls
7904 windowWillResize, with the frame it thinks should have. (This can
7905 make the frame exit maximized mode.)
7907 Note that this should work in situations where multiple monitors
7908 are present. Common configurations are side-by-side monitors and a
7909 monitor on top of another (e.g. when a laptop is placed under a
7911 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7913 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7914 NSTRACE_ARG_RECT (frameRect));
7916 #ifdef NS_IMPL_COCOA
7917 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7918 // If separate spaces is on, it is like each screen is independent. There is
7919 // no spanning of frames across screens.
7920 if ([NSScreen screensHaveSeparateSpaces])
7922 NSTRACE_MSG ("Screens have separate spaces");
7923 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7924 NSTRACE_RETURN_RECT (frameRect);
7930 return constrain_frame_rect(frameRect,
7931 [(EmacsView *)[self delegate] isFullscreen]);
7935 - (void)performZoom:(id)sender
7937 NSTRACE ("[EmacsWindow performZoom:]");
7939 return [super performZoom:sender];
7942 - (void)zoom:(id)sender
7944 NSTRACE ("[EmacsWindow zoom:]");
7946 ns_update_auto_hide_menu_bar();
7948 // Below are three zoom implementations. In the final commit, the
7949 // idea is that the last should be included.
7952 // Native zoom done using the standard zoom animation. Size of the
7953 // resulting frame reduced to accommodate the Dock and, if present,
7955 [super zoom:sender];
7958 // Native zoom done using the standard zoom animation, plus an
7959 // explicit resize to cover the full screen, except the menu-bar and
7960 // dock, if present.
7961 [super zoom:sender];
7963 // After the native zoom, resize the resulting frame to fill the
7964 // entire screen, except the menu-bar.
7966 // This works for all practical purposes. (The only minor oddity is
7967 // when transiting from full-height frame to a maximized, the
7968 // animation reduces the height of the frame slightly (to the 4
7969 // pixels needed to accommodate the Doc) before it snaps back into
7970 // full height. The user would need a very trained eye to spot
7972 NSScreen * screen = [self screen];
7975 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7977 NSTRACE_FSTYPE ("fullscreenState", fs_state);
7979 NSRect sr = [screen frame];
7980 struct EmacsMargins margins
7981 = ns_screen_margins_ignoring_hidden_dock(screen);
7983 NSRect wr = [self frame];
7984 NSTRACE_RECT ("Rect after zoom", wr);
7988 if (fs_state == FULLSCREEN_MAXIMIZED
7989 || fs_state == FULLSCREEN_HEIGHT)
7991 newWr.origin.y = sr.origin.y + margins.bottom;
7992 newWr.size.height = sr.size.height - margins.top - margins.bottom;
7995 if (fs_state == FULLSCREEN_MAXIMIZED
7996 || fs_state == FULLSCREEN_WIDTH)
7998 newWr.origin.x = sr.origin.x + margins.left;
7999 newWr.size.width = sr.size.width - margins.right - margins.left;
8002 if (newWr.size.width != wr.size.width
8003 || newWr.size.height != wr.size.height
8004 || newWr.origin.x != wr.origin.x
8005 || newWr.origin.y != wr.origin.y)
8007 NSTRACE_MSG ("New frame different");
8008 [self setFrame: newWr display: NO];
8012 // Non-native zoom which is done instantaneously. The resulting
8013 // frame covers the entire screen, except the menu-bar and dock, if
8015 NSScreen * screen = [self screen];
8018 NSRect sr = [screen frame];
8019 struct EmacsMargins margins
8020 = ns_screen_margins_ignoring_hidden_dock(screen);
8022 sr.size.height -= (margins.top + margins.bottom);
8023 sr.size.width -= (margins.left + margins.right);
8024 sr.origin.x += margins.left;
8025 sr.origin.y += margins.bottom;
8027 sr = [[self delegate] windowWillUseStandardFrame:self
8029 [self setFrame: sr display: NO];
8034 - (void)setFrame:(NSRect)windowFrame
8035 display:(BOOL)displayViews
8037 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8038 NSTRACE_ARG_RECT (windowFrame), displayViews);
8040 [super setFrame:windowFrame display:displayViews];
8043 - (void)setFrame:(NSRect)windowFrame
8044 display:(BOOL)displayViews
8045 animate:(BOOL)performAnimation
8047 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8048 " display:%d performAnimation:%d]",
8049 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8051 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8054 - (void)setFrameTopLeftPoint:(NSPoint)point
8056 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8057 NSTRACE_ARG_POINT (point));
8059 [super setFrameTopLeftPoint:point];
8061 @end /* EmacsWindow */
8064 @implementation EmacsFSWindow
8066 - (BOOL)canBecomeKeyWindow
8071 - (BOOL)canBecomeMainWindow
8078 /* ==========================================================================
8080 EmacsScroller implementation
8082 ========================================================================== */
8085 @implementation EmacsScroller
8087 /* for repeat button push */
8088 #define SCROLL_BAR_FIRST_DELAY 0.5
8089 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8091 + (CGFloat) scrollerWidth
8093 /* TODO: if we want to allow variable widths, this is the place to do it,
8094 however neither GNUstep nor Cocoa support it very well */
8096 #if !defined (NS_IMPL_COCOA) || \
8097 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8098 r = [NSScroller scrollerWidth];
8100 r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
8101 scrollerStyle: NSScrollerStyleLegacy];
8107 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8109 NSTRACE ("[EmacsScroller initFrame: window:]");
8111 r.size.width = [EmacsScroller scrollerWidth];
8112 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8113 [self setContinuous: YES];
8114 [self setEnabled: YES];
8116 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8117 locked against the top and bottom edges, and right edge on OS X, where
8118 scrollers are on right. */
8119 #ifdef NS_IMPL_GNUSTEP
8120 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8122 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8125 window = XWINDOW (nwin);
8127 pixel_height = NSHeight (r);
8128 if (pixel_height == 0) pixel_height = 1;
8129 min_portion = 20 / pixel_height;
8131 frame = XFRAME (window->frame);
8132 if (FRAME_LIVE_P (frame))
8135 EmacsView *view = FRAME_NS_VIEW (frame);
8136 NSView *sview = [[view window] contentView];
8137 NSArray *subs = [sview subviews];
8139 /* disable optimization stopping redraw of other scrollbars */
8140 view->scrollbarsNeedingUpdate = 0;
8141 for (i =[subs count]-1; i >= 0; i--)
8142 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8143 view->scrollbarsNeedingUpdate++;
8144 [sview addSubview: self];
8147 /* [self setFrame: r]; */
8153 - (void)setFrame: (NSRect)newRect
8155 NSTRACE ("[EmacsScroller setFrame:]");
8157 /* block_input (); */
8158 pixel_height = NSHeight (newRect);
8159 if (pixel_height == 0) pixel_height = 1;
8160 min_portion = 20 / pixel_height;
8161 [super setFrame: newRect];
8162 /* unblock_input (); */
8168 NSTRACE ("[EmacsScroller dealloc]");
8170 wset_vertical_scroll_bar (window, Qnil);
8178 NSTRACE ("[EmacsScroller condemn]");
8186 NSTRACE ("[EmacsScroller reprieve]");
8194 NSTRACE ("[EmacsScroller judge]");
8195 bool ret = condemned;
8200 /* ensure other scrollbar updates after deletion */
8201 view = (EmacsView *)FRAME_NS_VIEW (frame);
8203 view->scrollbarsNeedingUpdate++;
8205 wset_vertical_scroll_bar (window, Qnil);
8207 [self removeFromSuperview];
8215 - (void)resetCursorRects
8217 NSRect visible = [self visibleRect];
8218 NSTRACE ("[EmacsScroller resetCursorRects]");
8220 if (!NSIsEmptyRect (visible))
8221 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8222 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8226 - (int) checkSamePosition: (int) position portion: (int) portion
8229 return em_position ==position && em_portion ==portion && em_whole ==whole
8230 && portion != whole; /* needed for resize empty buf */
8234 - setPosition: (int)position portion: (int)portion whole: (int)whole
8236 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8238 em_position = position;
8239 em_portion = portion;
8242 if (portion >= whole)
8244 #ifdef NS_IMPL_COCOA
8245 [self setKnobProportion: 1.0];
8246 [self setDoubleValue: 1.0];
8248 [self setFloatValue: 0.0 knobProportion: 1.0];
8255 portion = max ((float)whole*min_portion/pixel_height, portion);
8256 pos = (float)position / (whole - portion);
8257 por = (CGFloat)portion/whole;
8258 #ifdef NS_IMPL_COCOA
8259 [self setKnobProportion: por];
8260 [self setDoubleValue: pos];
8262 [self setFloatValue: pos knobProportion: por];
8269 /* set up emacs_event */
8270 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8274 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8279 emacs_event->part = last_hit_part;
8280 emacs_event->code = 0;
8281 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8282 XSETWINDOW (win, window);
8283 emacs_event->frame_or_window = win;
8284 emacs_event->timestamp = EV_TIMESTAMP (e);
8285 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8286 emacs_event->arg = Qnil;
8287 XSETINT (emacs_event->x, loc * pixel_height);
8288 XSETINT (emacs_event->y, pixel_height-20);
8292 n_emacs_events_pending++;
8293 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8296 hold_event (emacs_event);
8297 EVENT_INIT (*emacs_event);
8298 ns_send_appdefined (-1);
8302 /* called manually thru timer to implement repeated button action w/hold-down */
8303 - repeatScroll: (NSTimer *)scrollEntry
8305 NSEvent *e = [[self window] currentEvent];
8306 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8307 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8309 NSTRACE ("[EmacsScroller repeatScroll:]");
8311 /* clear timer if need be */
8312 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8314 [scroll_repeat_entry invalidate];
8315 [scroll_repeat_entry release];
8316 scroll_repeat_entry = nil;
8322 = [[NSTimer scheduledTimerWithTimeInterval:
8323 SCROLL_BAR_CONTINUOUS_DELAY
8325 selector: @selector (repeatScroll:)
8331 [self sendScrollEventAtLoc: 0 fromEvent: e];
8336 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8337 mouseDragged events without going into a modal loop. */
8338 - (void)mouseDown: (NSEvent *)e
8341 /* hitPart is only updated AFTER event is passed on */
8342 NSScrollerPart part = [self testPart: [e locationInWindow]];
8343 CGFloat inc = 0.0, loc, kloc, pos;
8346 NSTRACE ("[EmacsScroller mouseDown:]");
8350 case NSScrollerDecrementPage:
8351 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8352 case NSScrollerIncrementPage:
8353 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8354 case NSScrollerDecrementLine:
8355 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8356 case NSScrollerIncrementLine:
8357 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8358 case NSScrollerKnob:
8359 last_hit_part = scroll_bar_handle; break;
8360 case NSScrollerKnobSlot: /* GNUstep-only */
8361 last_hit_part = scroll_bar_move_ratio; break;
8362 default: /* NSScrollerNoPart? */
8363 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8370 pos = 0; /* ignored */
8372 /* set a timer to repeat, as we can't let superclass do this modally */
8374 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8376 selector: @selector (repeatScroll:)
8383 /* handle, or on GNUstep possibly slot */
8384 NSEvent *fake_event;
8386 /* compute float loc in slot and mouse offset on knob */
8387 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8389 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8395 else if (loc >= NSHeight (sr))
8397 loc = NSHeight (sr);
8405 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8407 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8409 last_mouse_offset = kloc;
8411 /* if knob, tell emacs a location offset by knob pos
8412 (to indicate top of handle) */
8413 if (part == NSScrollerKnob)
8414 pos = (loc - last_mouse_offset) / NSHeight (sr);
8416 /* else this is a slot click on GNUstep: go straight there */
8417 pos = loc / NSHeight (sr);
8419 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8420 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8421 location: [e locationInWindow]
8422 modifierFlags: [e modifierFlags]
8423 timestamp: [e timestamp]
8424 windowNumber: [e windowNumber]
8425 context: [e context]
8426 eventNumber: [e eventNumber]
8427 clickCount: [e clickCount]
8428 pressure: [e pressure]];
8429 [super mouseUp: fake_event];
8432 if (part != NSScrollerKnob)
8433 [self sendScrollEventAtLoc: pos fromEvent: e];
8437 /* Called as we manually track scroller drags, rather than superclass. */
8438 - (void)mouseDragged: (NSEvent *)e
8443 NSTRACE ("[EmacsScroller mouseDragged:]");
8445 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8447 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8453 else if (loc >= NSHeight (sr) + last_mouse_offset)
8455 loc = NSHeight (sr) + last_mouse_offset;
8458 pos = (loc - last_mouse_offset) / NSHeight (sr);
8459 [self sendScrollEventAtLoc: pos fromEvent: e];
8463 - (void)mouseUp: (NSEvent *)e
8465 NSTRACE ("[EmacsScroller mouseUp:]");
8467 if (scroll_repeat_entry)
8469 [scroll_repeat_entry invalidate];
8470 [scroll_repeat_entry release];
8471 scroll_repeat_entry = nil;
8473 last_hit_part = scroll_bar_above_handle;
8477 /* treat scrollwheel events in the bar as though they were in the main window */
8478 - (void) scrollWheel: (NSEvent *)theEvent
8480 NSTRACE ("[EmacsScroller scrollWheel:]");
8482 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8483 [view mouseDown: theEvent];
8486 @end /* EmacsScroller */
8489 #ifdef NS_IMPL_GNUSTEP
8490 /* Dummy class to get rid of startup warnings. */
8491 @implementation EmacsDocument
8497 /* ==========================================================================
8499 Font-related functions; these used to be in nsfaces.m
8501 ========================================================================== */
8505 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8507 struct font *font = XFONT_OBJECT (font_object);
8508 EmacsView *view = FRAME_NS_VIEW (f);
8509 int font_ascent, font_descent;
8512 fontset = fontset_from_font (font_object);
8513 FRAME_FONTSET (f) = fontset;
8515 if (FRAME_FONT (f) == font)
8516 /* This font is already set in frame F. There's nothing more to
8520 FRAME_FONT (f) = font;
8522 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8523 FRAME_COLUMN_WIDTH (f) = font->average_width;
8524 get_font_ascent_descent (font, &font_ascent, &font_descent);
8525 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8527 /* Compute the scroll bar width in character columns. */
8528 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8530 int wid = FRAME_COLUMN_WIDTH (f);
8531 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8532 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8536 int wid = FRAME_COLUMN_WIDTH (f);
8537 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8540 /* Compute the scroll bar height in character lines. */
8541 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8543 int height = FRAME_LINE_HEIGHT (f);
8544 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8545 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8549 int height = FRAME_LINE_HEIGHT (f);
8550 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8553 /* Now make the frame display the given font. */
8554 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8555 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8556 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8563 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8564 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8568 ns_xlfd_to_fontname (const char *xlfd)
8569 /* --------------------------------------------------------------------------
8570 Convert an X font name (XLFD) to an NS font name.
8571 Only family is used.
8572 The string returned is temporarily allocated.
8573 -------------------------------------------------------------------------- */
8575 char *name = xmalloc (180);
8579 if (!strncmp (xlfd, "--", 2))
8580 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8582 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8584 /* stopgap for malformed XLFD input */
8585 if (strlen (name) == 0)
8586 strcpy (name, "Monaco");
8588 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8589 also uppercase after '-' or ' ' */
8590 name[0] = c_toupper (name[0]);
8591 for (len =strlen (name), i =0; i<len; i++)
8597 name[i+1] = c_toupper (name[i+1]);
8599 else if (name[i] == '_')
8603 name[i+1] = c_toupper (name[i+1]);
8606 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8607 ret = [[NSString stringWithUTF8String: name] UTF8String];
8614 syms_of_nsterm (void)
8616 NSTRACE ("syms_of_nsterm");
8618 ns_antialias_threshold = 10.0;
8620 /* from 23+ we need to tell emacs what modifiers there are.. */
8621 DEFSYM (Qmodifier_value, "modifier-value");
8622 DEFSYM (Qalt, "alt");
8623 DEFSYM (Qhyper, "hyper");
8624 DEFSYM (Qmeta, "meta");
8625 DEFSYM (Qsuper, "super");
8626 DEFSYM (Qcontrol, "control");
8627 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8629 DEFSYM (Qfile, "file");
8630 DEFSYM (Qurl, "url");
8632 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8633 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8634 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8635 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8636 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8638 DEFVAR_LISP ("ns-input-file", ns_input_file,
8639 "The file specified in the last NS event.");
8640 ns_input_file =Qnil;
8642 DEFVAR_LISP ("ns-working-text", ns_working_text,
8643 "String for visualizing working composition sequence.");
8644 ns_working_text =Qnil;
8646 DEFVAR_LISP ("ns-input-font", ns_input_font,
8647 "The font specified in the last NS event.");
8648 ns_input_font =Qnil;
8650 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8651 "The fontsize specified in the last NS event.");
8652 ns_input_fontsize =Qnil;
8654 DEFVAR_LISP ("ns-input-line", ns_input_line,
8655 "The line specified in the last NS event.");
8656 ns_input_line =Qnil;
8658 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8659 "The service name specified in the last NS event.");
8660 ns_input_spi_name =Qnil;
8662 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8663 "The service argument specified in the last NS event.");
8664 ns_input_spi_arg =Qnil;
8666 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8667 "This variable describes the behavior of the alternate or option key.\n\
8668 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8669 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8670 at all, allowing it to be used at a lower level for accented character entry.");
8671 ns_alternate_modifier = Qmeta;
8673 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8674 "This variable describes the behavior of the right 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 left means be the same key as `ns-alternate-modifier'.\n\
8677 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8678 at all, allowing it to be used at a lower level for accented character entry.");
8679 ns_right_alternate_modifier = Qleft;
8681 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8682 "This variable describes the behavior of the command key.\n\
8683 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8684 ns_command_modifier = Qsuper;
8686 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8687 "This variable describes the behavior of the right command key.\n\
8688 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8689 Set to left means be the same key as `ns-command-modifier'.\n\
8690 Set to none means that the command / option key is not interpreted by Emacs\n\
8691 at all, allowing it to be used at a lower level for accented character entry.");
8692 ns_right_command_modifier = Qleft;
8694 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8695 "This variable describes the behavior of the control key.\n\
8696 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8697 ns_control_modifier = Qcontrol;
8699 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8700 "This variable describes the behavior of the right control key.\n\
8701 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8702 Set to left means be the same key as `ns-control-modifier'.\n\
8703 Set to none means that the control / option key is not interpreted by Emacs\n\
8704 at all, allowing it to be used at a lower level for accented character entry.");
8705 ns_right_control_modifier = Qleft;
8707 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8708 "This variable describes the behavior of the function key (on laptops).\n\
8709 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8710 Set to none means that the function key is not interpreted by Emacs at all,\n\
8711 allowing it to be used at a lower level for accented character entry.");
8712 ns_function_modifier = Qnone;
8714 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8715 "Non-nil (the default) means to render text antialiased.");
8716 ns_antialias_text = Qt;
8718 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8719 "Whether to confirm application quit using dialog.");
8720 ns_confirm_quit = Qnil;
8722 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8723 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8724 Only works on OSX 10.6 or later. */);
8725 ns_auto_hide_menu_bar = Qnil;
8727 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8728 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8729 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8730 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
8731 Default is t for OSX >= 10.7, nil otherwise. */);
8732 #ifdef HAVE_NATIVE_FS
8733 ns_use_native_fullscreen = YES;
8735 ns_use_native_fullscreen = NO;
8737 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8739 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8740 doc: /*Non-nil means use animation on non-native fullscreen.
8741 For native fullscreen, this does nothing.
8742 Default is nil. */);
8743 ns_use_fullscreen_animation = NO;
8745 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8746 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8747 Note that this does not apply to images.
8748 This variable is ignored on OSX < 10.7 and GNUstep. */);
8749 ns_use_srgb_colorspace = YES;
8751 /* TODO: move to common code */
8752 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8753 doc: /* Which toolkit scroll bars Emacs uses, if any.
8754 A value of nil means Emacs doesn't use toolkit scroll bars.
8755 With the X Window system, the value is a symbol describing the
8756 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8757 With MS Windows or Nextstep, the value is t. */);
8758 Vx_toolkit_scroll_bars = Qt;
8760 DEFVAR_BOOL ("x-use-underline-position-properties",
8761 x_use_underline_position_properties,
8762 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8763 A value of nil means ignore them. If you encounter fonts with bogus
8764 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8765 to 4.1, set this to nil. */);
8766 x_use_underline_position_properties = 0;
8768 DEFVAR_BOOL ("x-underline-at-descent-line",
8769 x_underline_at_descent_line,
8770 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8771 A value of nil means to draw the underline according to the value of the
8772 variable `x-use-underline-position-properties', which is usually at the
8773 baseline level. The default value is nil. */);
8774 x_underline_at_descent_line = 0;
8776 /* Tell Emacs about this window system. */
8777 Fprovide (Qns, Qnil);
8779 DEFSYM (Qcocoa, "cocoa");
8780 DEFSYM (Qgnustep, "gnustep");
8782 #ifdef NS_IMPL_COCOA
8783 Fprovide (Qcocoa, Qnil);
8786 Fprovide (Qgnustep, Qnil);