1 /* NeXT/Open/GNUstep / MacOSX communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 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
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
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
73 int term_trace_num = 0;
74 #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
75 __FILE__, __LINE__, ++term_trace_num)
80 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
82 int term_trace_num = 0;
83 #define NSTRACE_SIZE(str,size) fprintf (stderr, \
85 " (S:%.0f x %.0f)\n", \
86 __FILE__, __LINE__, ++term_trace_num,\
89 #define NSTRACE_RECT(s,r) fprintf (stderr, \
91 " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
92 __FILE__, __LINE__, ++term_trace_num,\
98 #define NSTRACE_SIZE(str,size)
99 #define NSTRACE_RECT(s,r)
102 extern NSString *NSMenuDidBeginTrackingNotification;
104 /* ==========================================================================
106 NSColor, EmacsColor category.
108 ========================================================================== */
109 @implementation NSColor (EmacsColor)
110 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
111 blue:(CGFloat)blue alpha:(CGFloat)alpha
114 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
115 if (ns_use_srgb_colorspace)
116 return [NSColor colorWithSRGBRed: red
122 return [NSColor colorWithCalibratedRed: red
128 - (NSColor *)colorUsingDefaultColorSpace
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
132 if (ns_use_srgb_colorspace)
133 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
136 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
141 /* ==========================================================================
145 ========================================================================== */
147 /* Convert a symbol indexed with an NSxxx value to a value as defined
148 in keyboard.c (lispy_function_key). I hope this is a correct way
149 of doing things... */
150 static unsigned convert_ns_to_X_keysym[] =
152 NSHomeFunctionKey, 0x50,
153 NSLeftArrowFunctionKey, 0x51,
154 NSUpArrowFunctionKey, 0x52,
155 NSRightArrowFunctionKey, 0x53,
156 NSDownArrowFunctionKey, 0x54,
157 NSPageUpFunctionKey, 0x55,
158 NSPageDownFunctionKey, 0x56,
159 NSEndFunctionKey, 0x57,
160 NSBeginFunctionKey, 0x58,
161 NSSelectFunctionKey, 0x60,
162 NSPrintFunctionKey, 0x61,
163 NSClearLineFunctionKey, 0x0B,
164 NSExecuteFunctionKey, 0x62,
165 NSInsertFunctionKey, 0x63,
166 NSUndoFunctionKey, 0x65,
167 NSRedoFunctionKey, 0x66,
168 NSMenuFunctionKey, 0x67,
169 NSFindFunctionKey, 0x68,
170 NSHelpFunctionKey, 0x6A,
171 NSBreakFunctionKey, 0x6B,
173 NSF1FunctionKey, 0xBE,
174 NSF2FunctionKey, 0xBF,
175 NSF3FunctionKey, 0xC0,
176 NSF4FunctionKey, 0xC1,
177 NSF5FunctionKey, 0xC2,
178 NSF6FunctionKey, 0xC3,
179 NSF7FunctionKey, 0xC4,
180 NSF8FunctionKey, 0xC5,
181 NSF9FunctionKey, 0xC6,
182 NSF10FunctionKey, 0xC7,
183 NSF11FunctionKey, 0xC8,
184 NSF12FunctionKey, 0xC9,
185 NSF13FunctionKey, 0xCA,
186 NSF14FunctionKey, 0xCB,
187 NSF15FunctionKey, 0xCC,
188 NSF16FunctionKey, 0xCD,
189 NSF17FunctionKey, 0xCE,
190 NSF18FunctionKey, 0xCF,
191 NSF19FunctionKey, 0xD0,
192 NSF20FunctionKey, 0xD1,
193 NSF21FunctionKey, 0xD2,
194 NSF22FunctionKey, 0xD3,
195 NSF23FunctionKey, 0xD4,
196 NSF24FunctionKey, 0xD5,
198 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
199 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
200 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
202 NSTabCharacter, 0x09,
203 0x19, 0x09, /* left tab->regular since pass shift */
204 NSCarriageReturnCharacter, 0x0D,
205 NSNewlineCharacter, 0x0D,
206 NSEnterCharacter, 0x8D,
208 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
209 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
210 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
211 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
212 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
213 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
214 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
215 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
216 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
217 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
218 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
219 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
220 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
221 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
222 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
223 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
225 0x1B, 0x1B /* escape */
228 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
229 the maximum font size to NOT antialias. On GNUstep there is currently
230 no way to control this behavior. */
231 float ns_antialias_threshold;
233 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
234 NSString *ns_app_name = @"Emacs"; /* default changed later */
236 /* Display variables */
237 struct ns_display_info *x_display_list; /* Chain of existing displays */
238 long context_menu_value = 0;
241 static struct frame *ns_updating_frame;
242 static NSView *focus_view = NULL;
243 static int ns_window_num = 0;
244 #ifdef NS_IMPL_GNUSTEP
247 static BOOL gsaved = NO;
248 static BOOL ns_fake_keydown = NO;
250 static BOOL ns_menu_bar_is_hidden = NO;
252 /*static int debug_lock = 0; */
255 static BOOL send_appdefined = YES;
256 #define NO_APPDEFINED_DATA (-8)
257 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
258 static NSTimer *timed_entry = 0;
259 static NSTimer *scroll_repeat_entry = nil;
260 static fd_set select_readfds, select_writefds;
261 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
262 static int select_nfds = 0, select_valid = 0;
263 static struct timespec select_timeout = { 0, 0 };
264 static int selfds[2] = { -1, -1 };
265 static pthread_mutex_t select_mutex;
266 static int apploopnr = 0;
267 static NSAutoreleasePool *outerpool;
268 static struct input_event *emacs_event = NULL;
269 static struct input_event *q_event_ptr = NULL;
270 static int n_emacs_events_pending = 0;
271 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
272 *ns_pending_service_args;
273 static BOOL ns_do_open_file = NO;
274 static BOOL ns_last_use_native_fullscreen;
276 /* Non-zero means that a HELP_EVENT has been generated since Emacs
279 static BOOL any_help_event_p = NO;
282 struct input_event *q;
288 static NSString *represented_filename = nil;
289 static struct frame *represented_frame = 0;
293 * State for pending menu activation:
294 * MENU_NONE Normal state
295 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
296 * run lisp to update the menu.
297 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
301 #define MENU_PENDING 1
302 #define MENU_OPENING 2
303 static int menu_will_open_state = MENU_NONE;
305 /* Saved position for menu click. */
306 static CGPoint menu_mouse_point;
309 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
310 #define NS_FUNCTION_KEY_MASK 0x800000
311 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
312 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
313 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
314 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
315 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
316 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
317 #define EV_MODIFIERS2(flags) \
318 (((flags & NSHelpKeyMask) ? \
319 hyper_modifier : 0) \
320 | (!EQ (ns_right_alternate_modifier, Qleft) && \
321 ((flags & NSRightAlternateKeyMask) \
322 == NSRightAlternateKeyMask) ? \
323 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
324 | ((flags & NSAlternateKeyMask) ? \
325 parse_solitary_modifier (ns_alternate_modifier) : 0) \
326 | ((flags & NSShiftKeyMask) ? \
327 shift_modifier : 0) \
328 | (!EQ (ns_right_control_modifier, Qleft) && \
329 ((flags & NSRightControlKeyMask) \
330 == NSRightControlKeyMask) ? \
331 parse_solitary_modifier (ns_right_control_modifier) : 0) \
332 | ((flags & NSControlKeyMask) ? \
333 parse_solitary_modifier (ns_control_modifier) : 0) \
334 | ((flags & NS_FUNCTION_KEY_MASK) ? \
335 parse_solitary_modifier (ns_function_modifier) : 0) \
336 | (!EQ (ns_right_command_modifier, Qleft) && \
337 ((flags & NSRightCommandKeyMask) \
338 == NSRightCommandKeyMask) ? \
339 parse_solitary_modifier (ns_right_command_modifier) : 0) \
340 | ((flags & NSCommandKeyMask) ? \
341 parse_solitary_modifier (ns_command_modifier):0))
342 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
344 #define EV_UDMODIFIERS(e) \
345 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
346 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
347 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
348 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
349 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
350 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
351 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
352 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
353 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
355 #define EV_BUTTON(e) \
356 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
357 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
358 [e buttonNumber] - 1)
360 /* Convert the time field to a timestamp in milliseconds. */
361 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
363 /* This is a piece of code which is common to all the event handling
364 methods. Maybe it should even be a function. */
365 #define EV_TRAILER(e) \
367 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
371 #define EV_TRAILER2(e) \
373 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
376 Lisp_Object tem = Vinhibit_quit; \
377 Vinhibit_quit = Qt; \
378 n_emacs_events_pending++; \
379 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
380 Vinhibit_quit = tem; \
383 hold_event (emacs_event); \
384 EVENT_INIT (*emacs_event); \
385 ns_send_appdefined (-1); \
388 /* TODO: get rid of need for these forward declarations */
389 static void ns_condemn_scroll_bars (struct frame *f);
390 static void ns_judge_scroll_bars (struct frame *f);
391 void x_set_frame_alpha (struct frame *f);
394 /* ==========================================================================
398 ========================================================================== */
401 ns_set_represented_filename (NSString* fstr, struct frame *f)
403 represented_filename = [fstr retain];
404 represented_frame = f;
408 ns_init_events (struct input_event* ev)
421 hold_event (struct input_event *event)
423 if (hold_event_q.nr == hold_event_q.cap)
425 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
426 else hold_event_q.cap *= 2;
428 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
431 hold_event_q.q[hold_event_q.nr++] = *event;
432 /* Make sure ns_read_socket is called, i.e. we have input. */
434 send_appdefined = YES;
438 append2 (Lisp_Object list, Lisp_Object item)
439 /* --------------------------------------------------------------------------
440 Utility to append to a list
441 -------------------------------------------------------------------------- */
443 return CALLN (Fnconc, list, list1 (item));
448 ns_etc_directory (void)
449 /* If running as a self-contained app bundle, return as a string the
450 filename of the etc directory, if present; else nil. */
452 NSBundle *bundle = [NSBundle mainBundle];
453 NSString *resourceDir = [bundle resourcePath];
454 NSString *resourcePath;
455 NSFileManager *fileManager = [NSFileManager defaultManager];
458 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
459 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
461 if (isDir) return [resourcePath UTF8String];
469 /* If running as a self-contained app bundle, return as a path string
470 the filenames of the libexec and bin directories, ie libexec:bin.
471 Otherwise, return nil.
472 Normally, Emacs does not add its own bin/ directory to the PATH.
473 However, a self-contained NS build has a different layout, with
474 bin/ and libexec/ subdirectories in the directory that contains
476 We put libexec first, because init_callproc_1 uses the first
477 element to initialize exec-directory. An alternative would be
478 for init_callproc to check for invocation-directory/libexec.
481 NSBundle *bundle = [NSBundle mainBundle];
482 NSString *resourceDir = [bundle resourcePath];
483 NSString *binDir = [bundle bundlePath];
484 NSString *resourcePath, *resourcePaths;
486 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
487 NSFileManager *fileManager = [NSFileManager defaultManager];
489 NSEnumerator *pathEnum;
492 range = [resourceDir rangeOfString: @"Contents"];
493 if (range.location != NSNotFound)
495 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
497 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
501 paths = [binDir stringsByAppendingPaths:
502 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
503 pathEnum = [paths objectEnumerator];
506 while ((resourcePath = [pathEnum nextObject]))
508 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
511 if ([resourcePaths length] > 0)
513 = [resourcePaths stringByAppendingString: pathSeparator];
515 = [resourcePaths stringByAppendingString: resourcePath];
518 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
526 /* If running as a self-contained app bundle, return as a path string
527 the filenames of the site-lisp and lisp directories.
528 Ie, site-lisp:lisp. Otherwise, return nil. */
530 NSBundle *bundle = [NSBundle mainBundle];
531 NSString *resourceDir = [bundle resourcePath];
532 NSString *resourcePath, *resourcePaths;
533 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
534 NSFileManager *fileManager = [NSFileManager defaultManager];
536 NSArray *paths = [resourceDir stringsByAppendingPaths:
537 [NSArray arrayWithObjects:
538 @"site-lisp", @"lisp", nil]];
539 NSEnumerator *pathEnum = [paths objectEnumerator];
542 /* Hack to skip site-lisp. */
543 if (no_site_lisp) resourcePath = [pathEnum nextObject];
545 while ((resourcePath = [pathEnum nextObject]))
547 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
550 if ([resourcePaths length] > 0)
552 = [resourcePaths stringByAppendingString: pathSeparator];
554 = [resourcePaths stringByAppendingString: resourcePath];
557 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
563 ns_timeout (int usecs)
564 /* --------------------------------------------------------------------------
565 Blocking timer utility used by ns_ring_bell
566 -------------------------------------------------------------------------- */
568 struct timespec wakeup = timespec_add (current_timespec (),
569 make_timespec (0, usecs * 1000));
571 /* Keep waiting until past the time wakeup. */
574 struct timespec timeout, now = current_timespec ();
575 if (timespec_cmp (wakeup, now) <= 0)
577 timeout = timespec_sub (wakeup, now);
579 /* Try to wait that long--but we might wake up sooner. */
580 pselect (0, NULL, NULL, NULL, &timeout, NULL);
586 ns_release_object (void *obj)
587 /* --------------------------------------------------------------------------
588 Release an object (callable from C)
589 -------------------------------------------------------------------------- */
596 ns_retain_object (void *obj)
597 /* --------------------------------------------------------------------------
598 Retain an object (callable from C)
599 -------------------------------------------------------------------------- */
606 ns_alloc_autorelease_pool (void)
607 /* --------------------------------------------------------------------------
608 Allocate a pool for temporary objects (callable from C)
609 -------------------------------------------------------------------------- */
611 return [[NSAutoreleasePool alloc] init];
616 ns_release_autorelease_pool (void *pool)
617 /* --------------------------------------------------------------------------
618 Free a pool and temporary objects it refers to (callable from C)
619 -------------------------------------------------------------------------- */
621 ns_release_object (pool);
626 /* ==========================================================================
628 Focus (clipping) and screen update
630 ========================================================================== */
633 // Window constraining
634 // -------------------
636 // To ensure that the windows are not placed under the menu bar, they
637 // are typically moved by the call-back constrainFrameRect. However,
638 // by overriding it, it's possible to inhibit this, leaving the window
639 // in it's original position.
641 // It's possible to hide the menu bar. However, technically, it's only
642 // possible to hide it when the application is active. To ensure that
643 // this work properly, the menu bar and window constraining are
644 // deferred until the application becomes active.
646 // Even though it's not possible to manually move a window above the
647 // top of the screen, it is allowed if it's done programmatically,
648 // when the menu is hidden. This allows the editable area to cover the
649 // full screen height.
654 // Use the following extra files:
657 // ;; Hide menu and place frame slightly above the top of the screen.
658 // (setq ns-auto-hide-menu-bar t)
659 // (set-frame-position (selected-frame) 0 -20)
663 // emacs -Q -l init.el
665 // Result: No menu bar, and the title bar should be above the screen.
671 // Result: Menu bar visible, frame placed immediately below the menu.
675 ns_constrain_all_frames (void)
677 Lisp_Object tail, frame;
679 FOR_EACH_FRAME (tail, frame)
681 struct frame *f = XFRAME (frame);
684 NSView *view = FRAME_NS_VIEW (f);
685 /* This no-op will trigger the default window placing
686 * constraint system. */
687 [[view window] setFrameOrigin:[[view window] frame].origin];
693 /* True, if the menu bar should be hidden. */
696 ns_menu_bar_should_be_hidden (void)
698 return !NILP (ns_auto_hide_menu_bar)
699 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
703 /* Show or hide the menu bar, based on user setting. */
706 ns_update_auto_hide_menu_bar (void)
711 NSTRACE (ns_update_auto_hide_menu_bar);
713 if (NSApp != nil && [NSApp isActive])
715 // Note, "setPresentationOptions" triggers an error unless the
716 // application is active.
717 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
719 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
721 NSApplicationPresentationOptions options
722 = NSApplicationPresentationDefault;
724 if (menu_bar_should_be_hidden)
725 options |= NSApplicationPresentationAutoHideMenuBar
726 | NSApplicationPresentationAutoHideDock;
728 [NSApp setPresentationOptions: options];
730 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
732 if (!ns_menu_bar_is_hidden)
734 ns_constrain_all_frames ();
745 ns_update_begin (struct frame *f)
746 /* --------------------------------------------------------------------------
747 Prepare for a grouped sequence of drawing calls
748 external (RIF) call; whole frame, called before update_window_begin
749 -------------------------------------------------------------------------- */
751 EmacsView *view = FRAME_NS_VIEW (f);
752 NSTRACE (ns_update_begin);
754 ns_update_auto_hide_menu_bar ();
757 if ([view isFullscreen] && [view fsIsNative])
759 // Fix reappearing tool bar in fullscreen for OSX 10.7
760 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
761 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
762 if (! tbar_visible != ! [toolbar isVisible])
763 [toolbar setVisible: tbar_visible];
767 ns_updating_frame = f;
770 /* drawRect may have been called for say the minibuffer, and then clip path
771 is for the minibuffer. But the display engine may draw more because
772 we have set the frame as garbaged. So reset clip path to the whole
777 NSRect r = [view frame];
778 NSRect cr = [[view window] frame];
779 /* If a large frame size is set, r may be larger than the window frame
780 before constrained. In that case don't change the clip path, as we
781 will clear in to the tool bar and title bar. */
783 + FRAME_NS_TITLEBAR_HEIGHT (f)
784 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
786 bp = [[NSBezierPath bezierPathWithRect: r] retain];
793 #ifdef NS_IMPL_GNUSTEP
794 uRect = NSMakeRect (0, 0, 0, 0);
800 ns_update_window_begin (struct window *w)
801 /* --------------------------------------------------------------------------
802 Prepare for a grouped sequence of drawing calls
803 external (RIF) call; for one window, called after update_begin
804 -------------------------------------------------------------------------- */
806 struct frame *f = XFRAME (WINDOW_FRAME (w));
807 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
809 NSTRACE (ns_update_window_begin);
810 w->output_cursor = w->cursor;
814 if (f == hlinfo->mouse_face_mouse_frame)
816 /* Don't do highlighting for mouse motion during the update. */
817 hlinfo->mouse_face_defer = 1;
819 /* If the frame needs to be redrawn,
820 simply forget about any prior mouse highlighting. */
821 if (FRAME_GARBAGED_P (f))
822 hlinfo->mouse_face_window = Qnil;
824 /* (further code for mouse faces ifdef'd out in other terms elided) */
832 ns_update_window_end (struct window *w, bool cursor_on_p,
833 bool mouse_face_overwritten_p)
834 /* --------------------------------------------------------------------------
835 Finished a grouped sequence of drawing calls
836 external (RIF) call; for one window called before update_end
837 -------------------------------------------------------------------------- */
839 /* note: this fn is nearly identical in all terms */
840 if (!w->pseudo_window_p)
845 display_and_set_cursor (w, 1,
846 w->output_cursor.hpos, w->output_cursor.vpos,
847 w->output_cursor.x, w->output_cursor.y);
849 if (draw_window_fringes (w, 1))
851 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
852 x_draw_right_divider (w);
854 x_draw_vertical_border (w);
860 /* If a row with mouse-face was overwritten, arrange for
861 frame_up_to_date to redisplay the mouse highlight. */
862 if (mouse_face_overwritten_p)
863 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
865 NSTRACE (update_window_end);
870 ns_update_end (struct frame *f)
871 /* --------------------------------------------------------------------------
872 Finished a grouped sequence of drawing calls
873 external (RIF) call; for whole frame, called after update_window_end
874 -------------------------------------------------------------------------- */
876 EmacsView *view = FRAME_NS_VIEW (f);
878 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
879 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
884 [[view window] flushWindow];
887 ns_updating_frame = NULL;
888 NSTRACE (ns_update_end);
892 ns_focus (struct frame *f, NSRect *r, int n)
893 /* --------------------------------------------------------------------------
894 Internal: Focus on given frame. During small local updates this is used to
895 draw, however during large updates, ns_update_begin and ns_update_end are
896 called to wrap the whole thing, in which case these calls are stubbed out.
897 Except, on GNUstep, we accumulate the rectangle being drawn into, because
898 the back end won't do this automatically, and will just end up flushing
900 -------------------------------------------------------------------------- */
902 // NSTRACE (ns_focus);
904 fprintf (stderr, "focus: %d", c++);
905 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
906 fprintf (stderr, "\n"); */
908 if (f != ns_updating_frame)
910 NSView *view = FRAME_NS_VIEW (f);
911 if (view != focus_view)
913 if (focus_view != NULL)
915 [focus_view unlockFocus];
916 [[focus_view window] flushWindow];
923 /*if (view) debug_lock++; */
930 [[NSGraphicsContext currentContext] saveGraphicsState];
932 NSRectClipList (r, 2);
941 ns_unfocus (struct frame *f)
942 /* --------------------------------------------------------------------------
943 Internal: Remove focus on given frame
944 -------------------------------------------------------------------------- */
946 // NSTRACE (ns_unfocus);
950 [[NSGraphicsContext currentContext] restoreGraphicsState];
954 if (f != ns_updating_frame)
956 if (focus_view != NULL)
958 [focus_view unlockFocus];
959 [[focus_view window] flushWindow];
968 ns_clip_to_row (struct window *w, struct glyph_row *row,
969 enum glyph_row_area area, BOOL gc)
970 /* --------------------------------------------------------------------------
971 Internal (but parallels other terms): Focus drawing on given row
972 -------------------------------------------------------------------------- */
974 struct frame *f = XFRAME (WINDOW_FRAME (w));
976 int window_x, window_y, window_width;
978 window_box (w, area, &window_x, &window_y, &window_width, 0);
980 clip_rect.origin.x = window_x;
981 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
982 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
983 clip_rect.size.width = window_width;
984 clip_rect.size.height = row->visible_height;
986 ns_focus (f, &clip_rect, 1);
991 ns_ring_bell (struct frame *f)
992 /* --------------------------------------------------------------------------
994 -------------------------------------------------------------------------- */
996 NSTRACE (ns_ring_bell);
999 NSAutoreleasePool *pool;
1000 struct frame *frame = SELECTED_FRAME ();
1004 pool = [[NSAutoreleasePool alloc] init];
1006 view = FRAME_NS_VIEW (frame);
1010 NSPoint dim = NSMakePoint (128, 128);
1013 r.origin.x += (r.size.width - dim.x) / 2;
1014 r.origin.y += (r.size.height - dim.y) / 2;
1015 r.size.width = dim.x;
1016 r.size.height = dim.y;
1017 surr = NSInsetRect (r, -2, -2);
1018 ns_focus (frame, &surr, 1);
1019 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1020 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1021 (FRAME_DEFAULT_FACE (frame)), frame) set];
1023 [[view window] flushWindow];
1024 ns_timeout (150000);
1025 [[view window] restoreCachedImage];
1026 [[view window] flushWindow];
1038 /* ==========================================================================
1040 Frame / window manager related functions
1042 ========================================================================== */
1046 ns_raise_frame (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048 Bring window to foreground and make it active
1049 -------------------------------------------------------------------------- */
1052 check_window_system (f);
1053 view = FRAME_NS_VIEW (f);
1055 if (FRAME_VISIBLE_P (f))
1056 [[view window] makeKeyAndOrderFront: NSApp];
1062 ns_lower_frame (struct frame *f)
1063 /* --------------------------------------------------------------------------
1065 -------------------------------------------------------------------------- */
1068 check_window_system (f);
1069 view = FRAME_NS_VIEW (f);
1071 [[view window] orderBack: NSApp];
1077 ns_frame_raise_lower (struct frame *f, bool raise)
1078 /* --------------------------------------------------------------------------
1080 -------------------------------------------------------------------------- */
1082 NSTRACE (ns_frame_raise_lower);
1092 ns_frame_rehighlight (struct frame *frame)
1093 /* --------------------------------------------------------------------------
1094 External (hook): called on things like window switching within frame
1095 -------------------------------------------------------------------------- */
1097 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1098 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1100 NSTRACE (ns_frame_rehighlight);
1101 if (dpyinfo->x_focus_frame)
1103 dpyinfo->x_highlight_frame
1104 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1105 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1106 : dpyinfo->x_focus_frame);
1107 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1109 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1110 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1114 dpyinfo->x_highlight_frame = 0;
1116 if (dpyinfo->x_highlight_frame &&
1117 dpyinfo->x_highlight_frame != old_highlight)
1121 x_update_cursor (old_highlight, 1);
1122 x_set_frame_alpha (old_highlight);
1124 if (dpyinfo->x_highlight_frame)
1126 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1127 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1134 x_make_frame_visible (struct frame *f)
1135 /* --------------------------------------------------------------------------
1136 External: Show the window (X11 semantics)
1137 -------------------------------------------------------------------------- */
1139 NSTRACE (x_make_frame_visible);
1140 /* XXX: at some points in past this was not needed, as the only place that
1141 called this (frame.c:Fraise_frame ()) also called raise_lower;
1142 if this ends up the case again, comment this out again. */
1143 if (!FRAME_VISIBLE_P (f))
1145 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1147 SET_FRAME_VISIBLE (f, 1);
1150 /* Making a new frame from a fullscreen frame will make the new frame
1151 fullscreen also. So skip handleFS as this will print an error. */
1152 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1153 && [view isFullscreen])
1156 if (f->want_fullscreen != FULLSCREEN_NONE)
1167 x_make_frame_invisible (struct frame *f)
1168 /* --------------------------------------------------------------------------
1169 External: Hide the window (X11 semantics)
1170 -------------------------------------------------------------------------- */
1173 NSTRACE (x_make_frame_invisible);
1174 check_window_system (f);
1175 view = FRAME_NS_VIEW (f);
1176 [[view window] orderOut: NSApp];
1177 SET_FRAME_VISIBLE (f, 0);
1178 SET_FRAME_ICONIFIED (f, 0);
1183 x_iconify_frame (struct frame *f)
1184 /* --------------------------------------------------------------------------
1185 External: Iconify window
1186 -------------------------------------------------------------------------- */
1189 struct ns_display_info *dpyinfo;
1191 NSTRACE (x_iconify_frame);
1192 check_window_system (f);
1193 view = FRAME_NS_VIEW (f);
1194 dpyinfo = FRAME_DISPLAY_INFO (f);
1196 if (dpyinfo->x_highlight_frame == f)
1197 dpyinfo->x_highlight_frame = 0;
1199 if ([[view window] windowNumber] <= 0)
1201 /* the window is still deferred. Make it very small, bring it
1202 on screen and order it out. */
1203 NSRect s = { { 100, 100}, {0, 0} };
1205 t = [[view window] frame];
1206 [[view window] setFrame: s display: NO];
1207 [[view window] orderBack: NSApp];
1208 [[view window] orderOut: NSApp];
1209 [[view window] setFrame: t display: NO];
1211 [[view window] miniaturize: NSApp];
1214 /* Free X resources of frame F. */
1217 x_free_frame_resources (struct frame *f)
1220 struct ns_display_info *dpyinfo;
1221 Mouse_HLInfo *hlinfo;
1223 NSTRACE (x_free_frame_resources);
1224 check_window_system (f);
1225 view = FRAME_NS_VIEW (f);
1226 dpyinfo = FRAME_DISPLAY_INFO (f);
1227 hlinfo = MOUSE_HL_INFO (f);
1229 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1233 free_frame_menubar (f);
1234 free_frame_faces (f);
1236 if (f == dpyinfo->x_focus_frame)
1237 dpyinfo->x_focus_frame = 0;
1238 if (f == dpyinfo->x_highlight_frame)
1239 dpyinfo->x_highlight_frame = 0;
1240 if (f == hlinfo->mouse_face_mouse_frame)
1241 reset_mouse_highlight (hlinfo);
1243 if (f->output_data.ns->miniimage != nil)
1244 [f->output_data.ns->miniimage release];
1246 [[view window] close];
1249 xfree (f->output_data.ns);
1255 x_destroy_window (struct frame *f)
1256 /* --------------------------------------------------------------------------
1257 External: Delete the window
1258 -------------------------------------------------------------------------- */
1260 NSTRACE (x_destroy_window);
1261 check_window_system (f);
1262 x_free_frame_resources (f);
1268 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1269 /* --------------------------------------------------------------------------
1270 External: Position the window
1271 -------------------------------------------------------------------------- */
1273 NSView *view = FRAME_NS_VIEW (f);
1274 NSArray *screens = [NSScreen screens];
1275 NSScreen *fscreen = [screens objectAtIndex: 0];
1276 NSScreen *screen = [[view window] screen];
1278 NSTRACE (x_set_offset);
1285 if (view != nil && screen && fscreen)
1287 f->left_pos = f->size_hint_flags & XNegative
1288 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1290 /* We use visibleFrame here to take menu bar into account.
1291 Ideally we should also adjust left/top with visibleFrame.origin. */
1293 f->top_pos = f->size_hint_flags & YNegative
1294 ? ([screen visibleFrame].size.height + f->top_pos
1295 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1296 - FRAME_TOOLBAR_HEIGHT (f))
1298 #ifdef NS_IMPL_GNUSTEP
1299 if (f->left_pos < 100)
1300 f->left_pos = 100; /* don't overlap menu */
1302 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1304 [[view window] setFrameTopLeftPoint:
1305 NSMakePoint (SCREENMAXBOUND (f->left_pos),
1306 SCREENMAXBOUND ([fscreen frame].size.height
1307 - NS_TOP_POS (f)))];
1308 f->size_hint_flags &= ~(XNegative|YNegative);
1316 x_set_window_size (struct frame *f,
1317 bool change_gravity,
1321 /* --------------------------------------------------------------------------
1322 Adjust window pixel size based on given character grid size
1323 Impl is a bit more complex than other terms, need to do some
1325 -------------------------------------------------------------------------- */
1327 EmacsView *view = FRAME_NS_VIEW (f);
1328 NSWindow *window = [view window];
1329 NSRect wr = [window frame];
1330 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1331 int pixelwidth, pixelheight;
1333 int orig_height = wr.size.height;
1335 NSTRACE (x_set_window_size);
1340 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1346 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1347 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1348 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1349 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1353 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1354 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1359 /* If we have a toolbar, take its height into account. */
1360 if (tb && ! [view isFullscreen])
1362 /* NOTE: previously this would generate wrong result if toolbar not
1363 yet displayed and fixing toolbar_height=32 helped, but
1364 now (200903) seems no longer needed */
1365 FRAME_TOOLBAR_HEIGHT (f) =
1366 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1367 - FRAME_NS_TITLEBAR_HEIGHT (f);
1369 /* Only breaks things here, removed by martin 2015-09-30. */
1370 #ifdef NS_IMPL_GNUSTEP
1371 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1376 FRAME_TOOLBAR_HEIGHT (f) = 0;
1378 wr.size.width = pixelwidth + f->border_width;
1379 wr.size.height = pixelheight;
1380 if (! [view isFullscreen])
1381 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1382 + FRAME_TOOLBAR_HEIGHT (f);
1384 /* Do not try to constrain to this screen. We may have multiple
1385 screens, and want Emacs to span those. Constraining to screen
1386 prevents that, and that is not nice to the user. */
1387 if (f->output_data.ns->zooming)
1388 f->output_data.ns->zooming = 0;
1390 wr.origin.y += orig_height - wr.size.height;
1392 frame_size_history_add
1393 (f, Qx_set_window_size_1, width, height,
1394 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1395 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1396 make_number (f->border_width),
1397 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1398 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1400 [view setRows: rows andColumns: cols];
1401 [window setFrame: wr display: YES];
1403 /* This is a trick to compensate for Emacs' managing the scrollbar area
1404 as a fixed number of standard character columns. Instead of leaving
1405 blank space for the extra, we chopped it off above. Now for
1406 left-hand scrollbars, we shift all rendering to the left by the
1407 difference between the real width and Emacs' imagined one. For
1408 right-hand bars, don't worry about it since the extra is never used.
1409 (Obviously doesn't work for vertically split windows tho..) */
1411 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1412 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1413 - NS_SCROLL_BAR_WIDTH (f), 0)
1414 : NSMakePoint (0, 0);
1415 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1416 [view setBoundsOrigin: origin];
1419 [view updateFrameSize: NO];
1425 ns_fullscreen_hook (struct frame *f)
1427 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1429 if (!FRAME_VISIBLE_P (f))
1432 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1434 /* Old style fs don't initiate correctly if created from
1435 init/default-frame alist, so use a timer (not nice...).
1437 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1438 selector: @selector (handleFS)
1439 userInfo: nil repeats: NO];
1448 /* ==========================================================================
1452 ========================================================================== */
1456 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1458 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1459 if (idx < 1 || idx >= color_table->avail)
1461 return color_table->colors[idx];
1466 ns_index_color (NSColor *color, struct frame *f)
1468 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1472 if (!color_table->colors)
1474 color_table->size = NS_COLOR_CAPACITY;
1475 color_table->avail = 1; /* skip idx=0 as marker */
1476 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1477 color_table->colors[0] = nil;
1478 color_table->empty_indices = [[NSMutableSet alloc] init];
1481 /* Do we already have this color? */
1482 for (i = 1; i < color_table->avail; i++)
1483 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1486 if ([color_table->empty_indices count] > 0)
1488 NSNumber *index = [color_table->empty_indices anyObject];
1489 [color_table->empty_indices removeObject: index];
1490 idx = [index unsignedLongValue];
1494 if (color_table->avail == color_table->size)
1495 color_table->colors =
1496 xpalloc (color_table->colors, &color_table->size, 1,
1497 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1498 idx = color_table->avail++;
1501 color_table->colors[idx] = color;
1503 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1509 ns_free_indexed_color (unsigned long idx, struct frame *f)
1511 struct ns_color_table *color_table;
1518 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1520 if (idx <= 0 || idx >= color_table->size) {
1521 message1 ("ns_free_indexed_color: Color index out of range.\n");
1525 index = [NSNumber numberWithUnsignedInt: idx];
1526 if ([color_table->empty_indices containsObject: index]) {
1527 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1531 color = color_table->colors[idx];
1533 color_table->colors[idx] = nil;
1534 [color_table->empty_indices addObject: index];
1535 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1540 ns_get_color (const char *name, NSColor **col)
1541 /* --------------------------------------------------------------------------
1543 -------------------------------------------------------------------------- */
1544 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1545 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1546 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1549 static char hex[20];
1551 float r = -1.0, g, b;
1552 NSString *nsname = [NSString stringWithUTF8String: name];
1554 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1557 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1559 #ifdef NS_IMPL_COCOA
1560 NSString *defname = [[NSUserDefaults standardUserDefaults]
1561 stringForKey: @"AppleHighlightColor"];
1566 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1568 *col = [new colorUsingDefaultColorSpace];
1573 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1575 name = [nsname UTF8String];
1577 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1579 /* NOTE: OSX applications normally don't set foreground selection, but
1580 text may be unreadable if we don't.
1582 if ((new = [NSColor selectedTextColor]) != nil)
1584 *col = [new colorUsingDefaultColorSpace];
1589 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1590 name = [nsname UTF8String];
1593 /* First, check for some sort of numeric specification. */
1596 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1598 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1599 [scanner scanFloat: &r];
1600 [scanner scanFloat: &g];
1601 [scanner scanFloat: &b];
1603 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1604 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1605 else if (name[0] == '#') /* An old X11 format; convert to newer */
1607 int len = (strlen(name) - 1);
1608 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1610 scaling = strlen(name+start) / 3;
1611 for (i = 0; i < 3; i++)
1612 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1613 name + start + i * scaling);
1614 hex[3 * (scaling + 1) - 1] = '\0';
1620 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1621 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1631 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1636 /* Otherwise, color is expected to be from a list */
1638 NSEnumerator *lenum, *cenum;
1642 #ifdef NS_IMPL_GNUSTEP
1643 /* XXX: who is wrong, the requestor or the implementation? */
1644 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1646 nsname = @"highlightColor";
1649 lenum = [[NSColorList availableColorLists] objectEnumerator];
1650 while ( (clist = [lenum nextObject]) && new == nil)
1652 cenum = [[clist allKeys] objectEnumerator];
1653 while ( (name = [cenum nextObject]) && new == nil )
1655 if ([name compare: nsname
1656 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1657 new = [clist colorWithKey: name];
1663 *col = [new colorUsingDefaultColorSpace];
1670 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1671 /* --------------------------------------------------------------------------
1672 Convert a Lisp string object to a NS color
1673 -------------------------------------------------------------------------- */
1675 NSTRACE (ns_lisp_to_color);
1676 if (STRINGP (color))
1677 return ns_get_color (SSDATA (color), col);
1678 else if (SYMBOLP (color))
1679 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1685 ns_color_to_lisp (NSColor *col)
1686 /* --------------------------------------------------------------------------
1687 Convert a color to a lisp string with the RGB equivalent
1688 -------------------------------------------------------------------------- */
1690 EmacsCGFloat red, green, blue, alpha, gray;
1693 NSTRACE (ns_color_to_lisp);
1696 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1698 if ((str =[[col colorNameComponent] UTF8String]))
1701 return build_string ((char *)str);
1704 [[col colorUsingDefaultColorSpace]
1705 getRed: &red green: &green blue: &blue alpha: &alpha];
1706 if (red == green && red == blue)
1708 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1709 getWhite: &gray alpha: &alpha];
1710 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1711 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1713 return build_string (buf);
1716 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1717 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1720 return build_string (buf);
1725 ns_query_color(void *col, XColor *color_def, int setPixel)
1726 /* --------------------------------------------------------------------------
1727 Get ARGB values out of NSColor col and put them into color_def.
1728 If setPixel, set the pixel to a concatenated version.
1729 and set color_def pixel to the resulting index.
1730 -------------------------------------------------------------------------- */
1732 EmacsCGFloat r, g, b, a;
1734 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1735 color_def->red = r * 65535;
1736 color_def->green = g * 65535;
1737 color_def->blue = b * 65535;
1739 if (setPixel == YES)
1741 = ARGB_TO_ULONG((int)(a*255),
1742 (int)(r*255), (int)(g*255), (int)(b*255));
1747 ns_defined_color (struct frame *f,
1752 /* --------------------------------------------------------------------------
1753 Return true if named color found, and set color_def rgb accordingly.
1754 If makeIndex and alloc are nonzero put the color in the color_table,
1755 and set color_def pixel to the resulting index.
1756 If makeIndex is zero, set color_def pixel to ARGB.
1757 Return false if not found
1758 -------------------------------------------------------------------------- */
1761 NSTRACE (ns_defined_color);
1764 if (ns_get_color (name, &col) != 0) /* Color not found */
1769 if (makeIndex && alloc)
1770 color_def->pixel = ns_index_color (col, f);
1771 ns_query_color (col, color_def, !makeIndex);
1778 x_set_frame_alpha (struct frame *f)
1779 /* --------------------------------------------------------------------------
1780 change the entire-frame transparency
1781 -------------------------------------------------------------------------- */
1783 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1785 double alpha_min = 1.0;
1787 if (dpyinfo->x_highlight_frame == f)
1788 alpha = f->alpha[0];
1790 alpha = f->alpha[1];
1792 if (FLOATP (Vframe_alpha_lower_limit))
1793 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1794 else if (INTEGERP (Vframe_alpha_lower_limit))
1795 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1799 else if (1.0 < alpha)
1801 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1804 #ifdef NS_IMPL_COCOA
1806 EmacsView *view = FRAME_NS_VIEW (f);
1807 [[view window] setAlphaValue: alpha];
1813 /* ==========================================================================
1817 ========================================================================== */
1821 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1822 /* --------------------------------------------------------------------------
1823 Programmatically reposition mouse pointer in pixel coordinates
1824 -------------------------------------------------------------------------- */
1826 NSTRACE (frame_set_mouse_pixel_position);
1829 /* FIXME: this does not work, and what about GNUstep? */
1830 #ifdef NS_IMPL_COCOA
1831 [FRAME_NS_VIEW (f) lockFocus];
1832 PSsetmouse ((float)pix_x, (float)pix_y);
1833 [FRAME_NS_VIEW (f) unlockFocus];
1839 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1840 /* ------------------------------------------------------------------------
1841 Called by EmacsView on mouseMovement events. Passes on
1842 to emacs mainstream code if we moved off of a rect of interest
1843 known as last_mouse_glyph.
1844 ------------------------------------------------------------------------ */
1846 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1849 // NSTRACE (note_mouse_movement);
1851 dpyinfo->last_mouse_motion_frame = frame;
1852 r = &dpyinfo->last_mouse_glyph;
1854 /* Note, this doesn't get called for enter/leave, since we don't have a
1855 position. Those are taken care of in the corresponding NSView methods. */
1857 /* has movement gone beyond last rect we were tracking? */
1858 if (x < r->origin.x || x >= r->origin.x + r->size.width
1859 || y < r->origin.y || y >= r->origin.y + r->size.height)
1861 ns_update_begin (frame);
1862 frame->mouse_moved = 1;
1863 note_mouse_highlight (frame, x, y);
1864 remember_mouse_glyph (frame, x, y, r);
1865 ns_update_end (frame);
1874 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1875 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1877 /* --------------------------------------------------------------------------
1878 External (hook): inform emacs about mouse position and hit parts.
1879 If a scrollbar is being dragged, set bar_window, part, x, y, time.
1880 x & y should be position in the scrollbar (the whole bar, not the handle)
1881 and length of scrollbar respectively
1882 -------------------------------------------------------------------------- */
1886 Lisp_Object frame, tail;
1888 struct ns_display_info *dpyinfo;
1890 NSTRACE (ns_mouse_position);
1894 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1898 dpyinfo = FRAME_DISPLAY_INFO (*fp);
1902 /* Clear the mouse-moved flag for every frame on this display. */
1903 FOR_EACH_FRAME (tail, frame)
1904 if (FRAME_NS_P (XFRAME (frame))
1905 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1906 XFRAME (frame)->mouse_moved = 0;
1908 dpyinfo->last_mouse_scroll_bar = nil;
1909 if (dpyinfo->last_mouse_frame
1910 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1911 f = dpyinfo->last_mouse_frame;
1913 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1915 if (f && FRAME_NS_P (f))
1917 view = FRAME_NS_VIEW (*fp);
1919 position = [[view window] mouseLocationOutsideOfEventStream];
1920 position = [view convertPoint: position fromView: nil];
1921 remember_mouse_glyph (f, position.x, position.y,
1922 &dpyinfo->last_mouse_glyph);
1923 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1925 if (bar_window) *bar_window = Qnil;
1926 if (part) *part = scroll_bar_above_handle;
1928 if (x) XSETINT (*x, lrint (position.x));
1929 if (y) XSETINT (*y, lrint (position.y));
1931 *time = dpyinfo->last_mouse_movement_time;
1940 ns_frame_up_to_date (struct frame *f)
1941 /* --------------------------------------------------------------------------
1942 External (hook): Fix up mouse highlighting right after a full update.
1943 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1944 -------------------------------------------------------------------------- */
1946 NSTRACE (ns_frame_up_to_date);
1950 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1951 if (f == hlinfo->mouse_face_mouse_frame)
1955 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1956 hlinfo->mouse_face_mouse_x,
1957 hlinfo->mouse_face_mouse_y);
1966 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1967 /* --------------------------------------------------------------------------
1968 External (RIF): set frame mouse pointer type.
1969 -------------------------------------------------------------------------- */
1971 NSTRACE (ns_define_frame_cursor);
1972 if (FRAME_POINTER_TYPE (f) != cursor)
1974 EmacsView *view = FRAME_NS_VIEW (f);
1975 FRAME_POINTER_TYPE (f) = cursor;
1976 [[view window] invalidateCursorRectsForView: view];
1977 /* Redisplay assumes this function also draws the changed frame
1978 cursor, but this function doesn't, so do it explicitly. */
1979 x_update_cursor (f, 1);
1985 /* ==========================================================================
1989 ========================================================================== */
1993 ns_convert_key (unsigned code)
1994 /* --------------------------------------------------------------------------
1995 Internal call used by NSView-keyDown.
1996 -------------------------------------------------------------------------- */
1998 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2000 /* An array would be faster, but less easy to read. */
2001 for (keysym = 0; keysym < last_keysym; keysym += 2)
2002 if (code == convert_ns_to_X_keysym[keysym])
2003 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2005 /* if decide to use keyCode and Carbon table, use this line:
2006 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2011 x_get_keysym_name (int keysym)
2012 /* --------------------------------------------------------------------------
2013 Called by keyboard.c. Not sure if the return val is important, except
2015 -------------------------------------------------------------------------- */
2017 static char value[16];
2018 NSTRACE (x_get_keysym_name);
2019 sprintf (value, "%d", keysym);
2025 /* ==========================================================================
2027 Block drawing operations
2029 ========================================================================== */
2033 ns_redraw_scroll_bars (struct frame *f)
2037 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2038 NSTRACE (ns_redraw_scroll_bars);
2039 for (i =[subviews count]-1; i >= 0; i--)
2041 view = [subviews objectAtIndex: i];
2042 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2049 ns_clear_frame (struct frame *f)
2050 /* --------------------------------------------------------------------------
2051 External (hook): Erase the entire frame
2052 -------------------------------------------------------------------------- */
2054 NSView *view = FRAME_NS_VIEW (f);
2057 NSTRACE (ns_clear_frame);
2059 /* comes on initial frame because we have
2060 after-make-frame-functions = select-frame */
2061 if (!FRAME_DEFAULT_FACE (f))
2064 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2069 ns_focus (f, &r, 1);
2070 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2074 /* as of 2006/11 or so this is now needed */
2075 ns_redraw_scroll_bars (f);
2081 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2082 /* --------------------------------------------------------------------------
2083 External (RIF): Clear section of frame
2084 -------------------------------------------------------------------------- */
2086 NSRect r = NSMakeRect (x, y, width, height);
2087 NSView *view = FRAME_NS_VIEW (f);
2088 struct face *face = FRAME_DEFAULT_FACE (f);
2093 NSTRACE (ns_clear_frame_area);
2095 r = NSIntersectionRect (r, [view frame]);
2096 ns_focus (f, &r, 1);
2097 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2106 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2108 if (FRAME_NS_VIEW (f))
2110 ns_focus (f, &dest, 1);
2111 [FRAME_NS_VIEW (f) scrollRect: src
2112 by: NSMakeSize (dest.origin.x - src.origin.x,
2113 dest.origin.y - src.origin.y)];
2119 ns_scroll_run (struct window *w, struct run *run)
2120 /* --------------------------------------------------------------------------
2121 External (RIF): Insert or delete n lines at line vpos
2122 -------------------------------------------------------------------------- */
2124 struct frame *f = XFRAME (w->frame);
2125 int x, y, width, height, from_y, to_y, bottom_y;
2127 NSTRACE (ns_scroll_run);
2129 /* begin copy from other terms */
2130 /* Get frame-relative bounding box of the text display area of W,
2131 without mode lines. Include in this box the left and right
2133 window_box (w, ANY_AREA, &x, &y, &width, &height);
2135 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2136 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2137 bottom_y = y + height;
2141 /* Scrolling up. Make sure we don't copy part of the mode
2142 line at the bottom. */
2143 if (from_y + run->height > bottom_y)
2144 height = bottom_y - from_y;
2146 height = run->height;
2150 /* Scrolling down. Make sure we don't copy over the mode line.
2152 if (to_y + run->height > bottom_y)
2153 height = bottom_y - to_y;
2155 height = run->height;
2157 /* end copy from other terms */
2167 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2168 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2170 ns_copy_bits (f, srcRect , dstRect);
2178 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2179 /* --------------------------------------------------------------------------
2180 External (RIF): preparatory to fringe update after text was updated
2181 -------------------------------------------------------------------------- */
2186 NSTRACE (ns_after_update_window_line);
2188 /* begin copy from other terms */
2191 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2192 desired_row->redraw_fringe_bitmaps_p = 1;
2194 /* When a window has disappeared, make sure that no rest of
2195 full-width rows stays visible in the internal border. */
2196 if (windows_or_buffers_changed
2197 && desired_row->full_width_p
2198 && (f = XFRAME (w->frame),
2199 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2201 && (height = desired_row->visible_height,
2204 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2207 ns_clear_frame_area (f, 0, y, width, height);
2208 ns_clear_frame_area (f,
2209 FRAME_PIXEL_WIDTH (f) - width,
2217 ns_shift_glyphs_for_insert (struct frame *f,
2218 int x, int y, int width, int height,
2220 /* --------------------------------------------------------------------------
2221 External (RIF): copy an area horizontally, don't worry about clearing src
2222 -------------------------------------------------------------------------- */
2224 NSRect srcRect = NSMakeRect (x, y, width, height);
2225 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2227 NSTRACE (ns_shift_glyphs_for_insert);
2229 ns_copy_bits (f, srcRect, dstRect);
2234 /* ==========================================================================
2236 Character encoding and metrics
2238 ========================================================================== */
2242 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2243 /* --------------------------------------------------------------------------
2244 External (RIF); compute left/right overhang of whole string and set in s
2245 -------------------------------------------------------------------------- */
2247 struct font *font = s->font;
2251 struct font_metrics metrics;
2252 unsigned int codes[2];
2253 codes[0] = *(s->char2b);
2254 codes[1] = *(s->char2b + s->nchars - 1);
2256 font->driver->text_extents (font, codes, 2, &metrics);
2257 s->left_overhang = -metrics.lbearing;
2259 = metrics.rbearing > metrics.width
2260 ? metrics.rbearing - metrics.width : 0;
2264 s->left_overhang = 0;
2265 if (EQ (font->driver->type, Qns))
2266 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2267 FONT_HEIGHT (font) * 0.2 : 0;
2269 s->right_overhang = 0;
2275 /* ==========================================================================
2277 Fringe and cursor drawing
2279 ========================================================================== */
2282 extern int max_used_fringe_bitmap;
2284 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2285 struct draw_fringe_bitmap_params *p)
2286 /* --------------------------------------------------------------------------
2287 External (RIF); fringe-related
2288 -------------------------------------------------------------------------- */
2290 struct frame *f = XFRAME (WINDOW_FRAME (w));
2291 struct face *face = p->face;
2292 static EmacsImage **bimgs = NULL;
2293 static int nBimgs = 0;
2295 /* grow bimgs if needed */
2296 if (nBimgs < max_used_fringe_bitmap)
2298 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2299 memset (bimgs + nBimgs, 0,
2300 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2301 nBimgs = max_used_fringe_bitmap;
2304 /* Must clip because of partially visible lines. */
2305 ns_clip_to_row (w, row, ANY_AREA, YES);
2309 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2311 if (bx >= 0 && nx > 0)
2313 NSRect r = NSMakeRect (bx, by, nx, ny);
2315 [ns_lookup_indexed_color (face->background, f) set];
2322 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2323 EmacsImage *img = bimgs[p->which - 1];
2327 unsigned short *bits = p->bits + p->dh;
2330 unsigned char *cbits = xmalloc (len);
2332 for (i = 0; i < len; i++)
2333 cbits[i] = ~(bits[i] & 0xff);
2334 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2336 bimgs[p->which - 1] = img;
2341 /* Since we composite the bitmap instead of just blitting it, we need
2342 to erase the whole background. */
2343 [ns_lookup_indexed_color(face->background, f) set];
2349 bm_color = ns_lookup_indexed_color(face->foreground, f);
2350 else if (p->overlay_p)
2351 bm_color = ns_lookup_indexed_color(face->background, f);
2353 bm_color = f->output_data.ns->cursor_color;
2354 [img setXBMColor: bm_color];
2357 #ifdef NS_IMPL_COCOA
2359 fromRect: NSZeroRect
2360 operation: NSCompositeSourceOver
2366 NSPoint pt = r.origin;
2368 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2377 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2378 int x, int y, enum text_cursor_kinds cursor_type,
2379 int cursor_width, bool on_p, bool active_p)
2380 /* --------------------------------------------------------------------------
2381 External call (RIF): draw cursor.
2382 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2383 -------------------------------------------------------------------------- */
2386 int fx, fy, h, cursor_height;
2387 struct frame *f = WINDOW_XFRAME (w);
2388 struct glyph *phys_cursor_glyph;
2389 struct glyph *cursor_glyph;
2391 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2393 /* If cursor is out of bounds, don't draw garbage. This can happen
2394 in mini-buffer windows when switching between echo area glyphs
2397 NSTRACE (dumpcursor);
2402 w->phys_cursor_type = cursor_type;
2403 w->phys_cursor_on_p = on_p;
2405 if (cursor_type == NO_CURSOR)
2407 w->phys_cursor_width = 0;
2411 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2413 if (glyph_row->exact_window_width_line_p
2414 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2416 glyph_row->cursor_in_fringe_p = 1;
2417 draw_fringe_bitmap (w, glyph_row, 0);
2422 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2423 (other terminals do it the other way round). We must set
2424 w->phys_cursor_width to the cursor width. For bar cursors, that
2425 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2426 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2428 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2429 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2430 if (cursor_type == BAR_CURSOR)
2432 if (cursor_width < 1)
2433 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2434 w->phys_cursor_width = cursor_width;
2436 /* If we have an HBAR, "cursor_width" MAY specify height. */
2437 else if (cursor_type == HBAR_CURSOR)
2439 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2440 if (cursor_height > glyph_row->height)
2441 cursor_height = glyph_row->height;
2442 if (h > cursor_height) // Cursor smaller than line height, move down
2443 fy += h - cursor_height;
2447 r.origin.x = fx, r.origin.y = fy;
2449 r.size.width = w->phys_cursor_width;
2451 /* TODO: only needed in rare cases with last-resort font in HELLO..
2452 should we do this more efficiently? */
2453 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2456 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2457 if (face && NS_FACE_BACKGROUND (face)
2458 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2460 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2461 hollow_color = FRAME_CURSOR_COLOR (f);
2464 [FRAME_CURSOR_COLOR (f) set];
2466 #ifdef NS_IMPL_COCOA
2467 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2468 atomic. Cleaner ways of doing this should be investigated.
2469 One way would be to set a global variable DRAWING_CURSOR
2470 when making the call to draw_phys..(), don't focus in that
2471 case, then move the ns_unfocus() here after that call. */
2472 NSDisableScreenUpdates ();
2475 switch (cursor_type)
2477 case DEFAULT_CURSOR:
2480 case FILLED_BOX_CURSOR:
2483 case HOLLOW_BOX_CURSOR:
2486 NSRectFill (NSInsetRect (r, 1, 1));
2487 [FRAME_CURSOR_COLOR (f) set];
2494 /* If the character under cursor is R2L, draw the bar cursor
2495 on the right of its glyph, rather than on the left. */
2496 cursor_glyph = get_phys_cursor_glyph (w);
2497 if ((cursor_glyph->resolved_level & 1) != 0)
2498 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2505 /* draw the character under the cursor */
2506 if (cursor_type != NO_CURSOR)
2507 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2509 #ifdef NS_IMPL_COCOA
2510 NSEnableScreenUpdates ();
2517 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2518 /* --------------------------------------------------------------------------
2519 External (RIF): Draw a vertical line.
2520 -------------------------------------------------------------------------- */
2522 struct frame *f = XFRAME (WINDOW_FRAME (w));
2524 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2526 NSTRACE (ns_draw_vertical_window_border);
2528 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2530 [ns_lookup_indexed_color(face->foreground, f) set];
2532 ns_focus (f, &r, 1);
2539 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2540 /* --------------------------------------------------------------------------
2541 External (RIF): Draw a window divider.
2542 -------------------------------------------------------------------------- */
2544 struct frame *f = XFRAME (WINDOW_FRAME (w));
2546 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2548 NSTRACE (ns_draw_window_divider);
2550 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2552 [ns_lookup_indexed_color(face->foreground, f) set];
2554 ns_focus (f, &r, 1);
2560 ns_show_hourglass (struct frame *f)
2562 /* TODO: add NSProgressIndicator to all frames. */
2566 ns_hide_hourglass (struct frame *f)
2568 /* TODO: remove NSProgressIndicator from all frames. */
2571 /* ==========================================================================
2573 Glyph drawing operations
2575 ========================================================================== */
2578 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2579 /* --------------------------------------------------------------------------
2580 Wrapper utility to account for internal border width on full-width lines,
2581 and allow top full-width rows to hit the frame top. nr should be pointer
2582 to two successive NSRects. Number of rects actually used is returned.
2583 -------------------------------------------------------------------------- */
2585 int n = get_glyph_string_clip_rects (s, nr, 2);
2589 /* --------------------------------------------------------------------
2590 Draw a wavy line under glyph string s. The wave fills wave_height
2597 wave_height = 3 | * * * *
2598 --------------------------------------------------------------------- */
2601 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2603 int wave_height = 3, wave_length = 2;
2604 int y, dx, dy, odd, xmax;
2609 dy = wave_height - 1;
2610 y = s->ybase - wave_height + 3;
2613 /* Find and set clipping rectangle */
2614 waveClip = NSMakeRect (x, y, width, wave_height);
2615 [[NSGraphicsContext currentContext] saveGraphicsState];
2616 NSRectClip (waveClip);
2618 /* Draw the waves */
2619 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2621 odd = (int)(a.x/dx) % 2;
2622 a.y = b.y = y + 0.5;
2631 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2632 a.x = b.x, a.y = b.y;
2633 b.x += dx, b.y = y + 0.5 + odd*dy;
2637 /* Restore previous clipping rectangle(s) */
2638 [[NSGraphicsContext currentContext] restoreGraphicsState];
2644 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2645 NSColor *defaultCol, CGFloat width, CGFloat x)
2646 /* --------------------------------------------------------------------------
2647 Draw underline, overline, and strike-through on glyph string s.
2648 -------------------------------------------------------------------------- */
2650 if (s->for_overlaps)
2654 if (face->underline_p)
2656 if (s->face->underline_type == FACE_UNDER_WAVE)
2658 if (face->underline_defaulted_p)
2661 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2663 ns_draw_underwave (s, width, x);
2665 else if (s->face->underline_type == FACE_UNDER_LINE)
2669 unsigned long thickness, position;
2671 /* If the prev was underlined, match its appearance. */
2672 if (s->prev && s->prev->face->underline_p
2673 && s->prev->face->underline_type == FACE_UNDER_LINE
2674 && s->prev->underline_thickness > 0)
2676 thickness = s->prev->underline_thickness;
2677 position = s->prev->underline_position;
2682 unsigned long descent;
2685 descent = s->y + s->height - s->ybase;
2687 /* Use underline thickness of font, defaulting to 1. */
2688 thickness = (font && font->underline_thickness > 0)
2689 ? font->underline_thickness : 1;
2691 /* Determine the offset of underlining from the baseline. */
2692 if (x_underline_at_descent_line)
2693 position = descent - thickness;
2694 else if (x_use_underline_position_properties
2695 && font && font->underline_position >= 0)
2696 position = font->underline_position;
2698 position = lround (font->descent / 2);
2700 position = underline_minimum_offset;
2702 position = max (position, underline_minimum_offset);
2704 /* Ensure underlining is not cropped. */
2705 if (descent <= position)
2707 position = descent - 1;
2710 else if (descent < position + thickness)
2714 s->underline_thickness = thickness;
2715 s->underline_position = position;
2717 r = NSMakeRect (x, s->ybase + position, width, thickness);
2719 if (face->underline_defaulted_p)
2722 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2726 /* Do overline. We follow other terms in using a thickness of 1
2727 and ignoring overline_margin. */
2728 if (face->overline_p)
2731 r = NSMakeRect (x, s->y, width, 1);
2733 if (face->overline_color_defaulted_p)
2736 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2740 /* Do strike-through. We follow other terms for thickness and
2741 vertical position.*/
2742 if (face->strike_through_p)
2747 dy = lrint ((s->height - 1) / 2);
2748 r = NSMakeRect (x, s->y + dy, width, 1);
2750 if (face->strike_through_color_defaulted_p)
2753 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2759 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2760 char left_p, char right_p)
2761 /* --------------------------------------------------------------------------
2762 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2763 Note we can't just use an NSDrawRect command, because of the possibility
2764 of some sides not being drawn, and because the rect will be filled.
2765 -------------------------------------------------------------------------- */
2771 s.size.height = thickness;
2773 s.origin.y += r.size.height - thickness;
2776 s.size.height = r.size.height;
2777 s.origin.y = r.origin.y;
2779 /* left, right (optional) */
2780 s.size.width = thickness;
2785 s.origin.x += r.size.width - thickness;
2792 ns_draw_relief (NSRect r, int thickness, char raised_p,
2793 char top_p, char bottom_p, char left_p, char right_p,
2794 struct glyph_string *s)
2795 /* --------------------------------------------------------------------------
2796 Draw a relief rect inside r, optionally leaving some sides open.
2797 Note we can't just use an NSDrawBezel command, because of the possibility
2798 of some sides not being drawn, and because the rect will be filled.
2799 -------------------------------------------------------------------------- */
2801 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2802 NSColor *newBaseCol = nil;
2805 NSTRACE (ns_draw_relief);
2809 if (s->face->use_box_color_for_shadows_p)
2811 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2813 /* else if (s->first_glyph->type == IMAGE_GLYPH
2815 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2817 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2821 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2824 if (newBaseCol == nil)
2825 newBaseCol = [NSColor grayColor];
2827 if (newBaseCol != baseCol) /* TODO: better check */
2830 baseCol = [newBaseCol retain];
2832 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2834 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2837 [(raised_p ? lightCol : darkCol) set];
2839 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2842 sr.size.height = thickness;
2843 if (top_p) NSRectFill (sr);
2846 sr.size.height = r.size.height;
2847 sr.size.width = thickness;
2848 if (left_p) NSRectFill (sr);
2850 [(raised_p ? darkCol : lightCol) set];
2853 sr.size.width = r.size.width;
2854 sr.size.height = thickness;
2855 sr.origin.y += r.size.height - thickness;
2856 if (bottom_p) NSRectFill (sr);
2859 sr.size.height = r.size.height;
2860 sr.origin.y = r.origin.y;
2861 sr.size.width = thickness;
2862 sr.origin.x += r.size.width - thickness;
2863 if (right_p) NSRectFill (sr);
2868 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2869 /* --------------------------------------------------------------------------
2870 Function modeled after x_draw_glyph_string_box ().
2871 Sets up parameters for drawing.
2872 -------------------------------------------------------------------------- */
2874 int right_x, last_x;
2875 char left_p, right_p;
2876 struct glyph *last_glyph;
2881 if (s->hl == DRAW_MOUSE_FACE)
2883 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2885 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2890 thickness = face->box_line_width;
2892 NSTRACE (ns_dumpglyphs_box_or_relief);
2894 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2895 ? WINDOW_RIGHT_EDGE_X (s->w)
2896 : window_box_right (s->w, s->area));
2897 last_glyph = (s->cmp || s->img
2898 ? s->first_glyph : s->first_glyph + s->nchars-1);
2900 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2901 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2903 left_p = (s->first_glyph->left_box_line_p
2904 || (s->hl == DRAW_MOUSE_FACE
2905 && (s->prev == NULL || s->prev->hl != s->hl)));
2906 right_p = (last_glyph->right_box_line_p
2907 || (s->hl == DRAW_MOUSE_FACE
2908 && (s->next == NULL || s->next->hl != s->hl)));
2910 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2912 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2913 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2915 ns_draw_box (r, abs (thickness),
2916 ns_lookup_indexed_color (face->box_color, s->f),
2921 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2922 1, 1, left_p, right_p, s);
2928 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2929 /* --------------------------------------------------------------------------
2930 Modeled after x_draw_glyph_string_background, which draws BG in
2931 certain cases. Others are left to the text rendering routine.
2932 -------------------------------------------------------------------------- */
2934 NSTRACE (ns_maybe_dumpglyphs_background);
2936 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2938 int box_line_width = max (s->face->box_line_width, 0);
2939 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2940 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
2941 dimensions, since the actual glyphs might be much
2942 smaller. So in that case we always clear the rectangle
2943 with background color. */
2944 || FONT_TOO_HIGH (s->font)
2945 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2948 if (s->hl == DRAW_MOUSE_FACE)
2950 face = FACE_FROM_ID (s->f,
2951 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2953 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2956 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2958 [(NS_FACE_BACKGROUND (face) != 0
2959 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2960 : FRAME_BACKGROUND_COLOR (s->f)) set];
2963 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2964 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2967 if (s->hl != DRAW_CURSOR)
2969 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2970 s->background_width,
2971 s->height-2*box_line_width);
2975 s->background_filled_p = 1;
2982 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2983 /* --------------------------------------------------------------------------
2984 Renders an image and associated borders.
2985 -------------------------------------------------------------------------- */
2987 EmacsImage *img = s->img->pixmap;
2988 int box_line_vwidth = max (s->face->box_line_width, 0);
2989 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2990 int bg_x, bg_y, bg_height;
2997 NSTRACE (ns_dumpglyphs_image);
2999 if (s->face->box != FACE_NO_BOX
3000 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3001 x += abs (s->face->box_line_width);
3004 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3005 bg_height = s->height;
3006 /* other terms have this, but was causing problems w/tabbar mode */
3007 /* - 2 * box_line_vwidth; */
3009 if (s->slice.x == 0) x += s->img->hmargin;
3010 if (s->slice.y == 0) y += s->img->vmargin;
3012 /* Draw BG: if we need larger area than image itself cleared, do that,
3013 otherwise, since we composite the image under NS (instead of mucking
3014 with its background color), we must clear just the image area. */
3015 if (s->hl == DRAW_MOUSE_FACE)
3017 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3019 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3022 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3024 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3026 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3027 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3029 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3030 s->background_filled_p = 1;
3034 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3039 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3042 #ifdef NS_IMPL_COCOA
3043 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3044 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3045 s->slice.width, s->slice.height);
3048 operation: NSCompositeSourceOver
3053 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3054 operation: NSCompositeSourceOver];
3058 if (s->hl == DRAW_CURSOR)
3060 [FRAME_CURSOR_COLOR (s->f) set];
3061 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3062 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3064 /* Currently on NS img->mask is always 0. Since
3065 get_window_cursor_type specifies a hollow box cursor when on
3066 a non-masked image we never reach this clause. But we put it
3067 in in anticipation of better support for image masks on
3069 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3073 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3076 /* Draw underline, overline, strike-through. */
3077 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3079 /* Draw relief, if requested */
3080 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3082 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3084 th = tool_bar_button_relief >= 0 ?
3085 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3086 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3090 th = abs (s->img->relief);
3091 raised_p = (s->img->relief > 0);
3094 r.origin.x = x - th;
3095 r.origin.y = y - th;
3096 r.size.width = s->slice.width + 2*th-1;
3097 r.size.height = s->slice.height + 2*th-1;
3098 ns_draw_relief (r, th, raised_p,
3100 s->slice.y + s->slice.height == s->img->height,
3102 s->slice.x + s->slice.width == s->img->width, s);
3105 /* If there is no mask, the background won't be seen,
3106 so draw a rectangle on the image for the cursor.
3107 Do this for all images, getting transparency right is not reliable. */
3108 if (s->hl == DRAW_CURSOR)
3110 int thickness = abs (s->img->relief);
3111 if (thickness == 0) thickness = 1;
3112 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3118 ns_dumpglyphs_stretch (struct glyph_string *s)
3123 NSColor *fgCol, *bgCol;
3125 if (!s->background_filled_p)
3127 n = ns_get_glyph_string_clip_rect (s, r);
3128 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3130 ns_focus (s->f, r, n);
3132 if (s->hl == DRAW_MOUSE_FACE)
3134 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3136 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3139 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3141 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3142 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3144 for (i = 0; i < n; ++i)
3146 if (!s->row->full_width_p)
3148 int overrun, leftoverrun;
3150 /* truncate to avoid overwriting fringe and/or scrollbar */
3151 overrun = max (0, (s->x + s->background_width)
3152 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3153 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3154 r[i].size.width -= overrun;
3156 /* truncate to avoid overwriting to left of the window box */
3157 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3158 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3160 if (leftoverrun > 0)
3162 r[i].origin.x += leftoverrun;
3163 r[i].size.width -= leftoverrun;
3166 /* XXX: Try to work between problem where a stretch glyph on
3167 a partially-visible bottom row will clear part of the
3168 modeline, and another where list-buffers headers and similar
3169 rows erroneously have visible_height set to 0. Not sure
3170 where this is coming from as other terms seem not to show. */
3171 r[i].size.height = min (s->height, s->row->visible_height);
3176 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3177 overwriting cursor (usually when cursor on a tab) */
3178 if (s->hl == DRAW_CURSOR)
3183 width = s->w->phys_cursor_width;
3184 r[i].size.width -= width;
3185 r[i].origin.x += width;
3189 /* Draw overlining, etc. on the cursor. */
3190 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3191 ns_draw_text_decoration (s, face, bgCol, width, x);
3193 ns_draw_text_decoration (s, face, fgCol, width, x);
3200 /* Draw overlining, etc. on the stretch glyph (or the part
3201 of the stretch glyph after the cursor). */
3202 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3206 s->background_filled_p = 1;
3212 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3215 struct font *font = s->font;
3217 /* If first glyph of S has a left box line, start drawing the text
3218 of S to the right of that box line. */
3219 if (s->face && s->face->box != FACE_NO_BOX
3220 && s->first_glyph->left_box_line_p)
3221 x = s->x + eabs (s->face->box_line_width);
3225 /* S is a glyph string for a composition. S->cmp_from is the index
3226 of the first character drawn for glyphs of this composition.
3227 S->cmp_from == 0 means we are drawing the very first character of
3228 this composition. */
3230 /* Draw a rectangle for the composition if the font for the very
3231 first character of the composition could not be loaded. */
3232 if (s->font_not_found_p)
3234 if (s->cmp_from == 0)
3236 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3237 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3240 else if (! s->first_glyph->u.cmp.automatic)
3244 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3245 /* TAB in a composition means display glyphs with padding
3246 space on the left or right. */
3247 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3249 int xx = x + s->cmp->offsets[j * 2];
3250 int yy = y - s->cmp->offsets[j * 2 + 1];
3252 font->driver->draw (s, j, j + 1, xx, yy, false);
3253 if (s->face->overstrike)
3254 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3259 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3264 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3266 glyph = LGSTRING_GLYPH (gstring, i);
3267 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3268 width += LGLYPH_WIDTH (glyph);
3271 int xoff, yoff, wadjust;
3275 font->driver->draw (s, j, i, x, y, false);
3276 if (s->face->overstrike)
3277 font->driver->draw (s, j, i, x + 1, y, false);
3280 xoff = LGLYPH_XOFF (glyph);
3281 yoff = LGLYPH_YOFF (glyph);
3282 wadjust = LGLYPH_WADJUST (glyph);
3283 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3284 if (s->face->overstrike)
3285 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3294 font->driver->draw (s, j, i, x, y, false);
3295 if (s->face->overstrike)
3296 font->driver->draw (s, j, i, x + 1, y, false);
3302 ns_draw_glyph_string (struct glyph_string *s)
3303 /* --------------------------------------------------------------------------
3304 External (RIF): Main draw-text call.
3305 -------------------------------------------------------------------------- */
3307 /* TODO (optimize): focus for box and contents draw */
3310 char box_drawn_p = 0;
3311 struct font *font = s->face->font;
3312 if (! font) font = FRAME_FONT (s->f);
3314 NSTRACE (ns_draw_glyph_string);
3316 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3319 struct glyph_string *next;
3321 for (width = 0, next = s->next;
3322 next && width < s->right_overhang;
3323 width += next->width, next = next->next)
3324 if (next->first_glyph->type != IMAGE_GLYPH)
3326 if (next->first_glyph->type != STRETCH_GLYPH)
3328 n = ns_get_glyph_string_clip_rect (s->next, r);
3329 ns_focus (s->f, r, n);
3330 ns_maybe_dumpglyphs_background (s->next, 1);
3335 ns_dumpglyphs_stretch (s->next);
3337 next->num_clips = 0;
3341 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3342 && (s->first_glyph->type == CHAR_GLYPH
3343 || s->first_glyph->type == COMPOSITE_GLYPH))
3345 n = ns_get_glyph_string_clip_rect (s, r);
3346 ns_focus (s->f, r, n);
3347 ns_maybe_dumpglyphs_background (s, 1);
3348 ns_dumpglyphs_box_or_relief (s);
3353 switch (s->first_glyph->type)
3357 n = ns_get_glyph_string_clip_rect (s, r);
3358 ns_focus (s->f, r, n);
3359 ns_dumpglyphs_image (s, r[0]);
3364 ns_dumpglyphs_stretch (s);
3368 case COMPOSITE_GLYPH:
3369 n = ns_get_glyph_string_clip_rect (s, r);
3370 ns_focus (s->f, r, n);
3372 if (s->for_overlaps || (s->cmp_from > 0
3373 && ! s->first_glyph->u.cmp.automatic))
3374 s->background_filled_p = 1;
3376 ns_maybe_dumpglyphs_background
3377 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3379 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3380 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3381 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3382 NS_DUMPGLYPH_NORMAL));
3384 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3386 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3387 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3388 NS_FACE_FOREGROUND (s->face) = tmp;
3392 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3395 ns_draw_composite_glyph_string_foreground (s);
3398 (s, s->cmp_from, s->nchars, s->x, s->ybase,
3399 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3400 || flags == NS_DUMPGLYPH_MOUSEFACE);
3404 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3405 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3407 : FRAME_FOREGROUND_COLOR (s->f));
3410 /* Draw underline, overline, strike-through. */
3411 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3414 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3416 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3417 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3418 NS_FACE_FOREGROUND (s->face) = tmp;
3424 case GLYPHLESS_GLYPH:
3425 n = ns_get_glyph_string_clip_rect (s, r);
3426 ns_focus (s->f, r, n);
3428 if (s->for_overlaps || (s->cmp_from > 0
3429 && ! s->first_glyph->u.cmp.automatic))
3430 s->background_filled_p = 1;
3432 ns_maybe_dumpglyphs_background
3433 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3435 /* Not yet implemented. */
3444 /* Draw box if not done already. */
3445 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3447 n = ns_get_glyph_string_clip_rect (s, r);
3448 ns_focus (s->f, r, n);
3449 ns_dumpglyphs_box_or_relief (s);
3458 /* ==========================================================================
3462 ========================================================================== */
3466 ns_send_appdefined (int value)
3467 /* --------------------------------------------------------------------------
3468 Internal: post an appdefined event which EmacsApp-sendEvent will
3469 recognize and take as a command to halt the event loop.
3470 -------------------------------------------------------------------------- */
3472 /*NSTRACE (ns_send_appdefined); */
3474 #ifdef NS_IMPL_GNUSTEP
3475 // GNUstep needs postEvent to happen on the main thread.
3476 if (! [[NSThread currentThread] isMainThread])
3478 EmacsApp *app = (EmacsApp *)NSApp;
3479 app->nextappdefined = value;
3480 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3487 /* Only post this event if we haven't already posted one. This will end
3488 the [NXApp run] main loop after having processed all events queued at
3491 #ifdef NS_IMPL_COCOA
3492 if (! send_appdefined)
3494 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3495 in certain situations (rapid incoming events).
3496 So check if we have one, if not add one. */
3497 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3498 untilDate:[NSDate distantPast]
3499 inMode:NSDefaultRunLoopMode
3501 if (! appev) send_appdefined = YES;
3505 if (send_appdefined)
3509 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3510 send_appdefined = NO;
3512 /* Don't need wakeup timer any more */
3515 [timed_entry invalidate];
3516 [timed_entry release];
3520 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3521 location: NSMakePoint (0, 0)
3524 windowNumber: [[NSApp mainWindow] windowNumber]
3525 context: [NSApp context]
3530 /* Post an application defined event on the event queue. When this is
3531 received the [NXApp run] will return, thus having processed all
3532 events which are currently queued. */
3533 [NSApp postEvent: nxev atStart: NO];
3537 #ifdef HAVE_NATIVE_FS
3541 Lisp_Object frame, tail;
3543 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3546 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3548 FOR_EACH_FRAME (tail, frame)
3550 struct frame *f = XFRAME (frame);
3553 EmacsView *view = FRAME_NS_VIEW (f);
3554 [view updateCollectionBehavior];
3560 /* GNUstep does not have cancelTracking. */
3561 #ifdef NS_IMPL_COCOA
3562 /* Check if menu open should be canceled or continued as normal. */
3564 ns_check_menu_open (NSMenu *menu)
3566 /* Click in menu bar? */
3567 NSArray *a = [[NSApp mainMenu] itemArray];
3571 if (menu == nil) // Menu tracking ended.
3573 if (menu_will_open_state == MENU_OPENING)
3574 menu_will_open_state = MENU_NONE;
3578 for (i = 0; ! found && i < [a count]; i++)
3579 found = menu == [[a objectAtIndex:i] submenu];
3582 if (menu_will_open_state == MENU_NONE && emacs_event)
3584 NSEvent *theEvent = [NSApp currentEvent];
3585 struct frame *emacsframe = SELECTED_FRAME ();
3587 [menu cancelTracking];
3588 menu_will_open_state = MENU_PENDING;
3589 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3590 EV_TRAILER (theEvent);
3592 CGEventRef ourEvent = CGEventCreate (NULL);
3593 menu_mouse_point = CGEventGetLocation (ourEvent);
3594 CFRelease (ourEvent);
3596 else if (menu_will_open_state == MENU_OPENING)
3598 menu_will_open_state = MENU_NONE;
3603 /* Redo saved menu click if state is MENU_PENDING. */
3605 ns_check_pending_open_menu ()
3607 if (menu_will_open_state == MENU_PENDING)
3609 CGEventSourceRef source
3610 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3612 CGEventRef event = CGEventCreateMouseEvent (source,
3613 kCGEventLeftMouseDown,
3615 kCGMouseButtonLeft);
3616 CGEventSetType (event, kCGEventLeftMouseDown);
3617 CGEventPost (kCGHIDEventTap, event);
3621 menu_will_open_state = MENU_OPENING;
3624 #endif /* NS_IMPL_COCOA */
3627 unwind_apploopnr (Lisp_Object not_used)
3630 n_emacs_events_pending = 0;
3631 ns_finish_events ();
3636 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3637 /* --------------------------------------------------------------------------
3638 External (hook): Post an event to ourself and keep reading events until
3639 we read it back again. In effect process all events which were waiting.
3640 From 21+ we have to manage the event buffer ourselves.
3641 -------------------------------------------------------------------------- */
3643 struct input_event ev;
3646 /* NSTRACE (ns_read_socket); */
3648 #ifdef HAVE_NATIVE_FS
3652 if ([NSApp modalWindow] != nil)
3655 if (hold_event_q.nr > 0)
3658 for (i = 0; i < hold_event_q.nr; ++i)
3659 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3660 hold_event_q.nr = 0;
3665 n_emacs_events_pending = 0;
3666 ns_init_events (&ev);
3667 q_event_ptr = hold_quit;
3669 /* we manage autorelease pools by allocate/reallocate each time around
3670 the loop; strict nesting is occasionally violated but seems not to
3671 matter.. earlier methods using full nesting caused major memory leaks */
3672 [outerpool release];
3673 outerpool = [[NSAutoreleasePool alloc] init];
3675 /* If have pending open-file requests, attend to the next one of those. */
3676 if (ns_pending_files && [ns_pending_files count] != 0
3677 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3679 [ns_pending_files removeObjectAtIndex: 0];
3681 /* Deal with pending service requests. */
3682 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3684 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3685 withArg: [ns_pending_service_args objectAtIndex: 0]])
3687 [ns_pending_service_names removeObjectAtIndex: 0];
3688 [ns_pending_service_args removeObjectAtIndex: 0];
3692 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3693 /* Run and wait for events. We must always send one NX_APPDEFINED event
3694 to ourself, otherwise [NXApp run] will never exit. */
3695 send_appdefined = YES;
3696 ns_send_appdefined (-1);
3698 if (++apploopnr != 1)
3702 record_unwind_protect (unwind_apploopnr, Qt);
3704 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3707 nevents = n_emacs_events_pending;
3708 n_emacs_events_pending = 0;
3709 ns_finish_events ();
3718 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3719 fd_set *exceptfds, struct timespec const *timeout,
3720 sigset_t const *sigmask)
3721 /* --------------------------------------------------------------------------
3722 Replacement for select, checking for events
3723 -------------------------------------------------------------------------- */
3727 struct input_event event;
3730 /* NSTRACE (ns_select); */
3732 #ifdef HAVE_NATIVE_FS
3736 if (hold_event_q.nr > 0)
3738 /* We already have events pending. */
3744 for (k = 0; k < nfds+1; k++)
3746 if (readfds && FD_ISSET(k, readfds)) ++nr;
3747 if (writefds && FD_ISSET(k, writefds)) ++nr;
3751 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3752 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3754 [outerpool release];
3755 outerpool = [[NSAutoreleasePool alloc] init];
3758 send_appdefined = YES;
3761 pthread_mutex_lock (&select_mutex);
3766 select_readfds = *readfds;
3767 select_valid += SELECT_HAVE_READ;
3771 select_writefds = *writefds;
3772 select_valid += SELECT_HAVE_WRITE;
3777 select_timeout = *timeout;
3778 select_valid += SELECT_HAVE_TMO;
3781 pthread_mutex_unlock (&select_mutex);
3783 /* Inform fd_handler that select should be called */
3785 emacs_write_sig (selfds[1], &c, 1);
3787 else if (nr == 0 && timeout)
3789 /* No file descriptor, just a timeout, no need to wake fd_handler */
3790 double time = timespectod (*timeout);
3791 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3794 @selector (timeout_handler:)
3799 else /* No timeout and no file descriptors, can this happen? */
3801 /* Send appdefined so we exit from the loop */
3802 ns_send_appdefined (-1);
3806 ns_init_events (&event);
3807 if (++apploopnr != 1)
3813 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3814 record_unwind_protect (unwind_apploopnr, Qt);
3816 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3819 ns_finish_events ();
3820 if (nr > 0 && readfds)
3823 emacs_write_sig (selfds[1], &c, 1);
3827 t = last_appdefined_event_data;
3829 if (t != NO_APPDEFINED_DATA)
3831 last_appdefined_event_data = NO_APPDEFINED_DATA;
3835 /* The NX_APPDEFINED event we received was a timeout. */
3840 /* The NX_APPDEFINED event we received was the result of
3841 at least one real input event arriving. */
3847 /* Received back from select () in fd_handler; copy the results */
3848 pthread_mutex_lock (&select_mutex);
3849 if (readfds) *readfds = select_readfds;
3850 if (writefds) *writefds = select_writefds;
3851 pthread_mutex_unlock (&select_mutex);
3866 /* ==========================================================================
3870 ========================================================================== */
3874 ns_set_vertical_scroll_bar (struct window *window,
3875 int portion, int whole, int position)
3876 /* --------------------------------------------------------------------------
3877 External (hook): Update or add scrollbar
3878 -------------------------------------------------------------------------- */
3882 struct frame *f = XFRAME (WINDOW_FRAME (window));
3883 EmacsView *view = FRAME_NS_VIEW (f);
3885 int window_y, window_height;
3886 int top, left, height, width;
3887 BOOL update_p = YES;
3889 /* optimization; display engine sends WAY too many of these.. */
3890 if (!NILP (window->vertical_scroll_bar))
3892 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3893 if ([bar checkSamePosition: position portion: portion whole: whole])
3895 if (view->scrollbarsNeedingUpdate == 0)
3897 if (!windows_or_buffers_changed)
3901 view->scrollbarsNeedingUpdate--;
3906 NSTRACE (ns_set_vertical_scroll_bar);
3908 /* Get dimensions. */
3909 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3911 height = window_height;
3912 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3913 left = WINDOW_SCROLL_BAR_AREA_X (window);
3915 r = NSMakeRect (left, top, width, height);
3916 /* the parent view is flipped, so we need to flip y value */
3918 r.origin.y = (v.size.height - r.size.height - r.origin.y);
3920 XSETWINDOW (win, window);
3923 /* we want at least 5 lines to display a scrollbar */
3924 if (WINDOW_TOTAL_LINES (window) < 5)
3926 if (!NILP (window->vertical_scroll_bar))
3928 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3929 [bar removeFromSuperview];
3930 wset_vertical_scroll_bar (window, Qnil);
3933 ns_clear_frame_area (f, left, top, width, height);
3938 if (NILP (window->vertical_scroll_bar))
3940 if (width > 0 && height > 0)
3941 ns_clear_frame_area (f, left, top, width, height);
3943 bar = [[EmacsScroller alloc] initFrame: r window: win];
3944 wset_vertical_scroll_bar (window, make_save_ptr (bar));
3950 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3951 oldRect = [bar frame];
3952 r.size.width = oldRect.size.width;
3953 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3955 if (oldRect.origin.x != r.origin.x)
3956 ns_clear_frame_area (f, left, top, width, height);
3962 [bar setPosition: position portion: portion whole: whole];
3968 ns_set_horizontal_scroll_bar (struct window *window,
3969 int portion, int whole, int position)
3970 /* --------------------------------------------------------------------------
3971 External (hook): Update or add scrollbar
3972 -------------------------------------------------------------------------- */
3976 struct frame *f = XFRAME (WINDOW_FRAME (window));
3977 EmacsView *view = FRAME_NS_VIEW (f);
3979 int top, height, left, width;
3980 int window_x, window_width;
3981 BOOL update_p = YES;
3983 /* optimization; display engine sends WAY too many of these.. */
3984 if (!NILP (window->horizontal_scroll_bar))
3986 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3987 if ([bar checkSamePosition: position portion: portion whole: whole])
3989 if (view->scrollbarsNeedingUpdate == 0)
3991 if (!windows_or_buffers_changed)
3995 view->scrollbarsNeedingUpdate--;
4000 NSTRACE (ns_set_horizontal_scroll_bar);
4002 /* Get dimensions. */
4003 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4005 width = window_width;
4006 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4007 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4009 r = NSMakeRect (left, top, width, height);
4010 /* the parent view is flipped, so we need to flip y value */
4012 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4013 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4015 XSETWINDOW (win, window);
4018 if (WINDOW_TOTAL_COLS (window) < 5)
4020 if (!NILP (window->horizontal_scroll_bar))
4022 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4023 [bar removeFromSuperview];
4024 wset_horizontal_scroll_bar (window, Qnil);
4026 ns_clear_frame_area (f, left, top, width, height);
4031 if (NILP (window->horizontal_scroll_bar))
4033 if (width > 0 && height > 0)
4034 ns_clear_frame_area (f, left, top, width, height);
4036 bar = [[EmacsScroller alloc] initFrame: r window: win];
4037 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4043 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4044 oldRect = [bar frame];
4045 r.size.width = oldRect.size.width;
4046 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4048 if (oldRect.origin.x != r.origin.x)
4049 ns_clear_frame_area (f, left, top, width, height);
4056 [bar setPosition: position portion: portion whole: whole];
4062 ns_condemn_scroll_bars (struct frame *f)
4063 /* --------------------------------------------------------------------------
4064 External (hook): arrange for all frame's scrollbars to be removed
4065 at next call to judge_scroll_bars, except for those redeemed.
4066 -------------------------------------------------------------------------- */
4070 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4072 NSTRACE (ns_condemn_scroll_bars);
4074 for (i =[subviews count]-1; i >= 0; i--)
4076 view = [subviews objectAtIndex: i];
4077 if ([view isKindOfClass: [EmacsScroller class]])
4084 ns_redeem_scroll_bar (struct window *window)
4085 /* --------------------------------------------------------------------------
4086 External (hook): arrange to spare this window's scrollbar
4087 at next call to judge_scroll_bars.
4088 -------------------------------------------------------------------------- */
4091 NSTRACE (ns_redeem_scroll_bar);
4092 if (!NILP (window->vertical_scroll_bar))
4094 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4098 if (!NILP (window->horizontal_scroll_bar))
4100 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4107 ns_judge_scroll_bars (struct frame *f)
4108 /* --------------------------------------------------------------------------
4109 External (hook): destroy all scrollbars on frame that weren't
4110 redeemed after call to condemn_scroll_bars.
4111 -------------------------------------------------------------------------- */
4115 EmacsView *eview = FRAME_NS_VIEW (f);
4116 NSArray *subviews = [[eview superview] subviews];
4119 NSTRACE (ns_judge_scroll_bars);
4120 for (i = [subviews count]-1; i >= 0; --i)
4122 view = [subviews objectAtIndex: i];
4123 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4129 [eview updateFrameSize: NO];
4132 /* ==========================================================================
4136 ========================================================================== */
4139 x_display_pixel_height (struct ns_display_info *dpyinfo)
4141 NSArray *screens = [NSScreen screens];
4142 NSEnumerator *enumerator = [screens objectEnumerator];
4147 while ((screen = [enumerator nextObject]) != nil)
4148 frame = NSUnionRect (frame, [screen frame]);
4150 return NSHeight (frame);
4154 x_display_pixel_width (struct ns_display_info *dpyinfo)
4156 NSArray *screens = [NSScreen screens];
4157 NSEnumerator *enumerator = [screens objectEnumerator];
4162 while ((screen = [enumerator nextObject]) != nil)
4163 frame = NSUnionRect (frame, [screen frame]);
4165 return NSWidth (frame);
4169 static Lisp_Object ns_string_to_lispmod (const char *s)
4170 /* --------------------------------------------------------------------------
4171 Convert modifier name to lisp symbol
4172 -------------------------------------------------------------------------- */
4174 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4176 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4178 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4180 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4182 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4184 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4192 ns_default (const char *parameter, Lisp_Object *result,
4193 Lisp_Object yesval, Lisp_Object noval,
4194 BOOL is_float, BOOL is_modstring)
4195 /* --------------------------------------------------------------------------
4196 Check a parameter value in user's preferences
4197 -------------------------------------------------------------------------- */
4199 const char *value = ns_get_defaults_value (parameter);
4205 if (c_strcasecmp (value, "YES") == 0)
4207 else if (c_strcasecmp (value, "NO") == 0)
4209 else if (is_float && (f = strtod (value, &pos), pos != value))
4210 *result = make_float (f);
4211 else if (is_modstring && value)
4212 *result = ns_string_to_lispmod (value);
4213 else fprintf (stderr,
4214 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4220 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4221 /* --------------------------------------------------------------------------
4222 Initialize global info and storage for display.
4223 -------------------------------------------------------------------------- */
4225 NSScreen *screen = [NSScreen mainScreen];
4226 NSWindowDepth depth = [screen depth];
4228 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4229 dpyinfo->resy = 72.27;
4230 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4231 NSColorSpaceFromDepth (depth)]
4232 && ![NSCalibratedWhiteColorSpace isEqualToString:
4233 NSColorSpaceFromDepth (depth)];
4234 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4235 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4236 dpyinfo->color_table->colors = NULL;
4237 dpyinfo->root_window = 42; /* a placeholder.. */
4238 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4239 dpyinfo->n_fonts = 0;
4240 dpyinfo->smallest_font_height = 1;
4241 dpyinfo->smallest_char_width = 1;
4243 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4247 /* This and next define (many of the) public functions in this file. */
4248 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4249 with using despite presence in the "system dependent" redisplay
4250 interface. In addition, many of the ns_ methods have code that is
4251 shared with all terms, indicating need for further refactoring. */
4252 extern frame_parm_handler ns_frame_parm_handlers[];
4253 static struct redisplay_interface ns_redisplay_interface =
4255 ns_frame_parm_handlers,
4259 x_clear_end_of_line,
4261 ns_after_update_window_line,
4262 ns_update_window_begin,
4263 ns_update_window_end,
4264 0, /* flush_display */
4265 x_clear_window_mouse_face,
4266 x_get_glyph_overhangs,
4267 x_fix_overlapping_area,
4268 ns_draw_fringe_bitmap,
4269 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4270 0, /* destroy_fringe_bitmap */
4271 ns_compute_glyph_string_overhangs,
4272 ns_draw_glyph_string,
4273 ns_define_frame_cursor,
4274 ns_clear_frame_area,
4275 ns_draw_window_cursor,
4276 ns_draw_vertical_window_border,
4277 ns_draw_window_divider,
4278 ns_shift_glyphs_for_insert,
4285 ns_delete_display (struct ns_display_info *dpyinfo)
4291 /* This function is called when the last frame on a display is deleted. */
4293 ns_delete_terminal (struct terminal *terminal)
4295 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4297 /* Protect against recursive calls. delete_frame in
4298 delete_terminal calls us back when it deletes our last frame. */
4299 if (!terminal->name)
4304 x_destroy_all_bitmaps (dpyinfo);
4305 ns_delete_display (dpyinfo);
4310 static struct terminal *
4311 ns_create_terminal (struct ns_display_info *dpyinfo)
4312 /* --------------------------------------------------------------------------
4313 Set up use of NS before we make the first connection.
4314 -------------------------------------------------------------------------- */
4316 struct terminal *terminal;
4318 NSTRACE (ns_create_terminal);
4320 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4322 terminal->display_info.ns = dpyinfo;
4323 dpyinfo->terminal = terminal;
4325 terminal->clear_frame_hook = ns_clear_frame;
4326 terminal->ring_bell_hook = ns_ring_bell;
4327 terminal->update_begin_hook = ns_update_begin;
4328 terminal->update_end_hook = ns_update_end;
4329 terminal->read_socket_hook = ns_read_socket;
4330 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4331 terminal->mouse_position_hook = ns_mouse_position;
4332 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4333 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4334 terminal->fullscreen_hook = ns_fullscreen_hook;
4335 terminal->menu_show_hook = ns_menu_show;
4336 terminal->popup_dialog_hook = ns_popup_dialog;
4337 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4338 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4339 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4340 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4341 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4342 terminal->delete_frame_hook = x_destroy_window;
4343 terminal->delete_terminal_hook = ns_delete_terminal;
4344 /* Other hooks are NULL by default. */
4350 struct ns_display_info *
4351 ns_term_init (Lisp_Object display_name)
4352 /* --------------------------------------------------------------------------
4353 Start the Application and get things rolling.
4354 -------------------------------------------------------------------------- */
4356 struct terminal *terminal;
4357 struct ns_display_info *dpyinfo;
4358 static int ns_initialized = 0;
4361 if (ns_initialized) return x_display_list;
4364 NSTRACE (ns_term_init);
4366 [outerpool release];
4367 outerpool = [[NSAutoreleasePool alloc] init];
4369 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4370 /*GSDebugAllocationActive (YES); */
4374 Fset_input_interrupt_mode (Qnil);
4376 if (selfds[0] == -1)
4378 if (emacs_pipe (selfds) != 0)
4380 fprintf (stderr, "Failed to create pipe: %s\n",
4381 emacs_strerror (errno));
4385 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4386 FD_ZERO (&select_readfds);
4387 FD_ZERO (&select_writefds);
4388 pthread_mutex_init (&select_mutex, NULL);
4391 ns_pending_files = [[NSMutableArray alloc] init];
4392 ns_pending_service_names = [[NSMutableArray alloc] init];
4393 ns_pending_service_args = [[NSMutableArray alloc] init];
4395 /* Start app and create the main menu, window, view.
4396 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4397 The view will then ask the NSApp to stop and return to Emacs. */
4398 [EmacsApp sharedApplication];
4401 [NSApp setDelegate: NSApp];
4403 /* Start the select thread. */
4404 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4408 /* debugging: log all notifications */
4409 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4410 selector: @selector (logNotification:)
4411 name: nil object: nil]; */
4413 dpyinfo = xzalloc (sizeof *dpyinfo);
4415 ns_initialize_display_info (dpyinfo);
4416 terminal = ns_create_terminal (dpyinfo);
4418 terminal->kboard = allocate_kboard (Qns);
4419 /* Don't let the initial kboard remain current longer than necessary.
4420 That would cause problems if a file loaded on startup tries to
4421 prompt in the mini-buffer. */
4422 if (current_kboard == initial_kboard)
4423 current_kboard = terminal->kboard;
4424 terminal->kboard->reference_count++;
4426 dpyinfo->next = x_display_list;
4427 x_display_list = dpyinfo;
4429 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4431 terminal->name = xlispstrdup (display_name);
4435 if (!inhibit_x_resources)
4437 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4440 /* this is a standard variable */
4441 ns_default ("AppleAntiAliasingThreshold", &tmp,
4442 make_float (10.0), make_float (6.0), YES, NO);
4443 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4447 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4451 Lisp_Object color_file, color_map, color;
4455 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4456 Fsymbol_value (intern ("data-directory")));
4458 color_map = Fx_load_color_file (color_file);
4459 if (NILP (color_map))
4460 fatal ("Could not read %s.\n", SDATA (color_file));
4462 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4463 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4465 color = XCAR (color_map);
4466 name = SSDATA (XCAR (color));
4467 c = XINT (XCDR (color));
4469 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4470 green: GREEN_FROM_ULONG (c) / 255.0
4471 blue: BLUE_FROM_ULONG (c) / 255.0
4473 forKey: [NSString stringWithUTF8String: name]];
4475 [cl writeToFile: nil];
4480 #ifdef NS_IMPL_GNUSTEP
4481 Vwindow_system_version = build_string (gnustep_base_version);
4483 /*PSnextrelease (128, c); */
4484 char c[DBL_BUFSIZE_BOUND];
4485 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4486 Vwindow_system_version = make_unibyte_string (c, len);
4490 delete_keyboard_wait_descriptor (0);
4492 ns_app_name = [[NSProcessInfo processInfo] processName];
4494 /* Set up OS X app menu */
4495 #ifdef NS_IMPL_COCOA
4499 /* set up the application menu */
4500 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4501 [svcsMenu setAutoenablesItems: NO];
4502 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4503 [appMenu setAutoenablesItems: NO];
4504 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4505 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4507 [appMenu insertItemWithTitle: @"About Emacs"
4508 action: @selector (orderFrontStandardAboutPanel:)
4511 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4512 [appMenu insertItemWithTitle: @"Preferences..."
4513 action: @selector (showPreferencesWindow:)
4516 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4517 item = [appMenu insertItemWithTitle: @"Services"
4518 action: @selector (menuDown:)
4521 [appMenu setSubmenu: svcsMenu forItem: item];
4522 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4523 [appMenu insertItemWithTitle: @"Hide Emacs"
4524 action: @selector (hide:)
4527 item = [appMenu insertItemWithTitle: @"Hide Others"
4528 action: @selector (hideOtherApplications:)
4531 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4532 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4533 [appMenu insertItemWithTitle: @"Quit Emacs"
4534 action: @selector (terminate:)
4538 item = [mainMenu insertItemWithTitle: ns_app_name
4539 action: @selector (menuDown:)
4542 [mainMenu setSubmenu: appMenu forItem: item];
4543 [dockMenu insertItemWithTitle: @"New Frame"
4544 action: @selector (newFrame:)
4548 [NSApp setMainMenu: mainMenu];
4549 [NSApp setAppleMenu: appMenu];
4550 [NSApp setServicesMenu: svcsMenu];
4551 /* Needed at least on Cocoa, to get dock menu to show windows */
4552 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4554 [[NSNotificationCenter defaultCenter]
4555 addObserver: mainMenu
4556 selector: @selector (trackingNotification:)
4557 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4558 [[NSNotificationCenter defaultCenter]
4559 addObserver: mainMenu
4560 selector: @selector (trackingNotification:)
4561 name: NSMenuDidEndTrackingNotification object: mainMenu];
4563 #endif /* MAC OS X menu setup */
4565 /* Register our external input/output types, used for determining
4566 applicable services and also drag/drop eligibility. */
4567 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4568 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4570 ns_drag_types = [[NSArray arrayWithObjects:
4572 NSTabularTextPboardType,
4573 NSFilenamesPboardType,
4574 NSURLPboardType, nil] retain];
4576 /* If fullscreen is in init/default-frame-alist, focus isn't set
4577 right for fullscreen windows, so set this. */
4578 [NSApp activateIgnoringOtherApps:YES];
4581 ns_do_open_file = YES;
4583 #ifdef NS_IMPL_GNUSTEP
4584 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4585 We must re-catch it so subprocess works. */
4586 catch_child_signal ();
4593 ns_term_shutdown (int sig)
4595 [[NSUserDefaults standardUserDefaults] synchronize];
4597 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4598 if (STRINGP (Vauto_save_list_file_name))
4599 unlink (SSDATA (Vauto_save_list_file_name));
4601 if (sig == 0 || sig == SIGTERM)
4603 [NSApp terminate: NSApp];
4605 else // force a stack trace to happen
4612 /* ==========================================================================
4614 EmacsApp implementation
4616 ========================================================================== */
4619 @implementation EmacsApp
4623 if ((self = [super init]))
4625 #ifdef NS_IMPL_COCOA
4626 self->isFirst = YES;
4628 #ifdef NS_IMPL_GNUSTEP
4629 self->applicationDidFinishLaunchingCalled = NO;
4636 #ifdef NS_IMPL_COCOA
4639 #ifndef NSAppKitVersionNumber10_9
4640 #define NSAppKitVersionNumber10_9 1265
4643 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4649 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4651 if (isFirst) [self finishLaunching];
4654 shouldKeepRunning = YES;
4658 pool = [[NSAutoreleasePool alloc] init];
4661 [self nextEventMatchingMask:NSAnyEventMask
4662 untilDate:[NSDate distantFuture]
4663 inMode:NSDefaultRunLoopMode
4666 [self sendEvent:event];
4667 [self updateWindows];
4668 } while (shouldKeepRunning);
4673 - (void)stop: (id)sender
4675 shouldKeepRunning = NO;
4676 // Stop possible dialog also. Noop if no dialog present.
4677 // The file dialog still leaks 7k - 10k on 10.9 though.
4678 [super stop:sender];
4680 #endif /* NS_IMPL_COCOA */
4682 - (void)logNotification: (NSNotification *)notification
4684 const char *name = [[notification name] UTF8String];
4685 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4686 && !strstr (name, "WindowNumber"))
4687 NSLog (@"notification: '%@'", [notification name]);
4691 - (void)sendEvent: (NSEvent *)theEvent
4692 /* --------------------------------------------------------------------------
4693 Called when NSApp is running for each event received. Used to stop
4694 the loop when we choose, since there's no way to just run one iteration.
4695 -------------------------------------------------------------------------- */
4697 int type = [theEvent type];
4698 NSWindow *window = [theEvent window];
4700 /* NSTRACE (sendEvent); */
4701 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4703 #ifdef NS_IMPL_GNUSTEP
4704 // Keyboard events aren't propagated to file dialogs for some reason.
4705 if ([NSApp modalWindow] != nil &&
4706 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4708 [[NSApp modalWindow] sendEvent: theEvent];
4713 if (represented_filename != nil && represented_frame)
4715 NSString *fstr = represented_filename;
4716 NSView *view = FRAME_NS_VIEW (represented_frame);
4717 #ifdef NS_IMPL_COCOA
4718 /* work around a bug observed on 10.3 and later where
4719 setTitleWithRepresentedFilename does not clear out previous state
4720 if given filename does not exist */
4721 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4722 [[view window] setRepresentedFilename: @""];
4724 [[view window] setRepresentedFilename: fstr];
4725 [represented_filename release];
4726 represented_filename = nil;
4727 represented_frame = NULL;
4730 if (type == NSApplicationDefined)
4732 switch ([theEvent data2])
4734 #ifdef NS_IMPL_COCOA
4735 case NSAPP_DATA2_RUNASSCRIPT:
4740 case NSAPP_DATA2_RUNFILEDIALOG:
4741 ns_run_file_dialog ();
4747 if (type == NSCursorUpdate && window == nil)
4749 fprintf (stderr, "Dropping external cursor update event.\n");
4753 if (type == NSApplicationDefined)
4755 /* Events posted by ns_send_appdefined interrupt the run loop here.
4756 But, if a modal window is up, an appdefined can still come through,
4757 (e.g., from a makeKeyWindow event) but stopping self also stops the
4758 modal loop. Just defer it until later. */
4759 if ([NSApp modalWindow] == nil)
4761 last_appdefined_event_data = [theEvent data1];
4766 send_appdefined = YES;
4771 #ifdef NS_IMPL_COCOA
4772 /* If no dialog and none of our frames have focus and it is a move, skip it.
4773 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4774 such as Wifi, sound, date or similar.
4775 This prevents "spooky" highlighting in the frame under the menu. */
4776 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4778 struct ns_display_info *di;
4779 BOOL has_focus = NO;
4780 for (di = x_display_list; ! has_focus && di; di = di->next)
4781 has_focus = di->x_focus_frame != 0;
4787 [super sendEvent: theEvent];
4791 - (void)showPreferencesWindow: (id)sender
4793 struct frame *emacsframe = SELECTED_FRAME ();
4794 NSEvent *theEvent = [NSApp currentEvent];
4798 emacs_event->kind = NS_NONKEY_EVENT;
4799 emacs_event->code = KEY_NS_SHOW_PREFS;
4800 emacs_event->modifiers = 0;
4801 EV_TRAILER (theEvent);
4805 - (void)newFrame: (id)sender
4807 struct frame *emacsframe = SELECTED_FRAME ();
4808 NSEvent *theEvent = [NSApp currentEvent];
4812 emacs_event->kind = NS_NONKEY_EVENT;
4813 emacs_event->code = KEY_NS_NEW_FRAME;
4814 emacs_event->modifiers = 0;
4815 EV_TRAILER (theEvent);
4819 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4820 - (BOOL) openFile: (NSString *)fileName
4822 struct frame *emacsframe = SELECTED_FRAME ();
4823 NSEvent *theEvent = [NSApp currentEvent];
4828 emacs_event->kind = NS_NONKEY_EVENT;
4829 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4830 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4831 ns_input_line = Qnil; /* can be start or cons start,end */
4832 emacs_event->modifiers =0;
4833 EV_TRAILER (theEvent);
4839 /* **************************************************************************
4841 EmacsApp delegate implementation
4843 ************************************************************************** */
4845 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4846 /* --------------------------------------------------------------------------
4847 When application is loaded, terminate event loop in ns_term_init
4848 -------------------------------------------------------------------------- */
4850 NSTRACE (applicationDidFinishLaunching);
4851 #ifdef NS_IMPL_GNUSTEP
4852 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4854 [NSApp setServicesProvider: NSApp];
4856 [self antialiasThresholdDidChange:nil];
4857 #ifdef NS_IMPL_COCOA
4858 [[NSNotificationCenter defaultCenter]
4860 selector:@selector(antialiasThresholdDidChange:)
4861 name:NSAntialiasThresholdChangedNotification
4865 ns_send_appdefined (-2);
4868 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4870 #ifdef NS_IMPL_COCOA
4871 macfont_update_antialias_threshold ();
4876 /* Termination sequences:
4879 MenuBar | File | Exit:
4880 Select Quit from App menubar:
4882 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4885 Select Quit from Dock menu:
4888 Cancel -> Nothing else
4892 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4897 - (void) terminate: (id)sender
4899 struct frame *emacsframe = SELECTED_FRAME ();
4904 emacs_event->kind = NS_NONKEY_EVENT;
4905 emacs_event->code = KEY_NS_POWER_OFF;
4906 emacs_event->arg = Qt; /* mark as non-key event */
4907 EV_TRAILER ((id)nil);
4911 runAlertPanel(NSString *title,
4912 NSString *msgFormat,
4913 NSString *defaultButton,
4914 NSString *alternateButton)
4916 #if !defined (NS_IMPL_COCOA) || \
4917 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
4918 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
4919 == NSAlertDefaultReturn;
4921 NSAlert *alert = [[NSAlert alloc] init];
4922 [alert setAlertStyle: NSCriticalAlertStyle];
4923 [alert setMessageText: msgFormat];
4924 [alert addButtonWithTitle: defaultButton];
4925 [alert addButtonWithTitle: alternateButton];
4926 NSInteger ret = [alert runModal];
4928 return ret == NSAlertFirstButtonReturn;
4933 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4937 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
4938 return NSTerminateNow;
4940 ret = runAlertPanel(ns_app_name,
4941 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
4942 @"Save Buffers and Exit", @"Cancel");
4945 return NSTerminateNow;
4947 return NSTerminateCancel;
4948 return NSTerminateNow; /* just in case */
4952 not_in_argv (NSString *arg)
4955 const char *a = [arg UTF8String];
4956 for (k = 1; k < initial_argc; ++k)
4957 if (strcmp (a, initial_argv[k]) == 0) return 0;
4961 /* Notification from the Workspace to open a file */
4962 - (BOOL)application: sender openFile: (NSString *)file
4964 if (ns_do_open_file || not_in_argv (file))
4965 [ns_pending_files addObject: file];
4970 /* Open a file as a temporary file */
4971 - (BOOL)application: sender openTempFile: (NSString *)file
4973 if (ns_do_open_file || not_in_argv (file))
4974 [ns_pending_files addObject: file];
4979 /* Notification from the Workspace to open a file noninteractively (?) */
4980 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4982 if (ns_do_open_file || not_in_argv (file))
4983 [ns_pending_files addObject: file];
4987 /* Notification from the Workspace to open multiple files */
4988 - (void)application: sender openFiles: (NSArray *)fileList
4990 NSEnumerator *files = [fileList objectEnumerator];
4992 /* Don't open files from the command line unconditionally,
4993 Cocoa parses the command line wrong, --option value tries to open value
4994 if --option is the last option. */
4995 while ((file = [files nextObject]) != nil)
4996 if (ns_do_open_file || not_in_argv (file))
4997 [ns_pending_files addObject: file];
4999 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5004 /* Handle dock menu requests. */
5005 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5011 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5012 - (void)applicationWillBecomeActive: (NSNotification *)notification
5014 //ns_app_active=YES;
5016 - (void)applicationDidBecomeActive: (NSNotification *)notification
5018 NSTRACE (applicationDidBecomeActive);
5020 #ifdef NS_IMPL_GNUSTEP
5021 if (! applicationDidFinishLaunchingCalled)
5022 [self applicationDidFinishLaunching:notification];
5024 //ns_app_active=YES;
5026 ns_update_auto_hide_menu_bar ();
5027 // No constraining takes place when the application is not active.
5028 ns_constrain_all_frames ();
5030 - (void)applicationDidResignActive: (NSNotification *)notification
5033 ns_send_appdefined (-1);
5038 /* ==========================================================================
5040 EmacsApp aux handlers for managing event loop
5042 ========================================================================== */
5045 - (void)timeout_handler: (NSTimer *)timedEntry
5046 /* --------------------------------------------------------------------------
5047 The timeout specified to ns_select has passed.
5048 -------------------------------------------------------------------------- */
5050 /*NSTRACE (timeout_handler); */
5051 ns_send_appdefined (-2);
5054 #ifdef NS_IMPL_GNUSTEP
5055 - (void)sendFromMainThread:(id)unused
5057 ns_send_appdefined (nextappdefined);
5061 - (void)fd_handler:(id)unused
5062 /* --------------------------------------------------------------------------
5063 Check data waiting on file descriptors and terminate if so
5064 -------------------------------------------------------------------------- */
5067 int waiting = 1, nfds;
5070 fd_set readfds, writefds, *wfds;
5071 struct timespec timeout, *tmo;
5072 NSAutoreleasePool *pool = nil;
5074 /* NSTRACE (fd_handler); */
5079 pool = [[NSAutoreleasePool alloc] init];
5085 FD_SET (selfds[0], &fds);
5086 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5087 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5092 pthread_mutex_lock (&select_mutex);
5095 if (select_valid & SELECT_HAVE_READ)
5096 readfds = select_readfds;
5100 if (select_valid & SELECT_HAVE_WRITE)
5102 writefds = select_writefds;
5107 if (select_valid & SELECT_HAVE_TMO)
5109 timeout = select_timeout;
5115 pthread_mutex_unlock (&select_mutex);
5117 FD_SET (selfds[0], &readfds);
5118 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5120 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5123 ns_send_appdefined (-2);
5124 else if (result > 0)
5126 if (FD_ISSET (selfds[0], &readfds))
5128 if (read (selfds[0], &c, 1) == 1 && c == 's')
5133 pthread_mutex_lock (&select_mutex);
5134 if (select_valid & SELECT_HAVE_READ)
5135 select_readfds = readfds;
5136 if (select_valid & SELECT_HAVE_WRITE)
5137 select_writefds = writefds;
5138 if (select_valid & SELECT_HAVE_TMO)
5139 select_timeout = timeout;
5140 pthread_mutex_unlock (&select_mutex);
5142 ns_send_appdefined (result);
5152 /* ==========================================================================
5156 ========================================================================== */
5158 /* called from system: queue for next pass through event loop */
5159 - (void)requestService: (NSPasteboard *)pboard
5160 userData: (NSString *)userData
5161 error: (NSString **)error
5163 [ns_pending_service_names addObject: userData];
5164 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5165 SSDATA (ns_string_from_pasteboard (pboard))]];
5169 /* called from ns_read_socket to clear queue */
5170 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5172 struct frame *emacsframe = SELECTED_FRAME ();
5173 NSEvent *theEvent = [NSApp currentEvent];
5178 emacs_event->kind = NS_NONKEY_EVENT;
5179 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5180 ns_input_spi_name = build_string ([name UTF8String]);
5181 ns_input_spi_arg = build_string ([arg UTF8String]);
5182 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5183 EV_TRAILER (theEvent);
5193 /* ==========================================================================
5195 EmacsView implementation
5197 ========================================================================== */
5200 @implementation EmacsView
5202 /* needed to inform when window closed from LISP */
5203 - (void) setWindowClosing: (BOOL)closing
5205 windowClosing = closing;
5211 NSTRACE (EmacsView_dealloc);
5213 if (fs_state == FULLSCREEN_BOTH)
5214 [nonfs_window release];
5219 /* called on font panel selection */
5220 - (void)changeFont: (id)sender
5222 NSEvent *e = [[self window] currentEvent];
5223 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5224 struct font *font = face->font;
5229 NSTRACE (changeFont);
5234 #ifdef NS_IMPL_GNUSTEP
5235 nsfont = ((struct nsfont_info *)font)->nsfont;
5237 #ifdef NS_IMPL_COCOA
5238 nsfont = (NSFont *) macfont_get_nsctfont (font);
5241 if ((newFont = [sender convertFont: nsfont]))
5243 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5245 emacs_event->kind = NS_NONKEY_EVENT;
5246 emacs_event->modifiers = 0;
5247 emacs_event->code = KEY_NS_CHANGE_FONT;
5249 size = [newFont pointSize];
5250 ns_input_fontsize = make_number (lrint (size));
5251 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5257 - (BOOL)acceptsFirstResponder
5259 NSTRACE (acceptsFirstResponder);
5264 - (void)resetCursorRects
5266 NSRect visible = [self visibleRect];
5267 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5268 NSTRACE (resetCursorRects);
5270 if (currentCursor == nil)
5271 currentCursor = [NSCursor arrowCursor];
5273 if (!NSIsEmptyRect (visible))
5274 [self addCursorRect: visible cursor: currentCursor];
5275 [currentCursor setOnMouseEntered: YES];
5280 /*****************************************************************************/
5281 /* Keyboard handling. */
5284 - (void)keyDown: (NSEvent *)theEvent
5286 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5288 unsigned fnKeysym = 0;
5289 static NSMutableArray *nsEvArray;
5291 unsigned int flags = [theEvent modifierFlags];
5295 /* Rhapsody and OS X give up and down events for the arrow keys */
5296 if (ns_fake_keydown == YES)
5297 ns_fake_keydown = NO;
5298 else if ([theEvent type] != NSKeyDown)
5304 if (![[self window] isKeyWindow]
5305 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5306 /* we must avoid an infinite loop here. */
5307 && (EmacsView *)[[theEvent window] delegate] != self)
5309 /* XXX: There is an occasional condition in which, when Emacs display
5310 updates a different frame from the current one, and temporarily
5311 selects it, then processes some interrupt-driven input
5312 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5313 for some reason that window has its first responder set to the NSView
5314 most recently updated (I guess), which is not the correct one. */
5315 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5319 if (nsEvArray == nil)
5320 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5322 [NSCursor setHiddenUntilMouseMoves: YES];
5324 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5326 clear_mouse_face (hlinfo);
5327 hlinfo->mouse_face_hidden = 1;
5330 if (!processingCompose)
5332 /* When using screen sharing, no left or right information is sent,
5333 so use Left key in those cases. */
5334 int is_left_key, is_right_key;
5336 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5337 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5339 /* (Carbon way: [theEvent keyCode]) */
5341 /* is it a "function key"? */
5342 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5343 flag set (this is probably a bug in the OS).
5345 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5347 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5351 fnKeysym = ns_convert_key (code);
5356 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5357 because Emacs treats Delete and KP-Delete same (in simple.el). */
5358 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5359 #ifdef NS_IMPL_GNUSTEP
5360 /* GNUstep uses incompatible keycodes, even for those that are
5361 supposed to be hardware independent. Just check for delete.
5362 Keypad delete does not have keysym 0xFFFF.
5363 See http://savannah.gnu.org/bugs/?25395
5365 || (fnKeysym == 0xFFFF && code == 127)
5368 code = 0xFF08; /* backspace */
5373 /* are there modifiers? */
5374 emacs_event->modifiers = 0;
5376 if (flags & NSHelpKeyMask)
5377 emacs_event->modifiers |= hyper_modifier;
5379 if (flags & NSShiftKeyMask)
5380 emacs_event->modifiers |= shift_modifier;
5382 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5383 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5384 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5387 emacs_event->modifiers |= parse_solitary_modifier
5388 (EQ (ns_right_command_modifier, Qleft)
5389 ? ns_command_modifier
5390 : ns_right_command_modifier);
5394 emacs_event->modifiers |= parse_solitary_modifier
5395 (ns_command_modifier);
5397 /* if super (default), take input manager's word so things like
5398 dvorak / qwerty layout work */
5399 if (EQ (ns_command_modifier, Qsuper)
5401 && [[theEvent characters] length] != 0)
5403 /* XXX: the code we get will be unshifted, so if we have
5404 a shift modifier, must convert ourselves */
5405 if (!(flags & NSShiftKeyMask))
5406 code = [[theEvent characters] characterAtIndex: 0];
5408 /* this is ugly and also requires linking w/Carbon framework
5409 (for LMGetKbdType) so for now leave this rare (?) case
5410 undealt with.. in future look into CGEvent methods */
5413 long smv = GetScriptManagerVariable (smKeyScript);
5414 Handle uchrHandle = GetResource
5415 ('uchr', GetScriptVariable (smv, smScriptKeys));
5417 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5418 [[theEvent characters] characterAtIndex: 0],
5419 kUCKeyActionDisplay,
5420 (flags & ~NSCommandKeyMask) >> 8,
5421 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5422 &dummy, 1, &dummy, &code);
5429 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5430 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5431 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5434 emacs_event->modifiers |= parse_solitary_modifier
5435 (EQ (ns_right_control_modifier, Qleft)
5436 ? ns_control_modifier
5437 : ns_right_control_modifier);
5440 emacs_event->modifiers |= parse_solitary_modifier
5441 (ns_control_modifier);
5443 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5444 emacs_event->modifiers |=
5445 parse_solitary_modifier (ns_function_modifier);
5447 left_is_none = NILP (ns_alternate_modifier)
5448 || EQ (ns_alternate_modifier, Qnone);
5450 is_right_key = (flags & NSRightAlternateKeyMask)
5451 == NSRightAlternateKeyMask;
5452 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5454 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5458 if ((NILP (ns_right_alternate_modifier)
5459 || EQ (ns_right_alternate_modifier, Qnone)
5460 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5462 { /* accept pre-interp alt comb */
5463 if ([[theEvent characters] length] > 0)
5464 code = [[theEvent characters] characterAtIndex: 0];
5465 /*HACK: clear lone shift modifier to stop next if from firing */
5466 if (emacs_event->modifiers == shift_modifier)
5467 emacs_event->modifiers = 0;
5470 emacs_event->modifiers |= parse_solitary_modifier
5471 (EQ (ns_right_alternate_modifier, Qleft)
5472 ? ns_alternate_modifier
5473 : ns_right_alternate_modifier);
5476 if (is_left_key) /* default = meta */
5478 if (left_is_none && !fnKeysym)
5479 { /* accept pre-interp alt comb */
5480 if ([[theEvent characters] length] > 0)
5481 code = [[theEvent characters] characterAtIndex: 0];
5482 /*HACK: clear lone shift modifier to stop next if from firing */
5483 if (emacs_event->modifiers == shift_modifier)
5484 emacs_event->modifiers = 0;
5487 emacs_event->modifiers |=
5488 parse_solitary_modifier (ns_alternate_modifier);
5492 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5493 code, fnKeysym, flags, emacs_event->modifiers);
5495 /* if it was a function key or had modifiers, pass it directly to emacs */
5496 if (fnKeysym || (emacs_event->modifiers
5497 && (emacs_event->modifiers != shift_modifier)
5498 && [[theEvent charactersIgnoringModifiers] length] > 0))
5499 /*[[theEvent characters] length] */
5501 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5503 code |= (1<<28)|(3<<16);
5504 else if (code == 0x7f)
5505 code |= (1<<28)|(3<<16);
5507 emacs_event->kind = code > 0xFF
5508 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5510 emacs_event->code = code;
5511 EV_TRAILER (theEvent);
5512 processingCompose = NO;
5518 if (NS_KEYLOG && !processingCompose)
5519 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5521 processingCompose = YES;
5522 [nsEvArray addObject: theEvent];
5523 [self interpretKeyEvents: nsEvArray];
5524 [nsEvArray removeObject: theEvent];
5528 #ifdef NS_IMPL_COCOA
5529 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5530 decided not to send key-down for.
5531 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5532 This only applies on Tiger and earlier.
5533 If it matches one of these, send it on to keyDown. */
5534 -(void)keyUp: (NSEvent *)theEvent
5536 int flags = [theEvent modifierFlags];
5537 int code = [theEvent keyCode];
5538 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5539 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5542 fprintf (stderr, "keyUp: passed test");
5543 ns_fake_keydown = YES;
5544 [self keyDown: theEvent];
5550 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5553 /* <NSTextInput>: called when done composing;
5554 NOTE: also called when we delete over working text, followed immed.
5555 by doCommandBySelector: deleteBackward: */
5556 - (void)insertText: (id)aString
5559 int len = [(NSString *)aString length];
5563 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5564 processingCompose = NO;
5569 /* first, clear any working text */
5570 if (workingText != nil)
5571 [self deleteWorkingText];
5573 /* now insert the string as keystrokes */
5574 for (i =0; i<len; i++)
5576 code = [aString characterAtIndex: i];
5577 /* TODO: still need this? */
5579 code = '~'; /* 0x7E */
5580 if (code != 32) /* Space */
5581 emacs_event->modifiers = 0;
5583 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5584 emacs_event->code = code;
5585 EV_TRAILER ((id)nil);
5590 /* <NSTextInput>: inserts display of composing characters */
5591 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5593 NSString *str = [aString respondsToSelector: @selector (string)] ?
5594 [aString string] : aString;
5596 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5597 str, (unsigned long)[str length],
5598 (unsigned long)selRange.length,
5599 (unsigned long)selRange.location);
5601 if (workingText != nil)
5602 [self deleteWorkingText];
5603 if ([str length] == 0)
5609 processingCompose = YES;
5610 workingText = [str copy];
5611 ns_working_text = build_string ([workingText UTF8String]);
5613 emacs_event->kind = NS_TEXT_EVENT;
5614 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5615 EV_TRAILER ((id)nil);
5619 /* delete display of composing characters [not in <NSTextInput>] */
5620 - (void)deleteWorkingText
5622 if (workingText == nil)
5625 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5626 [workingText release];
5628 processingCompose = NO;
5633 emacs_event->kind = NS_TEXT_EVENT;
5634 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5635 EV_TRAILER ((id)nil);
5639 - (BOOL)hasMarkedText
5641 return workingText != nil;
5645 - (NSRange)markedRange
5647 NSRange rng = workingText != nil
5648 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5650 NSLog (@"markedRange request");
5658 NSLog (@"unmark (accept) text");
5659 [self deleteWorkingText];
5660 processingCompose = NO;
5664 /* used to position char selection windows, etc. */
5665 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5669 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5671 NSLog (@"firstRectForCharRange request");
5673 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5674 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5675 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5676 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5677 +FRAME_LINE_HEIGHT (emacsframe));
5679 pt = [self convertPoint: pt toView: nil];
5680 pt = [[self window] convertBaseToScreen: pt];
5686 - (NSInteger)conversationIdentifier
5688 return (NSInteger)self;
5692 - (void)doCommandBySelector: (SEL)aSelector
5695 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5697 processingCompose = NO;
5698 if (aSelector == @selector (deleteBackward:))
5700 /* happens when user backspaces over an ongoing composition:
5701 throw a 'delete' into the event queue */
5704 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5705 emacs_event->code = 0xFF08;
5706 EV_TRAILER ((id)nil);
5710 - (NSArray *)validAttributesForMarkedText
5712 static NSArray *arr = nil;
5713 if (arr == nil) arr = [NSArray new];
5714 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5718 - (NSRange)selectedRange
5721 NSLog (@"selectedRange request");
5722 return NSMakeRange (NSNotFound, 0);
5725 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5726 GNUSTEP_GUI_MINOR_VERSION > 22
5727 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5729 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5733 NSLog (@"characterIndexForPoint request");
5737 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5739 static NSAttributedString *str = nil;
5740 if (str == nil) str = [NSAttributedString new];
5742 NSLog (@"attributedSubstringFromRange request");
5746 /* End <NSTextInput> impl. */
5747 /*****************************************************************************/
5750 /* This is what happens when the user presses a mouse button. */
5751 - (void)mouseDown: (NSEvent *)theEvent
5753 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5754 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5756 NSTRACE (mouseDown);
5758 [self deleteWorkingText];
5763 dpyinfo->last_mouse_frame = emacsframe;
5764 /* appears to be needed to prevent spurious movement events generated on
5766 emacsframe->mouse_moved = 0;
5768 if ([theEvent type] == NSScrollWheel)
5770 CGFloat delta = [theEvent deltaY];
5771 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5774 delta = [theEvent deltaX];
5777 NSTRACE (deltaIsZero);
5780 emacs_event->kind = HORIZ_WHEEL_EVENT;
5783 emacs_event->kind = WHEEL_EVENT;
5785 emacs_event->code = 0;
5786 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5787 ((delta > 0) ? up_modifier : down_modifier);
5791 emacs_event->kind = MOUSE_CLICK_EVENT;
5792 emacs_event->code = EV_BUTTON (theEvent);
5793 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5794 | EV_UDMODIFIERS (theEvent);
5796 XSETINT (emacs_event->x, lrint (p.x));
5797 XSETINT (emacs_event->y, lrint (p.y));
5798 EV_TRAILER (theEvent);
5802 - (void)rightMouseDown: (NSEvent *)theEvent
5804 NSTRACE (rightMouseDown);
5805 [self mouseDown: theEvent];
5809 - (void)otherMouseDown: (NSEvent *)theEvent
5811 NSTRACE (otherMouseDown);
5812 [self mouseDown: theEvent];
5816 - (void)mouseUp: (NSEvent *)theEvent
5819 [self mouseDown: theEvent];
5823 - (void)rightMouseUp: (NSEvent *)theEvent
5825 NSTRACE (rightMouseUp);
5826 [self mouseDown: theEvent];
5830 - (void)otherMouseUp: (NSEvent *)theEvent
5832 NSTRACE (otherMouseUp);
5833 [self mouseDown: theEvent];
5837 - (void) scrollWheel: (NSEvent *)theEvent
5839 NSTRACE (scrollWheel);
5840 [self mouseDown: theEvent];
5844 /* Tell emacs the mouse has moved. */
5845 - (void)mouseMoved: (NSEvent *)e
5847 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5848 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5852 // NSTRACE (mouseMoved);
5854 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5855 pt = [self convertPoint: [e locationInWindow] fromView: nil];
5856 dpyinfo->last_mouse_motion_x = pt.x;
5857 dpyinfo->last_mouse_motion_y = pt.y;
5859 /* update any mouse face */
5860 if (hlinfo->mouse_face_hidden)
5862 hlinfo->mouse_face_hidden = 0;
5863 clear_mouse_face (hlinfo);
5866 /* tooltip handling */
5867 previous_help_echo_string = help_echo_string;
5868 help_echo_string = Qnil;
5870 if (!NILP (Vmouse_autoselect_window))
5872 NSTRACE (mouse_autoselect_window);
5873 static Lisp_Object last_mouse_window;
5875 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5877 if (WINDOWP (window)
5878 && !EQ (window, last_mouse_window)
5879 && !EQ (window, selected_window)
5880 && (focus_follows_mouse
5881 || (EQ (XWINDOW (window)->frame,
5882 XWINDOW (selected_window)->frame))))
5884 NSTRACE (in_window);
5885 emacs_event->kind = SELECT_WINDOW_EVENT;
5886 emacs_event->frame_or_window = window;
5889 /* Remember the last window where we saw the mouse. */
5890 last_mouse_window = window;
5893 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5894 help_echo_string = previous_help_echo_string;
5896 XSETFRAME (frame, emacsframe);
5897 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5899 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5900 (note_mouse_highlight), which is called through the
5901 note_mouse_movement () call above */
5902 any_help_event_p = YES;
5903 gen_help_event (help_echo_string, frame, help_echo_window,
5904 help_echo_object, help_echo_pos);
5907 if (emacsframe->mouse_moved && send_appdefined)
5908 ns_send_appdefined (-1);
5912 - (void)mouseDragged: (NSEvent *)e
5914 NSTRACE (mouseDragged);
5915 [self mouseMoved: e];
5919 - (void)rightMouseDragged: (NSEvent *)e
5921 NSTRACE (rightMouseDragged);
5922 [self mouseMoved: e];
5926 - (void)otherMouseDragged: (NSEvent *)e
5928 NSTRACE (otherMouseDragged);
5929 [self mouseMoved: e];
5933 - (BOOL)windowShouldClose: (id)sender
5935 NSEvent *e =[[self window] currentEvent];
5937 NSTRACE (windowShouldClose);
5938 windowClosing = YES;
5941 emacs_event->kind = DELETE_WINDOW_EVENT;
5942 emacs_event->modifiers = 0;
5943 emacs_event->code = 0;
5945 /* Don't close this window, let this be done from lisp code. */
5949 - (void) updateFrameSize: (BOOL) delay;
5951 NSWindow *window = [self window];
5952 NSRect wr = [window frame];
5954 int oldc = cols, oldr = rows;
5955 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5956 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5959 NSTRACE (updateFrameSize);
5960 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5962 if (! [self isFullscreen])
5964 #ifdef NS_IMPL_GNUSTEP
5965 // GNUstep does not always update the tool bar height. Force it.
5966 if (toolbar && [toolbar isVisible])
5967 update_frame_tool_bar (emacsframe);
5970 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5971 + FRAME_TOOLBAR_HEIGHT (emacsframe);
5974 if (wait_for_tool_bar)
5976 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5978 wait_for_tool_bar = NO;
5981 neww = (int)wr.size.width - emacsframe->border_width;
5982 newh = (int)wr.size.height - extra;
5984 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5985 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5987 if (cols < MINWIDTH)
5990 if (rows < MINHEIGHT)
5993 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5995 NSView *view = FRAME_NS_VIEW (emacsframe);
5996 NSWindow *win = [view window];
5997 NSSize sz = [win resizeIncrements];
5999 change_frame_size (emacsframe,
6000 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6001 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6003 SET_FRAME_GARBAGED (emacsframe);
6004 cancel_mouse_face (emacsframe);
6006 // Did resize increments change because of a font change?
6007 if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
6008 sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
6009 (frame_resize_pixelwise && sz.width != 1))
6011 sz.width = frame_resize_pixelwise
6012 ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
6013 sz.height = frame_resize_pixelwise
6014 ? 1 : FRAME_LINE_HEIGHT (emacsframe);
6015 [win setResizeIncrements: sz];
6017 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6020 [view setFrame: NSMakeRect (0, 0, neww, newh)];
6021 [self windowDidMove:nil]; // Update top/left.
6025 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6026 /* normalize frame to gridded text size */
6030 NSTRACE (windowWillResize);
6031 NSTRACE_SIZE ("Original size", frameSize);
6032 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
6034 if (fs_state == FULLSCREEN_MAXIMIZED
6035 && (maximized_width != (int)frameSize.width
6036 || maximized_height != (int)frameSize.height))
6037 [self setFSValue: FULLSCREEN_NONE];
6038 else if (fs_state == FULLSCREEN_WIDTH
6039 && maximized_width != (int)frameSize.width)
6040 [self setFSValue: FULLSCREEN_NONE];
6041 else if (fs_state == FULLSCREEN_HEIGHT
6042 && maximized_height != (int)frameSize.height)
6043 [self setFSValue: FULLSCREEN_NONE];
6044 if (fs_state == FULLSCREEN_NONE)
6045 maximized_width = maximized_height = -1;
6047 if (! [self isFullscreen])
6049 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6050 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6053 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6054 if (cols < MINWIDTH)
6057 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6058 frameSize.height - extra);
6059 if (rows < MINHEIGHT)
6061 #ifdef NS_IMPL_COCOA
6063 /* this sets window title to have size in it; the wm does this under GS */
6064 NSRect r = [[self window] frame];
6065 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6073 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6076 NSWindow *window = [self window];
6079 char *t = strdup ([[[self window] title] UTF8String]);
6080 char *pos = strstr (t, " — ");
6085 size_title = xmalloc (strlen (old_title) + 40);
6086 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6087 [window setTitle: [NSString stringWithUTF8String: size_title]];
6092 #endif /* NS_IMPL_COCOA */
6093 /*fprintf (stderr," ...size became %.0f x %.0f (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
6099 - (void)windowDidResize: (NSNotification *)notification
6101 if (! [self fsIsNative])
6103 NSWindow *theWindow = [notification object];
6104 /* We can get notification on the non-FS window when in
6106 if ([self window] != theWindow) return;
6109 #ifdef NS_IMPL_GNUSTEP
6110 NSWindow *theWindow = [notification object];
6112 /* In GNUstep, at least currently, it's possible to get a didResize
6113 without getting a willResize.. therefore we need to act as if we got
6114 the willResize now */
6115 NSSize sz = [theWindow frame].size;
6116 sz = [self windowWillResize: theWindow toSize: sz];
6117 #endif /* NS_IMPL_GNUSTEP */
6119 NSTRACE (windowDidResize);
6120 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
6122 if (cols > 0 && rows > 0)
6124 [self updateFrameSize: YES];
6127 ns_send_appdefined (-1);
6130 #ifdef NS_IMPL_COCOA
6131 - (void)viewDidEndLiveResize
6133 [super viewDidEndLiveResize];
6136 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6140 maximizing_resize = NO;
6142 #endif /* NS_IMPL_COCOA */
6145 - (void)windowDidBecomeKey: (NSNotification *)notification
6146 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6148 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6149 struct frame *old_focus = dpyinfo->x_focus_frame;
6151 NSTRACE (windowDidBecomeKey);
6153 if (emacsframe != old_focus)
6154 dpyinfo->x_focus_frame = emacsframe;
6156 ns_frame_rehighlight (emacsframe);
6160 emacs_event->kind = FOCUS_IN_EVENT;
6161 EV_TRAILER ((id)nil);
6166 - (void)windowDidResignKey: (NSNotification *)notification
6167 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6169 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6170 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6171 NSTRACE (windowDidResignKey);
6174 dpyinfo->x_focus_frame = 0;
6176 emacsframe->mouse_moved = 0;
6177 ns_frame_rehighlight (emacsframe);
6179 /* FIXME: for some reason needed on second and subsequent clicks away
6180 from sole-frame Emacs to get hollow box to show */
6181 if (!windowClosing && [[self window] isVisible] == YES)
6183 x_update_cursor (emacsframe, 1);
6184 x_set_frame_alpha (emacsframe);
6187 if (any_help_event_p)
6190 XSETFRAME (frame, emacsframe);
6191 help_echo_string = Qnil;
6192 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6195 if (emacs_event && is_focus_frame)
6197 [self deleteWorkingText];
6198 emacs_event->kind = FOCUS_OUT_EVENT;
6199 EV_TRAILER ((id)nil);
6204 - (void)windowWillMiniaturize: sender
6206 NSTRACE (windowWillMiniaturize);
6222 - initFrameFromEmacs: (struct frame *)f
6231 NSTRACE (initFrameFromEmacs);
6234 processingCompose = NO;
6235 scrollbarsNeedingUpdate = 0;
6236 fs_state = FULLSCREEN_NONE;
6237 fs_before_fs = next_maximized = -1;
6238 #ifdef HAVE_NATIVE_FS
6239 fs_is_native = ns_use_native_fullscreen;
6243 maximized_width = maximized_height = -1;
6246 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6248 ns_userRect = NSMakeRect (0, 0, 0, 0);
6249 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6250 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6251 [self initWithFrame: r];
6252 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6254 FRAME_NS_VIEW (f) = self;
6256 #ifdef NS_IMPL_COCOA
6258 maximizing_resize = NO;
6261 win = [[EmacsWindow alloc]
6262 initWithContentRect: r
6263 styleMask: (NSResizableWindowMask |
6264 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6265 NSTitledWindowMask |
6267 NSMiniaturizableWindowMask |
6268 NSClosableWindowMask)
6269 backing: NSBackingStoreBuffered
6272 #ifdef HAVE_NATIVE_FS
6273 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6277 bwidth = f->border_width = wr.size.width - r.size.width;
6278 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6280 [win setAcceptsMouseMovedEvents: YES];
6281 [win setDelegate: self];
6282 #if !defined (NS_IMPL_COCOA) || \
6283 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6284 [win useOptimizedDrawing: YES];
6286 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6287 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6288 [win setResizeIncrements: sz];
6290 [[win contentView] addSubview: self];
6293 [self registerForDraggedTypes: ns_drag_types];
6296 name = [NSString stringWithUTF8String:
6297 NILP (tem) ? "Emacs" : SSDATA (tem)];
6298 [win setTitle: name];
6300 /* toolbar support */
6301 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6302 [NSString stringWithFormat: @"Emacs Frame %d",
6304 [win setToolbar: toolbar];
6305 [toolbar setVisible: NO];
6307 /* Don't set frame garbaged until tool bar is up to date?
6308 This avoids an extra clear and redraw (flicker) at frame creation. */
6309 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6310 else wait_for_tool_bar = NO;
6313 #ifdef NS_IMPL_COCOA
6315 NSButton *toggleButton;
6316 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6317 [toggleButton setTarget: self];
6318 [toggleButton setAction: @selector (toggleToolbar: )];
6321 FRAME_TOOLBAR_HEIGHT (f) = 0;
6325 [win setMiniwindowTitle:
6326 [NSString stringWithUTF8String: SSDATA (tem)]];
6329 NSScreen *screen = [win screen];
6332 [win setFrameTopLeftPoint: NSMakePoint
6333 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6334 IN_BOUND (-SCREENMAX,
6335 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6338 [win makeFirstResponder: self];
6340 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6341 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6342 [win setBackgroundColor: col];
6343 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6344 [win setOpaque: NO];
6346 #if !defined (NS_IMPL_COCOA) || \
6347 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6348 [self allocateGState];
6350 [NSApp registerServicesMenuSendTypes: ns_send_types
6358 - (void)windowDidMove: sender
6360 NSWindow *win = [self window];
6361 NSRect r = [win frame];
6362 NSArray *screens = [NSScreen screens];
6363 NSScreen *screen = [screens objectAtIndex: 0];
6365 NSTRACE (windowDidMove);
6367 if (!emacsframe->output_data.ns)
6371 emacsframe->left_pos = r.origin.x;
6372 emacsframe->top_pos =
6373 [screen frame].size.height - (r.origin.y + r.size.height);
6378 /* Called AFTER method below, but before our windowWillResize call there leads
6379 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6380 location so set_window_size moves the frame. */
6381 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6383 emacsframe->output_data.ns->zooming = 1;
6388 /* Override to do something slightly nonstandard, but nice. First click on
6389 zoom button will zoom vertically. Second will zoom completely. Third
6390 returns to original. */
6391 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6392 defaultFrame:(NSRect)defaultFrame
6394 NSRect result = [sender frame];
6396 NSTRACE (windowWillUseStandardFrame);
6398 if (fs_before_fs != -1) /* Entering fullscreen */
6400 result = defaultFrame;
6402 else if (next_maximized == FULLSCREEN_HEIGHT
6403 || (next_maximized == -1
6404 && abs ((int)(defaultFrame.size.height - result.size.height))
6405 > FRAME_LINE_HEIGHT (emacsframe)))
6408 ns_userRect = result;
6409 maximized_height = result.size.height = defaultFrame.size.height;
6410 maximized_width = -1;
6411 result.origin.y = defaultFrame.origin.y;
6412 [self setFSValue: FULLSCREEN_HEIGHT];
6413 #ifdef NS_IMPL_COCOA
6414 maximizing_resize = YES;
6417 else if (next_maximized == FULLSCREEN_WIDTH)
6419 ns_userRect = result;
6420 maximized_width = result.size.width = defaultFrame.size.width;
6421 maximized_height = -1;
6422 result.origin.x = defaultFrame.origin.x;
6423 [self setFSValue: FULLSCREEN_WIDTH];
6425 else if (next_maximized == FULLSCREEN_MAXIMIZED
6426 || (next_maximized == -1
6427 && abs ((int)(defaultFrame.size.width - result.size.width))
6428 > FRAME_COLUMN_WIDTH (emacsframe)))
6430 result = defaultFrame; /* second click */
6431 maximized_width = result.size.width;
6432 maximized_height = result.size.height;
6433 [self setFSValue: FULLSCREEN_MAXIMIZED];
6434 #ifdef NS_IMPL_COCOA
6435 maximizing_resize = YES;
6441 result = ns_userRect.size.height ? ns_userRect : result;
6442 ns_userRect = NSMakeRect (0, 0, 0, 0);
6443 #ifdef NS_IMPL_COCOA
6444 maximizing_resize = fs_state != FULLSCREEN_NONE;
6446 [self setFSValue: FULLSCREEN_NONE];
6447 maximized_width = maximized_height = -1;
6450 if (fs_before_fs == -1) next_maximized = -1;
6451 [self windowWillResize: sender toSize: result.size];
6456 - (void)windowDidDeminiaturize: sender
6458 NSTRACE (windowDidDeminiaturize);
6459 if (!emacsframe->output_data.ns)
6462 SET_FRAME_ICONIFIED (emacsframe, 0);
6463 SET_FRAME_VISIBLE (emacsframe, 1);
6464 windows_or_buffers_changed = 63;
6468 emacs_event->kind = DEICONIFY_EVENT;
6469 EV_TRAILER ((id)nil);
6474 - (void)windowDidExpose: sender
6476 NSTRACE (windowDidExpose);
6477 if (!emacsframe->output_data.ns)
6480 SET_FRAME_VISIBLE (emacsframe, 1);
6481 SET_FRAME_GARBAGED (emacsframe);
6483 if (send_appdefined)
6484 ns_send_appdefined (-1);
6488 - (void)windowDidMiniaturize: sender
6490 NSTRACE (windowDidMiniaturize);
6491 if (!emacsframe->output_data.ns)
6494 SET_FRAME_ICONIFIED (emacsframe, 1);
6495 SET_FRAME_VISIBLE (emacsframe, 0);
6499 emacs_event->kind = ICONIFY_EVENT;
6500 EV_TRAILER ((id)nil);
6504 #ifdef HAVE_NATIVE_FS
6505 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6506 willUseFullScreenPresentationOptions:
6507 (NSApplicationPresentationOptions)proposedOptions
6509 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6513 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6515 fs_before_fs = fs_state;
6518 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6520 [self setFSValue: FULLSCREEN_BOTH];
6521 if (! [self fsIsNative])
6523 [self windowDidBecomeKey:notification];
6524 [nonfs_window orderOut:self];
6528 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6529 #ifdef NS_IMPL_COCOA
6530 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6531 unsigned val = (unsigned)[NSApp presentationOptions];
6533 // OSX 10.7 bug fix, the menu won't appear without this.
6534 // val is non-zero on other OSX versions.
6537 NSApplicationPresentationOptions options
6538 = NSApplicationPresentationAutoHideDock
6539 | NSApplicationPresentationAutoHideMenuBar
6540 | NSApplicationPresentationFullScreen
6541 | NSApplicationPresentationAutoHideToolbar;
6543 [NSApp setPresentationOptions: options];
6547 [toolbar setVisible:tbar_visible];
6551 - (void)windowWillExitFullScreen:(NSNotification *)notification
6553 if (next_maximized != -1)
6554 fs_before_fs = next_maximized;
6557 - (void)windowDidExitFullScreen:(NSNotification *)notification
6559 [self setFSValue: fs_before_fs];
6561 #ifdef HAVE_NATIVE_FS
6562 [self updateCollectionBehavior];
6564 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6566 [toolbar setVisible:YES];
6567 update_frame_tool_bar (emacsframe);
6568 [self updateFrameSize:YES];
6569 [[self window] display];
6572 [toolbar setVisible:NO];
6574 if (next_maximized != -1)
6575 [[self window] performZoom:self];
6580 return fs_is_native;
6583 - (BOOL)isFullscreen
6585 if (! fs_is_native) return nonfs_window != nil;
6586 #ifdef HAVE_NATIVE_FS
6587 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6593 #ifdef HAVE_NATIVE_FS
6594 - (void)updateCollectionBehavior
6596 if (! [self isFullscreen])
6598 NSWindow *win = [self window];
6599 NSWindowCollectionBehavior b = [win collectionBehavior];
6600 if (ns_use_native_fullscreen)
6601 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6603 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6605 [win setCollectionBehavior: b];
6606 fs_is_native = ns_use_native_fullscreen;
6611 - (void)toggleFullScreen: (id)sender
6622 #ifdef HAVE_NATIVE_FS
6623 [[self window] toggleFullScreen:sender];
6629 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6632 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6633 (FRAME_DEFAULT_FACE (f)),
6636 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6637 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6639 if (fs_state != FULLSCREEN_BOTH)
6641 NSScreen *screen = [w screen];
6643 #if defined (NS_IMPL_COCOA) && \
6644 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6645 /* Hide ghost menu bar on secondary monitor? */
6646 if (! onFirstScreen)
6647 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6649 /* Hide dock and menubar if we are on the primary screen. */
6652 #ifdef NS_IMPL_COCOA
6653 NSApplicationPresentationOptions options
6654 = NSApplicationPresentationAutoHideDock
6655 | NSApplicationPresentationAutoHideMenuBar;
6657 [NSApp setPresentationOptions: options];
6659 [NSMenu setMenuBarVisible:NO];
6663 fw = [[EmacsFSWindow alloc]
6664 initWithContentRect:[w contentRectForFrameRect:wr]
6665 styleMask:NSBorderlessWindowMask
6666 backing:NSBackingStoreBuffered
6670 [fw setContentView:[w contentView]];
6671 [fw setTitle:[w title]];
6672 [fw setDelegate:self];
6673 [fw setAcceptsMouseMovedEvents: YES];
6674 #if !defined (NS_IMPL_COCOA) || \
6675 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6676 [fw useOptimizedDrawing: YES];
6678 [fw setResizeIncrements: sz];
6679 [fw setBackgroundColor: col];
6680 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6683 f->border_width = 0;
6684 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6685 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6686 FRAME_TOOLBAR_HEIGHT (f) = 0;
6690 [self windowWillEnterFullScreen:nil];
6691 [fw makeKeyAndOrderFront:NSApp];
6692 [fw makeFirstResponder:self];
6694 r = [fw frameRectForContentRect:[screen frame]];
6695 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6696 [self windowDidEnterFullScreen:nil];
6707 #ifdef NS_IMPL_COCOA
6708 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6710 [NSMenu setMenuBarVisible:YES];
6714 [w setContentView:[fw contentView]];
6715 [w setResizeIncrements: sz];
6716 [w setBackgroundColor: col];
6717 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6720 f->border_width = bwidth;
6721 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6722 if (FRAME_EXTERNAL_TOOL_BAR (f))
6723 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6725 [self windowWillExitFullScreen:nil];
6726 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6728 [w makeKeyAndOrderFront:NSApp];
6729 [self windowDidExitFullScreen:nil];
6730 [self updateFrameSize:YES];
6736 if (fs_state != emacsframe->want_fullscreen)
6739 sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
6740 sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (emacsframe);
6741 [[self window] setResizeIncrements:sz];
6743 if (fs_state == FULLSCREEN_BOTH)
6745 [self toggleFullScreen:self];
6748 switch (emacsframe->want_fullscreen)
6750 case FULLSCREEN_BOTH:
6751 [self toggleFullScreen:self];
6753 case FULLSCREEN_WIDTH:
6754 next_maximized = FULLSCREEN_WIDTH;
6755 if (fs_state != FULLSCREEN_BOTH)
6756 [[self window] performZoom:self];
6758 case FULLSCREEN_HEIGHT:
6759 next_maximized = FULLSCREEN_HEIGHT;
6760 if (fs_state != FULLSCREEN_BOTH)
6761 [[self window] performZoom:self];
6763 case FULLSCREEN_MAXIMIZED:
6764 next_maximized = FULLSCREEN_MAXIMIZED;
6765 if (fs_state != FULLSCREEN_BOTH)
6766 [[self window] performZoom:self];
6768 case FULLSCREEN_NONE:
6769 if (fs_state != FULLSCREEN_BOTH)
6771 next_maximized = FULLSCREEN_NONE;
6772 [[self window] performZoom:self];
6777 emacsframe->want_fullscreen = FULLSCREEN_NONE;
6782 - (void) setFSValue: (int)value
6784 Lisp_Object lval = Qnil;
6787 case FULLSCREEN_BOTH:
6790 case FULLSCREEN_WIDTH:
6793 case FULLSCREEN_HEIGHT:
6796 case FULLSCREEN_MAXIMIZED:
6800 store_frame_param (emacsframe, Qfullscreen, lval);
6804 - (void)mouseEntered: (NSEvent *)theEvent
6806 NSTRACE (mouseEntered);
6808 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6809 = EV_TIMESTAMP (theEvent);
6813 - (void)mouseExited: (NSEvent *)theEvent
6815 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6817 NSTRACE (mouseExited);
6822 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6823 = EV_TIMESTAMP (theEvent);
6825 if (emacsframe == hlinfo->mouse_face_mouse_frame)
6827 clear_mouse_face (hlinfo);
6828 hlinfo->mouse_face_mouse_frame = 0;
6836 if (context_menu_value == -1)
6837 context_menu_value = [sender tag];
6840 NSInteger tag = [sender tag];
6841 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6842 emacsframe->menu_bar_vector,
6846 ns_send_appdefined (-1);
6851 - (EmacsToolbar *)toolbar
6857 /* this gets called on toolbar button click */
6858 - toolbarClicked: (id)item
6861 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6863 NSTRACE (toolbarClicked);
6868 /* send first event (for some reason two needed) */
6869 theEvent = [[self window] currentEvent];
6870 emacs_event->kind = TOOL_BAR_EVENT;
6871 XSETFRAME (emacs_event->arg, emacsframe);
6872 EV_TRAILER (theEvent);
6874 emacs_event->kind = TOOL_BAR_EVENT;
6875 /* XSETINT (emacs_event->code, 0); */
6876 emacs_event->arg = AREF (emacsframe->tool_bar_items,
6877 idx + TOOL_BAR_ITEM_KEY);
6878 emacs_event->modifiers = EV_MODIFIERS (theEvent);
6879 EV_TRAILER (theEvent);
6884 - toggleToolbar: (id)sender
6889 emacs_event->kind = NS_NONKEY_EVENT;
6890 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6891 EV_TRAILER ((id)nil);
6896 - (void)drawRect: (NSRect)rect
6898 int x = NSMinX (rect), y = NSMinY (rect);
6899 int width = NSWidth (rect), height = NSHeight (rect);
6903 if (!emacsframe || !emacsframe->output_data.ns)
6906 ns_clear_frame_area (emacsframe, x, y, width, height);
6908 expose_frame (emacsframe, x, y, width, height);
6912 drawRect: may be called (at least in OS X 10.5) for invisible
6913 views as well for some reason. Thus, do not infer visibility
6916 emacsframe->async_visible = 1;
6917 emacsframe->async_iconified = 0;
6922 /* NSDraggingDestination protocol methods. Actually this is not really a
6923 protocol, but a category of Object. O well... */
6925 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
6927 NSTRACE (draggingEntered);
6928 return NSDragOperationGeneric;
6932 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6938 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6943 NSEvent *theEvent = [[self window] currentEvent];
6945 NSDragOperation op = [sender draggingSourceOperationMask];
6948 NSTRACE (performDragOperation);
6953 position = [self convertPoint: [sender draggingLocation] fromView: nil];
6954 x = lrint (position.x); y = lrint (position.y);
6956 pb = [sender draggingPasteboard];
6957 type = [pb availableTypeFromArray: ns_drag_types];
6959 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6960 // URL drags contain all operations (0xf), don't allow all to be set.
6963 if (op & NSDragOperationLink)
6964 modifiers |= NSControlKeyMask;
6965 if (op & NSDragOperationCopy)
6966 modifiers |= NSAlternateKeyMask;
6967 if (op & NSDragOperationGeneric)
6968 modifiers |= NSCommandKeyMask;
6971 modifiers = EV_MODIFIERS2 (modifiers);
6976 else if ([type isEqualToString: NSFilenamesPboardType])
6979 NSEnumerator *fenum;
6982 if (!(files = [pb propertyListForType: type]))
6985 fenum = [files objectEnumerator];
6986 while ( (file = [fenum nextObject]) )
6988 emacs_event->kind = DRAG_N_DROP_EVENT;
6989 XSETINT (emacs_event->x, x);
6990 XSETINT (emacs_event->y, y);
6991 ns_input_file = append2 (ns_input_file,
6992 build_string ([file UTF8String]));
6993 emacs_event->modifiers = modifiers;
6994 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
6995 EV_TRAILER (theEvent);
6999 else if ([type isEqualToString: NSURLPboardType])
7001 NSURL *url = [NSURL URLFromPasteboard: pb];
7002 if (url == nil) return NO;
7004 emacs_event->kind = DRAG_N_DROP_EVENT;
7005 XSETINT (emacs_event->x, x);
7006 XSETINT (emacs_event->y, y);
7007 emacs_event->modifiers = modifiers;
7008 emacs_event->arg = list2 (Qurl,
7009 build_string ([[url absoluteString]
7011 EV_TRAILER (theEvent);
7013 if ([url isFileURL] != NO)
7015 NSString *file = [url path];
7016 ns_input_file = append2 (ns_input_file,
7017 build_string ([file UTF8String]));
7021 else if ([type isEqualToString: NSStringPboardType]
7022 || [type isEqualToString: NSTabularTextPboardType])
7026 if (! (data = [pb stringForType: type]))
7029 emacs_event->kind = DRAG_N_DROP_EVENT;
7030 XSETINT (emacs_event->x, x);
7031 XSETINT (emacs_event->y, y);
7032 emacs_event->modifiers = modifiers;
7033 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7034 EV_TRAILER (theEvent);
7039 fprintf (stderr, "Invalid data type in dragging pasteboard");
7045 - (id) validRequestorForSendType: (NSString *)typeSent
7046 returnType: (NSString *)typeReturned
7048 NSTRACE (validRequestorForSendType);
7049 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7050 && typeReturned == nil)
7052 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7056 return [super validRequestorForSendType: typeSent
7057 returnType: typeReturned];
7061 /* The next two methods are part of NSServicesRequests informal protocol,
7062 supposedly called when a services menu item is chosen from this app.
7063 But this should not happen because we override the services menu with our
7064 own entries which call ns-perform-service.
7065 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7066 So let's at least stub them out until further investigation can be done. */
7068 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7070 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7071 be written into the buffer in place of the existing selection..
7072 ordinary service calls go through functions defined in ns-win.el */
7076 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7078 NSArray *typesDeclared;
7081 /* We only support NSStringPboardType */
7082 if ([types containsObject:NSStringPboardType] == NO) {
7086 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7087 if (CONSP (val) && SYMBOLP (XCAR (val)))
7090 if (CONSP (val) && NILP (XCDR (val)))
7093 if (! STRINGP (val))
7096 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7097 [pb declareTypes:typesDeclared owner:nil];
7098 ns_string_to_pasteboard (pb, val);
7103 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7104 (gives a miniaturized version of the window); currently we use the latter for
7105 frames whose active buffer doesn't correspond to any file
7106 (e.g., '*scratch*') */
7107 - setMiniwindowImage: (BOOL) setMini
7109 id image = [[self window] miniwindowImage];
7110 NSTRACE (setMiniwindowImage);
7112 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7113 about "AppleDockIconEnabled" notwithstanding, however the set message
7114 below has its effect nonetheless. */
7115 if (image != emacsframe->output_data.ns->miniimage)
7117 if (image && [image isKindOfClass: [EmacsImage class]])
7119 [[self window] setMiniwindowImage:
7120 setMini ? emacsframe->output_data.ns->miniimage : nil];
7127 - (void) setRows: (int) r andColumns: (int) c
7133 @end /* EmacsView */
7137 /* ==========================================================================
7139 EmacsWindow implementation
7141 ========================================================================== */
7143 @implementation EmacsWindow
7145 #ifdef NS_IMPL_COCOA
7146 - (id)accessibilityAttributeValue:(NSString *)attribute
7148 Lisp_Object str = Qnil;
7149 struct frame *f = SELECTED_FRAME ();
7150 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7152 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7153 return NSAccessibilityTextFieldRole;
7155 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7156 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7158 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7160 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7162 if (! NILP (BVAR (curbuf, mark_active)))
7163 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7167 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7168 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7169 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7171 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7172 str = make_uninit_multibyte_string (range, byte_range);
7174 str = make_uninit_string (range);
7175 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7176 Is this a problem? */
7177 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7184 if (CONSP (str) && SYMBOLP (XCAR (str)))
7187 if (CONSP (str) && NILP (XCDR (str)))
7192 const char *utfStr = SSDATA (str);
7193 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7198 return [super accessibilityAttributeValue:attribute];
7200 #endif /* NS_IMPL_COCOA */
7202 /* If we have multiple monitors, one above the other, we don't want to
7203 restrict the height to just one monitor. So we override this. */
7204 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7206 /* When making the frame visible for the first time or if there is just
7207 one screen, we want to constrain. Other times not. */
7208 NSArray *screens = [NSScreen screens];
7209 NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7210 NSTRACE (constrainFrameRect);
7211 NSTRACE_RECT ("input", frameRect);
7213 if (ns_menu_bar_should_be_hidden ())
7216 if (nr_screens == 1)
7217 return [super constrainFrameRect:frameRect toScreen:screen];
7219 #ifdef NS_IMPL_COCOA
7220 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7221 // If separate spaces is on, it is like each screen is independent. There is
7222 // no spanning of frames across screens.
7223 if ([NSScreen screensHaveSeparateSpaces])
7224 return [super constrainFrameRect:frameRect toScreen:screen];
7228 for (i = 0; i < nr_screens; ++i)
7230 NSScreen *s = [screens objectAtIndex: i];
7231 NSRect scrrect = [s frame];
7232 NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7234 if (intersect.size.width > 0 || intersect.size.height > 0)
7238 if (nr_eff_screens == 1)
7239 return [super constrainFrameRect:frameRect toScreen:screen];
7241 /* The default implementation does two things 1) ensure that the top
7242 of the rectangle is below the menu bar (or below the top of the
7243 screen) and 2) resizes windows larger than the screen. As we
7244 don't want the latter, a smaller rectangle is used. */
7245 #define FAKE_HEIGHT 64
7246 float old_top = frameRect.origin.y + frameRect.size.height;
7248 r.size.height = FAKE_HEIGHT;
7249 r.size.width = frameRect.size.width;
7250 r.origin.x = frameRect.origin.x;
7251 r.origin.y = old_top - FAKE_HEIGHT;
7253 NSTRACE_RECT ("input to super", r);
7255 r = [super constrainFrameRect:r toScreen:screen];
7257 NSTRACE_RECT ("output from super", r);
7259 float new_top = r.origin.y + FAKE_HEIGHT;
7260 if (new_top < old_top)
7262 frameRect.origin.y = new_top - frameRect.size.height;
7265 NSTRACE_RECT ("output", frameRect);
7271 @end /* EmacsWindow */
7274 @implementation EmacsFSWindow
7276 - (BOOL)canBecomeKeyWindow
7281 - (BOOL)canBecomeMainWindow
7288 /* ==========================================================================
7290 EmacsScroller implementation
7292 ========================================================================== */
7295 @implementation EmacsScroller
7297 /* for repeat button push */
7298 #define SCROLL_BAR_FIRST_DELAY 0.5
7299 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7301 + (CGFloat) scrollerWidth
7303 /* TODO: if we want to allow variable widths, this is the place to do it,
7304 however neither GNUstep nor Cocoa support it very well */
7306 #if !defined (NS_IMPL_COCOA) || \
7307 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7308 r = [NSScroller scrollerWidth];
7310 r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7311 scrollerStyle: NSScrollerStyleLegacy];
7317 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7319 NSTRACE (EmacsScroller_initFrame);
7321 r.size.width = [EmacsScroller scrollerWidth];
7322 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7323 [self setContinuous: YES];
7324 [self setEnabled: YES];
7326 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7327 locked against the top and bottom edges, and right edge on OS X, where
7328 scrollers are on right. */
7329 #ifdef NS_IMPL_GNUSTEP
7330 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7332 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7335 window = XWINDOW (nwin);
7337 pixel_height = NSHeight (r);
7338 if (pixel_height == 0) pixel_height = 1;
7339 min_portion = 20 / pixel_height;
7341 frame = XFRAME (window->frame);
7342 if (FRAME_LIVE_P (frame))
7345 EmacsView *view = FRAME_NS_VIEW (frame);
7346 NSView *sview = [[view window] contentView];
7347 NSArray *subs = [sview subviews];
7349 /* disable optimization stopping redraw of other scrollbars */
7350 view->scrollbarsNeedingUpdate = 0;
7351 for (i =[subs count]-1; i >= 0; i--)
7352 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7353 view->scrollbarsNeedingUpdate++;
7354 [sview addSubview: self];
7357 /* [self setFrame: r]; */
7363 - (void)setFrame: (NSRect)newRect
7365 NSTRACE (EmacsScroller_setFrame);
7366 /* block_input (); */
7367 pixel_height = NSHeight (newRect);
7368 if (pixel_height == 0) pixel_height = 1;
7369 min_portion = 20 / pixel_height;
7370 [super setFrame: newRect];
7371 /* unblock_input (); */
7377 NSTRACE (EmacsScroller_dealloc);
7379 wset_vertical_scroll_bar (window, Qnil);
7404 bool ret = condemned;
7409 /* ensure other scrollbar updates after deletion */
7410 view = (EmacsView *)FRAME_NS_VIEW (frame);
7412 view->scrollbarsNeedingUpdate++;
7414 wset_vertical_scroll_bar (window, Qnil);
7416 [self removeFromSuperview];
7424 - (void)resetCursorRects
7426 NSRect visible = [self visibleRect];
7427 NSTRACE (resetCursorRects);
7429 if (!NSIsEmptyRect (visible))
7430 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7431 [[NSCursor arrowCursor] setOnMouseEntered: YES];
7435 - (int) checkSamePosition: (int) position portion: (int) portion
7438 return em_position ==position && em_portion ==portion && em_whole ==whole
7439 && portion != whole; /* needed for resize empty buf */
7443 - setPosition: (int)position portion: (int)portion whole: (int)whole
7445 NSTRACE (setPosition);
7447 em_position = position;
7448 em_portion = portion;
7451 if (portion >= whole)
7453 #ifdef NS_IMPL_COCOA
7454 [self setKnobProportion: 1.0];
7455 [self setDoubleValue: 1.0];
7457 [self setFloatValue: 0.0 knobProportion: 1.0];
7464 portion = max ((float)whole*min_portion/pixel_height, portion);
7465 pos = (float)position / (whole - portion);
7466 por = (CGFloat)portion/whole;
7467 #ifdef NS_IMPL_COCOA
7468 [self setKnobProportion: por];
7469 [self setDoubleValue: pos];
7471 [self setFloatValue: pos knobProportion: por];
7478 /* set up emacs_event */
7479 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7485 emacs_event->part = last_hit_part;
7486 emacs_event->code = 0;
7487 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7488 XSETWINDOW (win, window);
7489 emacs_event->frame_or_window = win;
7490 emacs_event->timestamp = EV_TIMESTAMP (e);
7491 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7492 emacs_event->arg = Qnil;
7493 XSETINT (emacs_event->x, loc * pixel_height);
7494 XSETINT (emacs_event->y, pixel_height-20);
7498 n_emacs_events_pending++;
7499 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7502 hold_event (emacs_event);
7503 EVENT_INIT (*emacs_event);
7504 ns_send_appdefined (-1);
7508 /* called manually thru timer to implement repeated button action w/hold-down */
7509 - repeatScroll: (NSTimer *)scrollEntry
7511 NSEvent *e = [[self window] currentEvent];
7512 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
7513 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7515 /* clear timer if need be */
7516 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7518 [scroll_repeat_entry invalidate];
7519 [scroll_repeat_entry release];
7520 scroll_repeat_entry = nil;
7526 = [[NSTimer scheduledTimerWithTimeInterval:
7527 SCROLL_BAR_CONTINUOUS_DELAY
7529 selector: @selector (repeatScroll:)
7535 [self sendScrollEventAtLoc: 0 fromEvent: e];
7540 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
7541 mouseDragged events without going into a modal loop. */
7542 - (void)mouseDown: (NSEvent *)e
7545 /* hitPart is only updated AFTER event is passed on */
7546 NSScrollerPart part = [self testPart: [e locationInWindow]];
7547 CGFloat inc = 0.0, loc, kloc, pos;
7550 NSTRACE (EmacsScroller_mouseDown);
7554 case NSScrollerDecrementPage:
7555 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7556 case NSScrollerIncrementPage:
7557 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7558 case NSScrollerDecrementLine:
7559 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7560 case NSScrollerIncrementLine:
7561 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7562 case NSScrollerKnob:
7563 last_hit_part = scroll_bar_handle; break;
7564 case NSScrollerKnobSlot: /* GNUstep-only */
7565 last_hit_part = scroll_bar_move_ratio; break;
7566 default: /* NSScrollerNoPart? */
7567 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7574 pos = 0; /* ignored */
7576 /* set a timer to repeat, as we can't let superclass do this modally */
7578 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7580 selector: @selector (repeatScroll:)
7587 /* handle, or on GNUstep possibly slot */
7588 NSEvent *fake_event;
7590 /* compute float loc in slot and mouse offset on knob */
7591 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7593 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7599 else if (loc >= NSHeight (sr))
7601 loc = NSHeight (sr);
7609 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7611 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7613 last_mouse_offset = kloc;
7615 /* if knob, tell emacs a location offset by knob pos
7616 (to indicate top of handle) */
7617 if (part == NSScrollerKnob)
7618 pos = (loc - last_mouse_offset) / NSHeight (sr);
7620 /* else this is a slot click on GNUstep: go straight there */
7621 pos = loc / NSHeight (sr);
7623 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7624 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7625 location: [e locationInWindow]
7626 modifierFlags: [e modifierFlags]
7627 timestamp: [e timestamp]
7628 windowNumber: [e windowNumber]
7629 context: [e context]
7630 eventNumber: [e eventNumber]
7631 clickCount: [e clickCount]
7632 pressure: [e pressure]];
7633 [super mouseUp: fake_event];
7636 if (part != NSScrollerKnob)
7637 [self sendScrollEventAtLoc: pos fromEvent: e];
7641 /* Called as we manually track scroller drags, rather than superclass. */
7642 - (void)mouseDragged: (NSEvent *)e
7647 NSTRACE (EmacsScroller_mouseDragged);
7649 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7651 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7657 else if (loc >= NSHeight (sr) + last_mouse_offset)
7659 loc = NSHeight (sr) + last_mouse_offset;
7662 pos = (loc - last_mouse_offset) / NSHeight (sr);
7663 [self sendScrollEventAtLoc: pos fromEvent: e];
7667 - (void)mouseUp: (NSEvent *)e
7669 if (scroll_repeat_entry)
7671 [scroll_repeat_entry invalidate];
7672 [scroll_repeat_entry release];
7673 scroll_repeat_entry = nil;
7675 last_hit_part = scroll_bar_above_handle;
7679 /* treat scrollwheel events in the bar as though they were in the main window */
7680 - (void) scrollWheel: (NSEvent *)theEvent
7682 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7683 [view mouseDown: theEvent];
7686 @end /* EmacsScroller */
7689 #ifdef NS_IMPL_GNUSTEP
7690 /* Dummy class to get rid of startup warnings. */
7691 @implementation EmacsDocument
7697 /* ==========================================================================
7699 Font-related functions; these used to be in nsfaces.m
7701 ========================================================================== */
7705 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7707 struct font *font = XFONT_OBJECT (font_object);
7708 EmacsView *view = FRAME_NS_VIEW (f);
7709 int font_ascent, font_descent;
7712 fontset = fontset_from_font (font_object);
7713 FRAME_FONTSET (f) = fontset;
7715 if (FRAME_FONT (f) == font)
7716 /* This font is already set in frame F. There's nothing more to
7720 FRAME_FONT (f) = font;
7722 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7723 FRAME_COLUMN_WIDTH (f) = font->average_width;
7724 get_font_ascent_descent (font, &font_ascent, &font_descent);
7725 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
7727 /* Compute the scroll bar width in character columns. */
7728 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7730 int wid = FRAME_COLUMN_WIDTH (f);
7731 FRAME_CONFIG_SCROLL_BAR_COLS (f)
7732 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7736 int wid = FRAME_COLUMN_WIDTH (f);
7737 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7740 /* Compute the scroll bar height in character lines. */
7741 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7743 int height = FRAME_LINE_HEIGHT (f);
7744 FRAME_CONFIG_SCROLL_BAR_LINES (f)
7745 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7749 int height = FRAME_LINE_HEIGHT (f);
7750 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7753 /* Now make the frame display the given font. */
7754 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7755 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7756 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
7763 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7764 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7768 ns_xlfd_to_fontname (const char *xlfd)
7769 /* --------------------------------------------------------------------------
7770 Convert an X font name (XLFD) to an NS font name.
7771 Only family is used.
7772 The string returned is temporarily allocated.
7773 -------------------------------------------------------------------------- */
7775 char *name = xmalloc (180);
7779 if (!strncmp (xlfd, "--", 2))
7780 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7782 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7784 /* stopgap for malformed XLFD input */
7785 if (strlen (name) == 0)
7786 strcpy (name, "Monaco");
7788 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7789 also uppercase after '-' or ' ' */
7790 name[0] = c_toupper (name[0]);
7791 for (len =strlen (name), i =0; i<len; i++)
7797 name[i+1] = c_toupper (name[i+1]);
7799 else if (name[i] == '_')
7803 name[i+1] = c_toupper (name[i+1]);
7806 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
7807 ret = [[NSString stringWithUTF8String: name] UTF8String];
7814 syms_of_nsterm (void)
7816 NSTRACE (syms_of_nsterm);
7818 ns_antialias_threshold = 10.0;
7820 /* from 23+ we need to tell emacs what modifiers there are.. */
7821 DEFSYM (Qmodifier_value, "modifier-value");
7822 DEFSYM (Qalt, "alt");
7823 DEFSYM (Qhyper, "hyper");
7824 DEFSYM (Qmeta, "meta");
7825 DEFSYM (Qsuper, "super");
7826 DEFSYM (Qcontrol, "control");
7827 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7829 DEFSYM (Qfile, "file");
7830 DEFSYM (Qurl, "url");
7832 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7833 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7834 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7835 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7836 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7838 DEFVAR_LISP ("ns-input-file", ns_input_file,
7839 "The file specified in the last NS event.");
7840 ns_input_file =Qnil;
7842 DEFVAR_LISP ("ns-working-text", ns_working_text,
7843 "String for visualizing working composition sequence.");
7844 ns_working_text =Qnil;
7846 DEFVAR_LISP ("ns-input-font", ns_input_font,
7847 "The font specified in the last NS event.");
7848 ns_input_font =Qnil;
7850 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7851 "The fontsize specified in the last NS event.");
7852 ns_input_fontsize =Qnil;
7854 DEFVAR_LISP ("ns-input-line", ns_input_line,
7855 "The line specified in the last NS event.");
7856 ns_input_line =Qnil;
7858 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7859 "The service name specified in the last NS event.");
7860 ns_input_spi_name =Qnil;
7862 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7863 "The service argument specified in the last NS event.");
7864 ns_input_spi_arg =Qnil;
7866 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7867 "This variable describes the behavior of the alternate or option key.\n\
7868 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7869 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7870 at all, allowing it to be used at a lower level for accented character entry.");
7871 ns_alternate_modifier = Qmeta;
7873 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7874 "This variable describes the behavior of the right alternate or option key.\n\
7875 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7876 Set to left means be the same key as `ns-alternate-modifier'.\n\
7877 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7878 at all, allowing it to be used at a lower level for accented character entry.");
7879 ns_right_alternate_modifier = Qleft;
7881 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7882 "This variable describes the behavior of the command key.\n\
7883 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7884 ns_command_modifier = Qsuper;
7886 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7887 "This variable describes the behavior of the right command key.\n\
7888 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7889 Set to left means be the same key as `ns-command-modifier'.\n\
7890 Set to none means that the command / option key is not interpreted by Emacs\n\
7891 at all, allowing it to be used at a lower level for accented character entry.");
7892 ns_right_command_modifier = Qleft;
7894 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7895 "This variable describes the behavior of the control key.\n\
7896 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7897 ns_control_modifier = Qcontrol;
7899 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7900 "This variable describes the behavior of the right control key.\n\
7901 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7902 Set to left means be the same key as `ns-control-modifier'.\n\
7903 Set to none means that the control / option key is not interpreted by Emacs\n\
7904 at all, allowing it to be used at a lower level for accented character entry.");
7905 ns_right_control_modifier = Qleft;
7907 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7908 "This variable describes the behavior of the function key (on laptops).\n\
7909 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7910 Set to none means that the function key is not interpreted by Emacs at all,\n\
7911 allowing it to be used at a lower level for accented character entry.");
7912 ns_function_modifier = Qnone;
7914 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7915 "Non-nil (the default) means to render text antialiased.");
7916 ns_antialias_text = Qt;
7918 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7919 "Whether to confirm application quit using dialog.");
7920 ns_confirm_quit = Qnil;
7922 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7923 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7924 Only works on OSX 10.6 or later. */);
7925 ns_auto_hide_menu_bar = Qnil;
7927 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7928 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7929 Nil means use fullscreen the old (< 10.7) way. The old way works better with
7930 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
7931 Default is t for OSX >= 10.7, nil otherwise. */);
7932 #ifdef HAVE_NATIVE_FS
7933 ns_use_native_fullscreen = YES;
7935 ns_use_native_fullscreen = NO;
7937 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7939 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
7940 doc: /*Non-nil means use animation on non-native fullscreen.
7941 For native fullscreen, this does nothing.
7942 Default is nil. */);
7943 ns_use_fullscreen_animation = NO;
7945 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7946 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7947 Note that this does not apply to images.
7948 This variable is ignored on OSX < 10.7 and GNUstep. */);
7949 ns_use_srgb_colorspace = YES;
7951 /* TODO: move to common code */
7952 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7953 doc: /* Which toolkit scroll bars Emacs uses, if any.
7954 A value of nil means Emacs doesn't use toolkit scroll bars.
7955 With the X Window system, the value is a symbol describing the
7956 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
7957 With MS Windows or Nextstep, the value is t. */);
7958 Vx_toolkit_scroll_bars = Qt;
7960 DEFVAR_BOOL ("x-use-underline-position-properties",
7961 x_use_underline_position_properties,
7962 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7963 A value of nil means ignore them. If you encounter fonts with bogus
7964 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7965 to 4.1, set this to nil. */);
7966 x_use_underline_position_properties = 0;
7968 DEFVAR_BOOL ("x-underline-at-descent-line",
7969 x_underline_at_descent_line,
7970 doc: /* Non-nil means to draw the underline at the same place as the descent line.
7971 A value of nil means to draw the underline according to the value of the
7972 variable `x-use-underline-position-properties', which is usually at the
7973 baseline level. The default value is nil. */);
7974 x_underline_at_descent_line = 0;
7976 /* Tell Emacs about this window system. */
7977 Fprovide (Qns, Qnil);
7979 DEFSYM (Qcocoa, "cocoa");
7980 DEFSYM (Qgnustep, "gnustep");
7982 #ifdef NS_IMPL_COCOA
7983 Fprovide (Qcocoa, Qnil);
7986 Fprovide (Qgnustep, Qnil);