]> code.delx.au - gnu-emacs/blob - src/nsterm.m
NextSten maximization and NSTRACE rewrite.
[gnu-emacs] / src / nsterm.m
1 /* NeXT/Open/GNUstep / MacOSX communication module. -*- coding: utf-8 -*-
2
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 Free Software
4 Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
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.
12
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.
17
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/>. */
20
21 /*
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)
27 */
28
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
31 #include <config.h>
32
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
40
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
44
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
54
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
62
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
66
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
70
71
72 extern NSString *NSMenuDidBeginTrackingNotification;
73
74
75 #if NSTRACE_ENABLED
76 int nstrace_num = 0;
77 int nstrace_depth = 0;
78
79 /* Called when nstrace_enabled goes out of scope. */
80 void nstrace_leave(int * pointer_to_nstrace_enabled)
81 {
82 if (*pointer_to_nstrace_enabled)
83 {
84 --nstrace_depth;
85 }
86 }
87
88
89 void ns_print_fullscreen_type_name (char const * s, int fs_type)
90 {
91 // This is a support function for the NSTRACE system, don't add a
92 // NSTRACE () here. However, a local `nstrace_enabled' variable is
93 // needed by the NSTRACE_MSG macros.
94 int nstrace_enabled = 1;
95
96 switch (fs_type)
97 {
98 case FULLSCREEN_NONE:
99 NSTRACE_MSG ("%s: FULLSCREEN_NONE", s);
100 break;
101
102 case FULLSCREEN_WIDTH:
103 NSTRACE_MSG ("%s: FULLSCREEN_WIDTH", s);
104 break;
105
106 case FULLSCREEN_HEIGHT:
107 NSTRACE_MSG ("%s: FULLSCREEN_HEIGHT", s);
108 break;
109
110 case FULLSCREEN_BOTH:
111 NSTRACE_MSG ("%s: FULLSCREEN_BOTH", s);
112 break;
113
114 case FULLSCREEN_MAXIMIZED:
115 NSTRACE_MSG ("%s: FULLSCREEN_MAXIMIZED", s);
116 break;
117
118 default:
119 NSTRACE_MSG ("%s: %d", s, fs_type);
120 break;
121 }
122 }
123 #endif
124
125
126 /* ==========================================================================
127
128 NSColor, EmacsColor category.
129
130 ========================================================================== */
131 @implementation NSColor (EmacsColor)
132 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
133 blue:(CGFloat)blue alpha:(CGFloat)alpha
134 {
135 #ifdef NS_IMPL_COCOA
136 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
137 if (ns_use_srgb_colorspace)
138 return [NSColor colorWithSRGBRed: red
139 green: green
140 blue: blue
141 alpha: alpha];
142 #endif
143 #endif
144 return [NSColor colorWithCalibratedRed: red
145 green: green
146 blue: blue
147 alpha: alpha];
148 }
149
150 - (NSColor *)colorUsingDefaultColorSpace
151 {
152 #ifdef NS_IMPL_COCOA
153 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
154 if (ns_use_srgb_colorspace)
155 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
156 #endif
157 #endif
158 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
159 }
160
161 @end
162
163 /* ==========================================================================
164
165 Local declarations
166
167 ========================================================================== */
168
169 /* Convert a symbol indexed with an NSxxx value to a value as defined
170 in keyboard.c (lispy_function_key). I hope this is a correct way
171 of doing things... */
172 static unsigned convert_ns_to_X_keysym[] =
173 {
174 NSHomeFunctionKey, 0x50,
175 NSLeftArrowFunctionKey, 0x51,
176 NSUpArrowFunctionKey, 0x52,
177 NSRightArrowFunctionKey, 0x53,
178 NSDownArrowFunctionKey, 0x54,
179 NSPageUpFunctionKey, 0x55,
180 NSPageDownFunctionKey, 0x56,
181 NSEndFunctionKey, 0x57,
182 NSBeginFunctionKey, 0x58,
183 NSSelectFunctionKey, 0x60,
184 NSPrintFunctionKey, 0x61,
185 NSClearLineFunctionKey, 0x0B,
186 NSExecuteFunctionKey, 0x62,
187 NSInsertFunctionKey, 0x63,
188 NSUndoFunctionKey, 0x65,
189 NSRedoFunctionKey, 0x66,
190 NSMenuFunctionKey, 0x67,
191 NSFindFunctionKey, 0x68,
192 NSHelpFunctionKey, 0x6A,
193 NSBreakFunctionKey, 0x6B,
194
195 NSF1FunctionKey, 0xBE,
196 NSF2FunctionKey, 0xBF,
197 NSF3FunctionKey, 0xC0,
198 NSF4FunctionKey, 0xC1,
199 NSF5FunctionKey, 0xC2,
200 NSF6FunctionKey, 0xC3,
201 NSF7FunctionKey, 0xC4,
202 NSF8FunctionKey, 0xC5,
203 NSF9FunctionKey, 0xC6,
204 NSF10FunctionKey, 0xC7,
205 NSF11FunctionKey, 0xC8,
206 NSF12FunctionKey, 0xC9,
207 NSF13FunctionKey, 0xCA,
208 NSF14FunctionKey, 0xCB,
209 NSF15FunctionKey, 0xCC,
210 NSF16FunctionKey, 0xCD,
211 NSF17FunctionKey, 0xCE,
212 NSF18FunctionKey, 0xCF,
213 NSF19FunctionKey, 0xD0,
214 NSF20FunctionKey, 0xD1,
215 NSF21FunctionKey, 0xD2,
216 NSF22FunctionKey, 0xD3,
217 NSF23FunctionKey, 0xD4,
218 NSF24FunctionKey, 0xD5,
219
220 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
221 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
222 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
223
224 NSTabCharacter, 0x09,
225 0x19, 0x09, /* left tab->regular since pass shift */
226 NSCarriageReturnCharacter, 0x0D,
227 NSNewlineCharacter, 0x0D,
228 NSEnterCharacter, 0x8D,
229
230 0x41|NSNumericPadKeyMask, 0xAE, /* KP_Decimal */
231 0x43|NSNumericPadKeyMask, 0xAA, /* KP_Multiply */
232 0x45|NSNumericPadKeyMask, 0xAB, /* KP_Add */
233 0x4B|NSNumericPadKeyMask, 0xAF, /* KP_Divide */
234 0x4E|NSNumericPadKeyMask, 0xAD, /* KP_Subtract */
235 0x51|NSNumericPadKeyMask, 0xBD, /* KP_Equal */
236 0x52|NSNumericPadKeyMask, 0xB0, /* KP_0 */
237 0x53|NSNumericPadKeyMask, 0xB1, /* KP_1 */
238 0x54|NSNumericPadKeyMask, 0xB2, /* KP_2 */
239 0x55|NSNumericPadKeyMask, 0xB3, /* KP_3 */
240 0x56|NSNumericPadKeyMask, 0xB4, /* KP_4 */
241 0x57|NSNumericPadKeyMask, 0xB5, /* KP_5 */
242 0x58|NSNumericPadKeyMask, 0xB6, /* KP_6 */
243 0x59|NSNumericPadKeyMask, 0xB7, /* KP_7 */
244 0x5B|NSNumericPadKeyMask, 0xB8, /* KP_8 */
245 0x5C|NSNumericPadKeyMask, 0xB9, /* KP_9 */
246
247 0x1B, 0x1B /* escape */
248 };
249
250 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
251 the maximum font size to NOT antialias. On GNUstep there is currently
252 no way to control this behavior. */
253 float ns_antialias_threshold;
254
255 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
256 NSString *ns_app_name = @"Emacs"; /* default changed later */
257
258 /* Display variables */
259 struct ns_display_info *x_display_list; /* Chain of existing displays */
260 long context_menu_value = 0;
261
262 /* display update */
263 static struct frame *ns_updating_frame;
264 static NSView *focus_view = NULL;
265 static int ns_window_num = 0;
266 #ifdef NS_IMPL_GNUSTEP
267 static NSRect uRect; // TODO: This is dead, remove it?
268 #endif
269 static BOOL gsaved = NO;
270 static BOOL ns_fake_keydown = NO;
271 #ifdef NS_IMPL_COCOA
272 static BOOL ns_menu_bar_is_hidden = NO;
273 #endif
274 /*static int debug_lock = 0; */
275
276 /* event loop */
277 static BOOL send_appdefined = YES;
278 #define NO_APPDEFINED_DATA (-8)
279 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
280 static NSTimer *timed_entry = 0;
281 static NSTimer *scroll_repeat_entry = nil;
282 static fd_set select_readfds, select_writefds;
283 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
284 static int select_nfds = 0, select_valid = 0;
285 static struct timespec select_timeout = { 0, 0 };
286 static int selfds[2] = { -1, -1 };
287 static pthread_mutex_t select_mutex;
288 static int apploopnr = 0;
289 static NSAutoreleasePool *outerpool;
290 static struct input_event *emacs_event = NULL;
291 static struct input_event *q_event_ptr = NULL;
292 static int n_emacs_events_pending = 0;
293 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
294 *ns_pending_service_args;
295 static BOOL ns_do_open_file = NO;
296 static BOOL ns_last_use_native_fullscreen;
297
298 /* Non-zero means that a HELP_EVENT has been generated since Emacs
299 start. */
300
301 static BOOL any_help_event_p = NO;
302
303 static struct {
304 struct input_event *q;
305 int nr, cap;
306 } hold_event_q = {
307 NULL, 0, 0
308 };
309
310 static NSString *represented_filename = nil;
311 static struct frame *represented_frame = 0;
312
313 #ifdef NS_IMPL_COCOA
314 /*
315 * State for pending menu activation:
316 * MENU_NONE Normal state
317 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
318 * run lisp to update the menu.
319 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
320 * will open.
321 */
322 #define MENU_NONE 0
323 #define MENU_PENDING 1
324 #define MENU_OPENING 2
325 static int menu_will_open_state = MENU_NONE;
326
327 /* Saved position for menu click. */
328 static CGPoint menu_mouse_point;
329 #endif
330
331 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
332 #define NS_FUNCTION_KEY_MASK 0x800000
333 #define NSLeftControlKeyMask (0x000001 | NSControlKeyMask)
334 #define NSRightControlKeyMask (0x002000 | NSControlKeyMask)
335 #define NSLeftCommandKeyMask (0x000008 | NSCommandKeyMask)
336 #define NSRightCommandKeyMask (0x000010 | NSCommandKeyMask)
337 #define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask)
338 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
339 #define EV_MODIFIERS2(flags) \
340 (((flags & NSHelpKeyMask) ? \
341 hyper_modifier : 0) \
342 | (!EQ (ns_right_alternate_modifier, Qleft) && \
343 ((flags & NSRightAlternateKeyMask) \
344 == NSRightAlternateKeyMask) ? \
345 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
346 | ((flags & NSAlternateKeyMask) ? \
347 parse_solitary_modifier (ns_alternate_modifier) : 0) \
348 | ((flags & NSShiftKeyMask) ? \
349 shift_modifier : 0) \
350 | (!EQ (ns_right_control_modifier, Qleft) && \
351 ((flags & NSRightControlKeyMask) \
352 == NSRightControlKeyMask) ? \
353 parse_solitary_modifier (ns_right_control_modifier) : 0) \
354 | ((flags & NSControlKeyMask) ? \
355 parse_solitary_modifier (ns_control_modifier) : 0) \
356 | ((flags & NS_FUNCTION_KEY_MASK) ? \
357 parse_solitary_modifier (ns_function_modifier) : 0) \
358 | (!EQ (ns_right_command_modifier, Qleft) && \
359 ((flags & NSRightCommandKeyMask) \
360 == NSRightCommandKeyMask) ? \
361 parse_solitary_modifier (ns_right_command_modifier) : 0) \
362 | ((flags & NSCommandKeyMask) ? \
363 parse_solitary_modifier (ns_command_modifier):0))
364 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
365
366 #define EV_UDMODIFIERS(e) \
367 ((([e type] == NSLeftMouseDown) ? down_modifier : 0) \
368 | (([e type] == NSRightMouseDown) ? down_modifier : 0) \
369 | (([e type] == NSOtherMouseDown) ? down_modifier : 0) \
370 | (([e type] == NSLeftMouseDragged) ? down_modifier : 0) \
371 | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
372 | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
373 | (([e type] == NSLeftMouseUp) ? up_modifier : 0) \
374 | (([e type] == NSRightMouseUp) ? up_modifier : 0) \
375 | (([e type] == NSOtherMouseUp) ? up_modifier : 0))
376
377 #define EV_BUTTON(e) \
378 ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 : \
379 (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
380 [e buttonNumber] - 1)
381
382 /* Convert the time field to a timestamp in milliseconds. */
383 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
384
385 /* This is a piece of code which is common to all the event handling
386 methods. Maybe it should even be a function. */
387 #define EV_TRAILER(e) \
388 { \
389 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
390 EV_TRAILER2 (e); \
391 }
392
393 #define EV_TRAILER2(e) \
394 { \
395 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
396 if (q_event_ptr) \
397 { \
398 Lisp_Object tem = Vinhibit_quit; \
399 Vinhibit_quit = Qt; \
400 n_emacs_events_pending++; \
401 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
402 Vinhibit_quit = tem; \
403 } \
404 else \
405 hold_event (emacs_event); \
406 EVENT_INIT (*emacs_event); \
407 ns_send_appdefined (-1); \
408 }
409
410 /* TODO: get rid of need for these forward declarations */
411 static void ns_condemn_scroll_bars (struct frame *f);
412 static void ns_judge_scroll_bars (struct frame *f);
413 void x_set_frame_alpha (struct frame *f);
414
415
416 /* ==========================================================================
417
418 Utilities
419
420 ========================================================================== */
421
422 void
423 ns_set_represented_filename (NSString* fstr, struct frame *f)
424 {
425 represented_filename = [fstr retain];
426 represented_frame = f;
427 }
428
429 void
430 ns_init_events (struct input_event* ev)
431 {
432 EVENT_INIT (*ev);
433 emacs_event = ev;
434 }
435
436 void
437 ns_finish_events ()
438 {
439 emacs_event = NULL;
440 }
441
442 static void
443 hold_event (struct input_event *event)
444 {
445 if (hold_event_q.nr == hold_event_q.cap)
446 {
447 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
448 else hold_event_q.cap *= 2;
449 hold_event_q.q =
450 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
451 }
452
453 hold_event_q.q[hold_event_q.nr++] = *event;
454 /* Make sure ns_read_socket is called, i.e. we have input. */
455 raise (SIGIO);
456 send_appdefined = YES;
457 }
458
459 static Lisp_Object
460 append2 (Lisp_Object list, Lisp_Object item)
461 /* --------------------------------------------------------------------------
462 Utility to append to a list
463 -------------------------------------------------------------------------- */
464 {
465 return CALLN (Fnconc, list, list1 (item));
466 }
467
468
469 const char *
470 ns_etc_directory (void)
471 /* If running as a self-contained app bundle, return as a string the
472 filename of the etc directory, if present; else nil. */
473 {
474 NSBundle *bundle = [NSBundle mainBundle];
475 NSString *resourceDir = [bundle resourcePath];
476 NSString *resourcePath;
477 NSFileManager *fileManager = [NSFileManager defaultManager];
478 BOOL isDir;
479
480 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
481 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
482 {
483 if (isDir) return [resourcePath UTF8String];
484 }
485 return NULL;
486 }
487
488
489 const char *
490 ns_exec_path (void)
491 /* If running as a self-contained app bundle, return as a path string
492 the filenames of the libexec and bin directories, ie libexec:bin.
493 Otherwise, return nil.
494 Normally, Emacs does not add its own bin/ directory to the PATH.
495 However, a self-contained NS build has a different layout, with
496 bin/ and libexec/ subdirectories in the directory that contains
497 Emacs.app itself.
498 We put libexec first, because init_callproc_1 uses the first
499 element to initialize exec-directory. An alternative would be
500 for init_callproc to check for invocation-directory/libexec.
501 */
502 {
503 NSBundle *bundle = [NSBundle mainBundle];
504 NSString *resourceDir = [bundle resourcePath];
505 NSString *binDir = [bundle bundlePath];
506 NSString *resourcePath, *resourcePaths;
507 NSRange range;
508 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
509 NSFileManager *fileManager = [NSFileManager defaultManager];
510 NSArray *paths;
511 NSEnumerator *pathEnum;
512 BOOL isDir;
513
514 range = [resourceDir rangeOfString: @"Contents"];
515 if (range.location != NSNotFound)
516 {
517 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
518 #ifdef NS_IMPL_COCOA
519 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
520 #endif
521 }
522
523 paths = [binDir stringsByAppendingPaths:
524 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
525 pathEnum = [paths objectEnumerator];
526 resourcePaths = @"";
527
528 while ((resourcePath = [pathEnum nextObject]))
529 {
530 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
531 if (isDir)
532 {
533 if ([resourcePaths length] > 0)
534 resourcePaths
535 = [resourcePaths stringByAppendingString: pathSeparator];
536 resourcePaths
537 = [resourcePaths stringByAppendingString: resourcePath];
538 }
539 }
540 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
541
542 return NULL;
543 }
544
545
546 const char *
547 ns_load_path (void)
548 /* If running as a self-contained app bundle, return as a path string
549 the filenames of the site-lisp and lisp directories.
550 Ie, site-lisp:lisp. Otherwise, return nil. */
551 {
552 NSBundle *bundle = [NSBundle mainBundle];
553 NSString *resourceDir = [bundle resourcePath];
554 NSString *resourcePath, *resourcePaths;
555 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
556 NSFileManager *fileManager = [NSFileManager defaultManager];
557 BOOL isDir;
558 NSArray *paths = [resourceDir stringsByAppendingPaths:
559 [NSArray arrayWithObjects:
560 @"site-lisp", @"lisp", nil]];
561 NSEnumerator *pathEnum = [paths objectEnumerator];
562 resourcePaths = @"";
563
564 /* Hack to skip site-lisp. */
565 if (no_site_lisp) resourcePath = [pathEnum nextObject];
566
567 while ((resourcePath = [pathEnum nextObject]))
568 {
569 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
570 if (isDir)
571 {
572 if ([resourcePaths length] > 0)
573 resourcePaths
574 = [resourcePaths stringByAppendingString: pathSeparator];
575 resourcePaths
576 = [resourcePaths stringByAppendingString: resourcePath];
577 }
578 }
579 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
580
581 return NULL;
582 }
583
584 static void
585 ns_timeout (int usecs)
586 /* --------------------------------------------------------------------------
587 Blocking timer utility used by ns_ring_bell
588 -------------------------------------------------------------------------- */
589 {
590 struct timespec wakeup = timespec_add (current_timespec (),
591 make_timespec (0, usecs * 1000));
592
593 /* Keep waiting until past the time wakeup. */
594 while (1)
595 {
596 struct timespec timeout, now = current_timespec ();
597 if (timespec_cmp (wakeup, now) <= 0)
598 break;
599 timeout = timespec_sub (wakeup, now);
600
601 /* Try to wait that long--but we might wake up sooner. */
602 pselect (0, NULL, NULL, NULL, &timeout, NULL);
603 }
604 }
605
606
607 void
608 ns_release_object (void *obj)
609 /* --------------------------------------------------------------------------
610 Release an object (callable from C)
611 -------------------------------------------------------------------------- */
612 {
613 [(id)obj release];
614 }
615
616
617 void
618 ns_retain_object (void *obj)
619 /* --------------------------------------------------------------------------
620 Retain an object (callable from C)
621 -------------------------------------------------------------------------- */
622 {
623 [(id)obj retain];
624 }
625
626
627 void *
628 ns_alloc_autorelease_pool (void)
629 /* --------------------------------------------------------------------------
630 Allocate a pool for temporary objects (callable from C)
631 -------------------------------------------------------------------------- */
632 {
633 return [[NSAutoreleasePool alloc] init];
634 }
635
636
637 void
638 ns_release_autorelease_pool (void *pool)
639 /* --------------------------------------------------------------------------
640 Free a pool and temporary objects it refers to (callable from C)
641 -------------------------------------------------------------------------- */
642 {
643 ns_release_object (pool);
644 }
645
646
647 /* True, if the menu bar should be hidden. */
648
649 static BOOL
650 ns_menu_bar_should_be_hidden (void)
651 {
652 return !NILP (ns_auto_hide_menu_bar)
653 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
654 }
655
656
657 static CGFloat
658 ns_menu_bar_height (NSScreen *screen)
659 /* The height of the menu bar, if visible. */
660 {
661 // NSTRACE ("ns_menu_bar_height");
662
663 CGFloat res;
664
665 if (ns_menu_bar_should_be_hidden())
666 {
667 res = 0;
668 }
669 else
670 {
671 NSRect screenFrame = [screen frame];
672 NSRect screenVisibleFrame = [screen visibleFrame];
673
674 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
675 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
676 + screenVisibleFrame.size.height);
677
678 res = frameTop - visibleFrameTop;
679
680 }
681
682 // NSTRACE_MSG (NSTRACE_FMT_RETURN "%.0f", res);
683
684 return res;
685 }
686
687
688 /* ==========================================================================
689
690 Focus (clipping) and screen update
691
692 ========================================================================== */
693
694 //
695 // Window constraining
696 // -------------------
697 //
698 // To ensure that the windows are not placed under the menu bar, they
699 // are typically moved by the call-back constrainFrameRect. However,
700 // by overriding it, it's possible to inhibit this, leaving the window
701 // in it's original position.
702 //
703 // It's possible to hide the menu bar. However, technically, it's only
704 // possible to hide it when the application is active. To ensure that
705 // this work properly, the menu bar and window constraining are
706 // deferred until the application becomes active.
707 //
708 // Even though it's not possible to manually move a window above the
709 // top of the screen, it is allowed if it's done programmatically,
710 // when the menu is hidden. This allows the editable area to cover the
711 // full screen height.
712 //
713 // Test cases
714 // ----------
715 //
716 // Use the following extra files:
717 //
718 // init.el:
719 // ;; Hide menu and place frame slightly above the top of the screen.
720 // (setq ns-auto-hide-menu-bar t)
721 // (set-frame-position (selected-frame) 0 -20)
722 //
723 // Test 1:
724 //
725 // emacs -Q -l init.el
726 //
727 // Result: No menu bar, and the title bar should be above the screen.
728 //
729 // Test 2:
730 //
731 // emacs -Q
732 //
733 // Result: Menu bar visible, frame placed immediately below the menu.
734 //
735
736 static NSRect constrain_frame_rect(NSRect frameRect)
737 {
738 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
739 NSTRACE_ARG_RECT (frameRect));
740
741 // --------------------
742 // Collect information about the screen the frame is covering.
743 //
744
745 NSArray *screens = [NSScreen screens];
746 NSUInteger nr_screens = [screens count];
747
748 int i;
749
750 // The height of the menu bar, if present in any screen the frame is
751 // displayed in.
752 int menu_bar_height = 0;
753
754 // A rectangle covering all the screen the frame is displayed in.
755 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
756 for (i = 0; i < nr_screens; ++i )
757 {
758 NSScreen *s = [screens objectAtIndex: i];
759 NSRect scrRect = [s frame];
760
761 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
762 i, NSTRACE_ARG_RECT (scrRect));
763
764 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
765 {
766 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
767
768 menu_bar_height = max(menu_bar_height, ns_menu_bar_height (s));
769 }
770 }
771
772 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
773
774 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
775
776 if (multiscreenRect.size.width == 0
777 || multiscreenRect.size.height == 0)
778 {
779 // Failed to find any monitor, give up.
780 NSTRACE_MSG ("multiscreenRect empty");
781 NSTRACE_RETURN_RECT (frameRect);
782 return frameRect;
783 }
784
785
786 // --------------------
787 // Find a suitable placement.
788 //
789
790 if (ns_menu_bar_should_be_hidden())
791 {
792 // When the menu bar is hidden, the user may place part of the
793 // frame above the top of the screen, for example to hide the
794 // title bar.
795 //
796 // Hence, keep the original position.
797 }
798 else
799 {
800 // Ensure that the frame is below the menu bar, or below the top
801 // of the screen.
802 //
803 // This assume that the menu bar is placed at the top in the
804 // rectangle that covers the monitors. (It doesn't have to be,
805 // but if it's not it's hard to do anything useful.)
806 CGFloat topOfWorkArea = (multiscreenRect.origin.y
807 + multiscreenRect.size.height
808 - menu_bar_height);
809
810 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
811 if (topOfFrame > topOfWorkArea)
812 {
813 frameRect.origin.y -= topOfFrame - topOfWorkArea;
814 NSTRACE_RECT ("After placement adjust", frameRect);
815 }
816 }
817
818 // Include the following section to restrict frame to the screens.
819 // (If so, update it to allow the frame to stretch down below the
820 // screen.)
821 #if 0
822 // --------------------
823 // Ensure frame doesn't stretch below the screens.
824 //
825
826 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
827
828 if (diff > 0)
829 {
830 frameRect.origin.y = multiscreenRect.origin.y;
831 frameRect.size.height -= diff;
832 }
833 #endif
834
835 NSTRACE_RETURN_RECT (frameRect);
836 return frameRect;
837 }
838
839
840 static void
841 ns_constrain_all_frames (void)
842 {
843 Lisp_Object tail, frame;
844
845 NSTRACE ("ns_constrain_all_frames");
846
847 FOR_EACH_FRAME (tail, frame)
848 {
849 struct frame *f = XFRAME (frame);
850 if (FRAME_NS_P (f))
851 {
852 NSView *view = FRAME_NS_VIEW (f);
853
854 [[view window] setFrame:constrain_frame_rect([[view window] frame])
855 display:NO];
856 }
857 }
858 }
859
860
861 /* Show or hide the menu bar, based on user setting. */
862
863 static void
864 ns_update_auto_hide_menu_bar (void)
865 {
866 #ifdef NS_IMPL_COCOA
867 NSTRACE ("ns_update_auto_hide_menu_bar");
868
869 block_input ();
870
871 if (NSApp != nil && [NSApp isActive])
872 {
873 // Note, "setPresentationOptions" triggers an error unless the
874 // application is active.
875 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
876
877 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
878 {
879 NSApplicationPresentationOptions options
880 = NSApplicationPresentationDefault;
881
882 if (menu_bar_should_be_hidden)
883 options |= NSApplicationPresentationAutoHideMenuBar
884 | NSApplicationPresentationAutoHideDock;
885
886 [NSApp setPresentationOptions: options];
887
888 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
889
890 if (!ns_menu_bar_is_hidden)
891 {
892 ns_constrain_all_frames ();
893 }
894 }
895 }
896
897 unblock_input ();
898 #endif
899 }
900
901
902 static void
903 ns_update_begin (struct frame *f)
904 /* --------------------------------------------------------------------------
905 Prepare for a grouped sequence of drawing calls
906 external (RIF) call; whole frame, called before update_window_begin
907 -------------------------------------------------------------------------- */
908 {
909 EmacsView *view = FRAME_NS_VIEW (f);
910 NSTRACE ("ns_update_begin");
911
912 ns_update_auto_hide_menu_bar ();
913
914 #ifdef NS_IMPL_COCOA
915 if ([view isFullscreen] && [view fsIsNative])
916 {
917 // Fix reappearing tool bar in fullscreen for OSX 10.7
918 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
919 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
920 if (! tbar_visible != ! [toolbar isVisible])
921 [toolbar setVisible: tbar_visible];
922 }
923 #endif
924
925 ns_updating_frame = f;
926 [view lockFocus];
927
928 /* drawRect may have been called for say the minibuffer, and then clip path
929 is for the minibuffer. But the display engine may draw more because
930 we have set the frame as garbaged. So reset clip path to the whole
931 view. */
932 #ifdef NS_IMPL_COCOA
933 {
934 NSBezierPath *bp;
935 NSRect r = [view frame];
936 NSRect cr = [[view window] frame];
937 /* If a large frame size is set, r may be larger than the window frame
938 before constrained. In that case don't change the clip path, as we
939 will clear in to the tool bar and title bar. */
940 if (r.size.height
941 + FRAME_NS_TITLEBAR_HEIGHT (f)
942 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
943 {
944 bp = [[NSBezierPath bezierPathWithRect: r] retain];
945 [bp setClip];
946 [bp release];
947 }
948 }
949 #endif
950
951 #ifdef NS_IMPL_GNUSTEP
952 uRect = NSMakeRect (0, 0, 0, 0);
953 #endif
954 }
955
956
957 static void
958 ns_update_window_begin (struct window *w)
959 /* --------------------------------------------------------------------------
960 Prepare for a grouped sequence of drawing calls
961 external (RIF) call; for one window, called after update_begin
962 -------------------------------------------------------------------------- */
963 {
964 struct frame *f = XFRAME (WINDOW_FRAME (w));
965 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
966
967 NSTRACE ("ns_update_window_begin");
968 w->output_cursor = w->cursor;
969
970 block_input ();
971
972 if (f == hlinfo->mouse_face_mouse_frame)
973 {
974 /* Don't do highlighting for mouse motion during the update. */
975 hlinfo->mouse_face_defer = 1;
976
977 /* If the frame needs to be redrawn,
978 simply forget about any prior mouse highlighting. */
979 if (FRAME_GARBAGED_P (f))
980 hlinfo->mouse_face_window = Qnil;
981
982 /* (further code for mouse faces ifdef'd out in other terms elided) */
983 }
984
985 unblock_input ();
986 }
987
988
989 static void
990 ns_update_window_end (struct window *w, bool cursor_on_p,
991 bool mouse_face_overwritten_p)
992 /* --------------------------------------------------------------------------
993 Finished a grouped sequence of drawing calls
994 external (RIF) call; for one window called before update_end
995 -------------------------------------------------------------------------- */
996 {
997 NSTRACE ("update_window_end");
998
999 /* note: this fn is nearly identical in all terms */
1000 if (!w->pseudo_window_p)
1001 {
1002 block_input ();
1003
1004 if (cursor_on_p)
1005 display_and_set_cursor (w, 1,
1006 w->output_cursor.hpos, w->output_cursor.vpos,
1007 w->output_cursor.x, w->output_cursor.y);
1008
1009 if (draw_window_fringes (w, 1))
1010 {
1011 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1012 x_draw_right_divider (w);
1013 else
1014 x_draw_vertical_border (w);
1015 }
1016
1017 unblock_input ();
1018 }
1019
1020 /* If a row with mouse-face was overwritten, arrange for
1021 frame_up_to_date to redisplay the mouse highlight. */
1022 if (mouse_face_overwritten_p)
1023 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1024 }
1025
1026
1027 static void
1028 ns_update_end (struct frame *f)
1029 /* --------------------------------------------------------------------------
1030 Finished a grouped sequence of drawing calls
1031 external (RIF) call; for whole frame, called after update_window_end
1032 -------------------------------------------------------------------------- */
1033 {
1034 EmacsView *view = FRAME_NS_VIEW (f);
1035
1036 NSTRACE ("ns_update_end");
1037
1038 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1039 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1040
1041 block_input ();
1042
1043 [view unlockFocus];
1044 [[view window] flushWindow];
1045
1046 unblock_input ();
1047 ns_updating_frame = NULL;
1048 }
1049
1050 static void
1051 ns_focus (struct frame *f, NSRect *r, int n)
1052 /* --------------------------------------------------------------------------
1053 Internal: Focus on given frame. During small local updates this is used to
1054 draw, however during large updates, ns_update_begin and ns_update_end are
1055 called to wrap the whole thing, in which case these calls are stubbed out.
1056 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1057 the back end won't do this automatically, and will just end up flushing
1058 the entire window.
1059 -------------------------------------------------------------------------- */
1060 {
1061 // NSTRACE ("ns_focus");
1062 /* static int c =0;
1063 fprintf (stderr, "focus: %d", c++);
1064 if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
1065 fprintf (stderr, "\n"); */
1066
1067 if (f != ns_updating_frame)
1068 {
1069 NSView *view = FRAME_NS_VIEW (f);
1070 if (view != focus_view)
1071 {
1072 if (focus_view != NULL)
1073 {
1074 [focus_view unlockFocus];
1075 [[focus_view window] flushWindow];
1076 /*debug_lock--; */
1077 }
1078
1079 if (view)
1080 [view lockFocus];
1081 focus_view = view;
1082 /*if (view) debug_lock++; */
1083 }
1084 }
1085
1086 /* clipping */
1087 if (r)
1088 {
1089 [[NSGraphicsContext currentContext] saveGraphicsState];
1090 if (n == 2)
1091 NSRectClipList (r, 2);
1092 else
1093 NSRectClip (*r);
1094 gsaved = YES;
1095 }
1096 }
1097
1098
1099 static void
1100 ns_unfocus (struct frame *f)
1101 /* --------------------------------------------------------------------------
1102 Internal: Remove focus on given frame
1103 -------------------------------------------------------------------------- */
1104 {
1105 // NSTRACE ("ns_unfocus");
1106
1107 if (gsaved)
1108 {
1109 [[NSGraphicsContext currentContext] restoreGraphicsState];
1110 gsaved = NO;
1111 }
1112
1113 if (f != ns_updating_frame)
1114 {
1115 if (focus_view != NULL)
1116 {
1117 [focus_view unlockFocus];
1118 [[focus_view window] flushWindow];
1119 focus_view = NULL;
1120 /*debug_lock--; */
1121 }
1122 }
1123 }
1124
1125
1126 static void
1127 ns_clip_to_row (struct window *w, struct glyph_row *row,
1128 enum glyph_row_area area, BOOL gc)
1129 /* --------------------------------------------------------------------------
1130 Internal (but parallels other terms): Focus drawing on given row
1131 -------------------------------------------------------------------------- */
1132 {
1133 struct frame *f = XFRAME (WINDOW_FRAME (w));
1134 NSRect clip_rect;
1135 int window_x, window_y, window_width;
1136
1137 window_box (w, area, &window_x, &window_y, &window_width, 0);
1138
1139 clip_rect.origin.x = window_x;
1140 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1141 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1142 clip_rect.size.width = window_width;
1143 clip_rect.size.height = row->visible_height;
1144
1145 ns_focus (f, &clip_rect, 1);
1146 }
1147
1148
1149 static void
1150 ns_ring_bell (struct frame *f)
1151 /* --------------------------------------------------------------------------
1152 "Beep" routine
1153 -------------------------------------------------------------------------- */
1154 {
1155 NSTRACE ("ns_ring_bell");
1156 if (visible_bell)
1157 {
1158 NSAutoreleasePool *pool;
1159 struct frame *frame = SELECTED_FRAME ();
1160 NSView *view;
1161
1162 block_input ();
1163 pool = [[NSAutoreleasePool alloc] init];
1164
1165 view = FRAME_NS_VIEW (frame);
1166 if (view != nil)
1167 {
1168 NSRect r, surr;
1169 NSPoint dim = NSMakePoint (128, 128);
1170
1171 r = [view bounds];
1172 r.origin.x += (r.size.width - dim.x) / 2;
1173 r.origin.y += (r.size.height - dim.y) / 2;
1174 r.size.width = dim.x;
1175 r.size.height = dim.y;
1176 surr = NSInsetRect (r, -2, -2);
1177 ns_focus (frame, &surr, 1);
1178 [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1179 [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1180 (FRAME_DEFAULT_FACE (frame)), frame) set];
1181 NSRectFill (r);
1182 [[view window] flushWindow];
1183 ns_timeout (150000);
1184 [[view window] restoreCachedImage];
1185 [[view window] flushWindow];
1186 ns_unfocus (frame);
1187 }
1188 [pool release];
1189 unblock_input ();
1190 }
1191 else
1192 {
1193 NSBeep ();
1194 }
1195 }
1196
1197 /* ==========================================================================
1198
1199 Frame / window manager related functions
1200
1201 ========================================================================== */
1202
1203
1204 static void
1205 ns_raise_frame (struct frame *f)
1206 /* --------------------------------------------------------------------------
1207 Bring window to foreground and make it active
1208 -------------------------------------------------------------------------- */
1209 {
1210 NSView *view;
1211 check_window_system (f);
1212 view = FRAME_NS_VIEW (f);
1213 block_input ();
1214 if (FRAME_VISIBLE_P (f))
1215 [[view window] makeKeyAndOrderFront: NSApp];
1216 unblock_input ();
1217 }
1218
1219
1220 static void
1221 ns_lower_frame (struct frame *f)
1222 /* --------------------------------------------------------------------------
1223 Send window to back
1224 -------------------------------------------------------------------------- */
1225 {
1226 NSView *view;
1227 check_window_system (f);
1228 view = FRAME_NS_VIEW (f);
1229 block_input ();
1230 [[view window] orderBack: NSApp];
1231 unblock_input ();
1232 }
1233
1234
1235 static void
1236 ns_frame_raise_lower (struct frame *f, bool raise)
1237 /* --------------------------------------------------------------------------
1238 External (hook)
1239 -------------------------------------------------------------------------- */
1240 {
1241 NSTRACE ("ns_frame_raise_lower");
1242
1243 if (raise)
1244 ns_raise_frame (f);
1245 else
1246 ns_lower_frame (f);
1247 }
1248
1249
1250 static void
1251 ns_frame_rehighlight (struct frame *frame)
1252 /* --------------------------------------------------------------------------
1253 External (hook): called on things like window switching within frame
1254 -------------------------------------------------------------------------- */
1255 {
1256 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1257 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1258
1259 NSTRACE ("ns_frame_rehighlight");
1260 if (dpyinfo->x_focus_frame)
1261 {
1262 dpyinfo->x_highlight_frame
1263 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1264 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1265 : dpyinfo->x_focus_frame);
1266 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1267 {
1268 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1269 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1270 }
1271 }
1272 else
1273 dpyinfo->x_highlight_frame = 0;
1274
1275 if (dpyinfo->x_highlight_frame &&
1276 dpyinfo->x_highlight_frame != old_highlight)
1277 {
1278 if (old_highlight)
1279 {
1280 x_update_cursor (old_highlight, 1);
1281 x_set_frame_alpha (old_highlight);
1282 }
1283 if (dpyinfo->x_highlight_frame)
1284 {
1285 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1286 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1287 }
1288 }
1289 }
1290
1291
1292 void
1293 x_make_frame_visible (struct frame *f)
1294 /* --------------------------------------------------------------------------
1295 External: Show the window (X11 semantics)
1296 -------------------------------------------------------------------------- */
1297 {
1298 NSTRACE ("x_make_frame_visible");
1299 /* XXX: at some points in past this was not needed, as the only place that
1300 called this (frame.c:Fraise_frame ()) also called raise_lower;
1301 if this ends up the case again, comment this out again. */
1302 if (!FRAME_VISIBLE_P (f))
1303 {
1304 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1305
1306 SET_FRAME_VISIBLE (f, 1);
1307 ns_raise_frame (f);
1308
1309 /* Making a new frame from a fullscreen frame will make the new frame
1310 fullscreen also. So skip handleFS as this will print an error. */
1311 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1312 && [view isFullscreen])
1313 return;
1314
1315 if (f->want_fullscreen != FULLSCREEN_NONE)
1316 {
1317 block_input ();
1318 [view handleFS];
1319 unblock_input ();
1320 }
1321 }
1322 }
1323
1324
1325 void
1326 x_make_frame_invisible (struct frame *f)
1327 /* --------------------------------------------------------------------------
1328 External: Hide the window (X11 semantics)
1329 -------------------------------------------------------------------------- */
1330 {
1331 NSView *view;
1332 NSTRACE ("x_make_frame_invisible");
1333 check_window_system (f);
1334 view = FRAME_NS_VIEW (f);
1335 [[view window] orderOut: NSApp];
1336 SET_FRAME_VISIBLE (f, 0);
1337 SET_FRAME_ICONIFIED (f, 0);
1338 }
1339
1340
1341 void
1342 x_iconify_frame (struct frame *f)
1343 /* --------------------------------------------------------------------------
1344 External: Iconify window
1345 -------------------------------------------------------------------------- */
1346 {
1347 NSView *view;
1348 struct ns_display_info *dpyinfo;
1349
1350 NSTRACE ("x_iconify_frame");
1351 check_window_system (f);
1352 view = FRAME_NS_VIEW (f);
1353 dpyinfo = FRAME_DISPLAY_INFO (f);
1354
1355 if (dpyinfo->x_highlight_frame == f)
1356 dpyinfo->x_highlight_frame = 0;
1357
1358 if ([[view window] windowNumber] <= 0)
1359 {
1360 /* the window is still deferred. Make it very small, bring it
1361 on screen and order it out. */
1362 NSRect s = { { 100, 100}, {0, 0} };
1363 NSRect t;
1364 t = [[view window] frame];
1365 [[view window] setFrame: s display: NO];
1366 [[view window] orderBack: NSApp];
1367 [[view window] orderOut: NSApp];
1368 [[view window] setFrame: t display: NO];
1369 }
1370 [[view window] miniaturize: NSApp];
1371 }
1372
1373 /* Free X resources of frame F. */
1374
1375 void
1376 x_free_frame_resources (struct frame *f)
1377 {
1378 NSView *view;
1379 struct ns_display_info *dpyinfo;
1380 Mouse_HLInfo *hlinfo;
1381
1382 NSTRACE ("x_free_frame_resources");
1383 check_window_system (f);
1384 view = FRAME_NS_VIEW (f);
1385 dpyinfo = FRAME_DISPLAY_INFO (f);
1386 hlinfo = MOUSE_HL_INFO (f);
1387
1388 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1389
1390 block_input ();
1391
1392 free_frame_menubar (f);
1393 free_frame_faces (f);
1394
1395 if (f == dpyinfo->x_focus_frame)
1396 dpyinfo->x_focus_frame = 0;
1397 if (f == dpyinfo->x_highlight_frame)
1398 dpyinfo->x_highlight_frame = 0;
1399 if (f == hlinfo->mouse_face_mouse_frame)
1400 reset_mouse_highlight (hlinfo);
1401
1402 if (f->output_data.ns->miniimage != nil)
1403 [f->output_data.ns->miniimage release];
1404
1405 [[view window] close];
1406 [view release];
1407
1408 xfree (f->output_data.ns);
1409
1410 unblock_input ();
1411 }
1412
1413 void
1414 x_destroy_window (struct frame *f)
1415 /* --------------------------------------------------------------------------
1416 External: Delete the window
1417 -------------------------------------------------------------------------- */
1418 {
1419 NSTRACE ("x_destroy_window");
1420 check_window_system (f);
1421 x_free_frame_resources (f);
1422 ns_window_num--;
1423 }
1424
1425
1426 void
1427 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1428 /* --------------------------------------------------------------------------
1429 External: Position the window
1430 -------------------------------------------------------------------------- */
1431 {
1432 NSView *view = FRAME_NS_VIEW (f);
1433 NSArray *screens = [NSScreen screens];
1434 NSScreen *fscreen = [screens objectAtIndex: 0];
1435 NSScreen *screen = [[view window] screen];
1436
1437 NSTRACE ("x_set_offset");
1438
1439 block_input ();
1440
1441 f->left_pos = xoff;
1442 f->top_pos = yoff;
1443
1444 if (view != nil && screen && fscreen)
1445 {
1446 f->left_pos = f->size_hint_flags & XNegative
1447 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1448 : f->left_pos;
1449 /* We use visibleFrame here to take menu bar into account.
1450 Ideally we should also adjust left/top with visibleFrame.origin. */
1451
1452 f->top_pos = f->size_hint_flags & YNegative
1453 ? ([screen visibleFrame].size.height + f->top_pos
1454 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1455 - FRAME_TOOLBAR_HEIGHT (f))
1456 : f->top_pos;
1457 #ifdef NS_IMPL_GNUSTEP
1458 if (f->left_pos < 100)
1459 f->left_pos = 100; /* don't overlap menu */
1460 #endif
1461 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1462 menu bar. */
1463 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1464 SCREENMAXBOUND ([fscreen frame].size.height
1465 - NS_TOP_POS (f)));
1466 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1467 [[view window] setFrameTopLeftPoint: pt];
1468 f->size_hint_flags &= ~(XNegative|YNegative);
1469 }
1470
1471 unblock_input ();
1472 }
1473
1474
1475 void
1476 x_set_window_size (struct frame *f,
1477 bool change_gravity,
1478 int width,
1479 int height,
1480 bool pixelwise)
1481 /* --------------------------------------------------------------------------
1482 Adjust window pixel size based on given character grid size
1483 Impl is a bit more complex than other terms, need to do some
1484 internal clipping.
1485 -------------------------------------------------------------------------- */
1486 {
1487 EmacsView *view = FRAME_NS_VIEW (f);
1488 NSWindow *window = [view window];
1489 NSRect wr = [window frame];
1490 int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1491 int pixelwidth, pixelheight;
1492 int rows, cols;
1493 int orig_height = wr.size.height;
1494
1495 NSTRACE ("x_set_window_size");
1496
1497 if (view == nil)
1498 return;
1499
1500 NSTRACE_RECT ("input", wr);
1501
1502 /*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));*/
1503
1504 block_input ();
1505
1506 if (pixelwise)
1507 {
1508 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1509 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1510 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1511 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1512 }
1513 else
1514 {
1515 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1516 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1517 cols = width;
1518 rows = height;
1519 }
1520
1521 /* If we have a toolbar, take its height into account. */
1522 if (tb && ! [view isFullscreen])
1523 {
1524 /* NOTE: previously this would generate wrong result if toolbar not
1525 yet displayed and fixing toolbar_height=32 helped, but
1526 now (200903) seems no longer needed */
1527 FRAME_TOOLBAR_HEIGHT (f) =
1528 NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1529 - FRAME_NS_TITLEBAR_HEIGHT (f);
1530 #if 0
1531 /* Only breaks things here, removed by martin 2015-09-30. */
1532 #ifdef NS_IMPL_GNUSTEP
1533 FRAME_TOOLBAR_HEIGHT (f) -= 3;
1534 #endif
1535 #endif
1536 }
1537 else
1538 FRAME_TOOLBAR_HEIGHT (f) = 0;
1539
1540 wr.size.width = pixelwidth + f->border_width;
1541 wr.size.height = pixelheight;
1542 if (! [view isFullscreen])
1543 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1544 + FRAME_TOOLBAR_HEIGHT (f);
1545
1546 /* Do not try to constrain to this screen. We may have multiple
1547 screens, and want Emacs to span those. Constraining to screen
1548 prevents that, and that is not nice to the user. */
1549 if (f->output_data.ns->zooming)
1550 f->output_data.ns->zooming = 0;
1551 else
1552 wr.origin.y += orig_height - wr.size.height;
1553
1554 frame_size_history_add
1555 (f, Qx_set_window_size_1, width, height,
1556 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1557 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1558 make_number (f->border_width),
1559 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1560 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1561
1562 [view setRows: rows andColumns: cols];
1563 NSTRACE_RECT ("setFrame", wr);
1564 [window setFrame: wr display: YES];
1565
1566 /* This is a trick to compensate for Emacs' managing the scrollbar area
1567 as a fixed number of standard character columns. Instead of leaving
1568 blank space for the extra, we chopped it off above. Now for
1569 left-hand scrollbars, we shift all rendering to the left by the
1570 difference between the real width and Emacs' imagined one. For
1571 right-hand bars, don't worry about it since the extra is never used.
1572 (Obviously doesn't work for vertically split windows tho..) */
1573 {
1574 NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1575 ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1576 - NS_SCROLL_BAR_WIDTH (f), 0)
1577 : NSMakePoint (0, 0);
1578 NSTRACE_RECT ("setFrame", wr);
1579 [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1580 [view setBoundsOrigin: origin];
1581 }
1582
1583 [view updateFrameSize: NO];
1584 unblock_input ();
1585 }
1586
1587
1588 static void
1589 ns_fullscreen_hook (struct frame *f)
1590 {
1591 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1592
1593 NSTRACE ("ns_fullscreen_hook");
1594
1595 if (!FRAME_VISIBLE_P (f))
1596 return;
1597
1598 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1599 {
1600 /* Old style fs don't initiate correctly if created from
1601 init/default-frame alist, so use a timer (not nice...).
1602 */
1603 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1604 selector: @selector (handleFS)
1605 userInfo: nil repeats: NO];
1606 return;
1607 }
1608
1609 block_input ();
1610 [view handleFS];
1611 unblock_input ();
1612 }
1613
1614 /* ==========================================================================
1615
1616 Color management
1617
1618 ========================================================================== */
1619
1620
1621 NSColor *
1622 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1623 {
1624 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1625 if (idx < 1 || idx >= color_table->avail)
1626 return nil;
1627 return color_table->colors[idx];
1628 }
1629
1630
1631 unsigned long
1632 ns_index_color (NSColor *color, struct frame *f)
1633 {
1634 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1635 ptrdiff_t idx;
1636 ptrdiff_t i;
1637
1638 if (!color_table->colors)
1639 {
1640 color_table->size = NS_COLOR_CAPACITY;
1641 color_table->avail = 1; /* skip idx=0 as marker */
1642 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1643 color_table->colors[0] = nil;
1644 color_table->empty_indices = [[NSMutableSet alloc] init];
1645 }
1646
1647 /* Do we already have this color? */
1648 for (i = 1; i < color_table->avail; i++)
1649 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1650 return i;
1651
1652 if ([color_table->empty_indices count] > 0)
1653 {
1654 NSNumber *index = [color_table->empty_indices anyObject];
1655 [color_table->empty_indices removeObject: index];
1656 idx = [index unsignedLongValue];
1657 }
1658 else
1659 {
1660 if (color_table->avail == color_table->size)
1661 color_table->colors =
1662 xpalloc (color_table->colors, &color_table->size, 1,
1663 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1664 idx = color_table->avail++;
1665 }
1666
1667 color_table->colors[idx] = color;
1668 [color retain];
1669 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1670 return idx;
1671 }
1672
1673
1674 void
1675 ns_free_indexed_color (unsigned long idx, struct frame *f)
1676 {
1677 struct ns_color_table *color_table;
1678 NSColor *color;
1679 NSNumber *index;
1680
1681 if (!f)
1682 return;
1683
1684 color_table = FRAME_DISPLAY_INFO (f)->color_table;
1685
1686 if (idx <= 0 || idx >= color_table->size) {
1687 message1 ("ns_free_indexed_color: Color index out of range.\n");
1688 return;
1689 }
1690
1691 index = [NSNumber numberWithUnsignedInt: idx];
1692 if ([color_table->empty_indices containsObject: index]) {
1693 message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1694 return;
1695 }
1696
1697 color = color_table->colors[idx];
1698 [color release];
1699 color_table->colors[idx] = nil;
1700 [color_table->empty_indices addObject: index];
1701 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1702 }
1703
1704
1705 static int
1706 ns_get_color (const char *name, NSColor **col)
1707 /* --------------------------------------------------------------------------
1708 Parse a color name
1709 -------------------------------------------------------------------------- */
1710 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1711 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1712 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1713 {
1714 NSColor *new = nil;
1715 static char hex[20];
1716 int scaling = 0;
1717 float r = -1.0, g, b;
1718 NSString *nsname = [NSString stringWithUTF8String: name];
1719
1720 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1721 block_input ();
1722
1723 if ([nsname isEqualToString: @"ns_selection_bg_color"])
1724 {
1725 #ifdef NS_IMPL_COCOA
1726 NSString *defname = [[NSUserDefaults standardUserDefaults]
1727 stringForKey: @"AppleHighlightColor"];
1728 if (defname != nil)
1729 nsname = defname;
1730 else
1731 #endif
1732 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1733 {
1734 *col = [new colorUsingDefaultColorSpace];
1735 unblock_input ();
1736 return 0;
1737 }
1738 else
1739 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1740
1741 name = [nsname UTF8String];
1742 }
1743 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1744 {
1745 /* NOTE: OSX applications normally don't set foreground selection, but
1746 text may be unreadable if we don't.
1747 */
1748 if ((new = [NSColor selectedTextColor]) != nil)
1749 {
1750 *col = [new colorUsingDefaultColorSpace];
1751 unblock_input ();
1752 return 0;
1753 }
1754
1755 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1756 name = [nsname UTF8String];
1757 }
1758
1759 /* First, check for some sort of numeric specification. */
1760 hex[0] = '\0';
1761
1762 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
1763 {
1764 NSScanner *scanner = [NSScanner scannerWithString: nsname];
1765 [scanner scanFloat: &r];
1766 [scanner scanFloat: &g];
1767 [scanner scanFloat: &b];
1768 }
1769 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
1770 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1771 else if (name[0] == '#') /* An old X11 format; convert to newer */
1772 {
1773 int len = (strlen(name) - 1);
1774 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1775 int i;
1776 scaling = strlen(name+start) / 3;
1777 for (i = 0; i < 3; i++)
1778 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1779 name + start + i * scaling);
1780 hex[3 * (scaling + 1) - 1] = '\0';
1781 }
1782
1783 if (hex[0])
1784 {
1785 int rr, gg, bb;
1786 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1787 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1788 {
1789 r = rr / fscale;
1790 g = gg / fscale;
1791 b = bb / fscale;
1792 }
1793 }
1794
1795 if (r >= 0.0F)
1796 {
1797 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1798 unblock_input ();
1799 return 0;
1800 }
1801
1802 /* Otherwise, color is expected to be from a list */
1803 {
1804 NSEnumerator *lenum, *cenum;
1805 NSString *name;
1806 NSColorList *clist;
1807
1808 #ifdef NS_IMPL_GNUSTEP
1809 /* XXX: who is wrong, the requestor or the implementation? */
1810 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1811 == NSOrderedSame)
1812 nsname = @"highlightColor";
1813 #endif
1814
1815 lenum = [[NSColorList availableColorLists] objectEnumerator];
1816 while ( (clist = [lenum nextObject]) && new == nil)
1817 {
1818 cenum = [[clist allKeys] objectEnumerator];
1819 while ( (name = [cenum nextObject]) && new == nil )
1820 {
1821 if ([name compare: nsname
1822 options: NSCaseInsensitiveSearch] == NSOrderedSame )
1823 new = [clist colorWithKey: name];
1824 }
1825 }
1826 }
1827
1828 if (new)
1829 *col = [new colorUsingDefaultColorSpace];
1830 unblock_input ();
1831 return new ? 0 : 1;
1832 }
1833
1834
1835 int
1836 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1837 /* --------------------------------------------------------------------------
1838 Convert a Lisp string object to a NS color
1839 -------------------------------------------------------------------------- */
1840 {
1841 NSTRACE ("ns_lisp_to_color");
1842 if (STRINGP (color))
1843 return ns_get_color (SSDATA (color), col);
1844 else if (SYMBOLP (color))
1845 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1846 return 1;
1847 }
1848
1849
1850 Lisp_Object
1851 ns_color_to_lisp (NSColor *col)
1852 /* --------------------------------------------------------------------------
1853 Convert a color to a lisp string with the RGB equivalent
1854 -------------------------------------------------------------------------- */
1855 {
1856 EmacsCGFloat red, green, blue, alpha, gray;
1857 char buf[1024];
1858 const char *str;
1859 NSTRACE ("ns_color_to_lisp");
1860
1861 block_input ();
1862 if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1863
1864 if ((str =[[col colorNameComponent] UTF8String]))
1865 {
1866 unblock_input ();
1867 return build_string ((char *)str);
1868 }
1869
1870 [[col colorUsingDefaultColorSpace]
1871 getRed: &red green: &green blue: &blue alpha: &alpha];
1872 if (red == green && red == blue)
1873 {
1874 [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1875 getWhite: &gray alpha: &alpha];
1876 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1877 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1878 unblock_input ();
1879 return build_string (buf);
1880 }
1881
1882 snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1883 lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1884
1885 unblock_input ();
1886 return build_string (buf);
1887 }
1888
1889
1890 void
1891 ns_query_color(void *col, XColor *color_def, int setPixel)
1892 /* --------------------------------------------------------------------------
1893 Get ARGB values out of NSColor col and put them into color_def.
1894 If setPixel, set the pixel to a concatenated version.
1895 and set color_def pixel to the resulting index.
1896 -------------------------------------------------------------------------- */
1897 {
1898 EmacsCGFloat r, g, b, a;
1899
1900 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1901 color_def->red = r * 65535;
1902 color_def->green = g * 65535;
1903 color_def->blue = b * 65535;
1904
1905 if (setPixel == YES)
1906 color_def->pixel
1907 = ARGB_TO_ULONG((int)(a*255),
1908 (int)(r*255), (int)(g*255), (int)(b*255));
1909 }
1910
1911
1912 bool
1913 ns_defined_color (struct frame *f,
1914 const char *name,
1915 XColor *color_def,
1916 bool alloc,
1917 bool makeIndex)
1918 /* --------------------------------------------------------------------------
1919 Return true if named color found, and set color_def rgb accordingly.
1920 If makeIndex and alloc are nonzero put the color in the color_table,
1921 and set color_def pixel to the resulting index.
1922 If makeIndex is zero, set color_def pixel to ARGB.
1923 Return false if not found
1924 -------------------------------------------------------------------------- */
1925 {
1926 NSColor *col;
1927 NSTRACE ("ns_defined_color");
1928
1929 block_input ();
1930 if (ns_get_color (name, &col) != 0) /* Color not found */
1931 {
1932 unblock_input ();
1933 return 0;
1934 }
1935 if (makeIndex && alloc)
1936 color_def->pixel = ns_index_color (col, f);
1937 ns_query_color (col, color_def, !makeIndex);
1938 unblock_input ();
1939 return 1;
1940 }
1941
1942
1943 void
1944 x_set_frame_alpha (struct frame *f)
1945 /* --------------------------------------------------------------------------
1946 change the entire-frame transparency
1947 -------------------------------------------------------------------------- */
1948 {
1949 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1950 double alpha = 1.0;
1951 double alpha_min = 1.0;
1952
1953 if (dpyinfo->x_highlight_frame == f)
1954 alpha = f->alpha[0];
1955 else
1956 alpha = f->alpha[1];
1957
1958 if (FLOATP (Vframe_alpha_lower_limit))
1959 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1960 else if (INTEGERP (Vframe_alpha_lower_limit))
1961 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1962
1963 if (alpha < 0.0)
1964 return;
1965 else if (1.0 < alpha)
1966 alpha = 1.0;
1967 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1968 alpha = alpha_min;
1969
1970 #ifdef NS_IMPL_COCOA
1971 {
1972 EmacsView *view = FRAME_NS_VIEW (f);
1973 [[view window] setAlphaValue: alpha];
1974 }
1975 #endif
1976 }
1977
1978
1979 /* ==========================================================================
1980
1981 Mouse handling
1982
1983 ========================================================================== */
1984
1985
1986 void
1987 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1988 /* --------------------------------------------------------------------------
1989 Programmatically reposition mouse pointer in pixel coordinates
1990 -------------------------------------------------------------------------- */
1991 {
1992 NSTRACE ("frame_set_mouse_pixel_position");
1993 ns_raise_frame (f);
1994 #if 0
1995 /* FIXME: this does not work, and what about GNUstep? */
1996 #ifdef NS_IMPL_COCOA
1997 [FRAME_NS_VIEW (f) lockFocus];
1998 PSsetmouse ((float)pix_x, (float)pix_y);
1999 [FRAME_NS_VIEW (f) unlockFocus];
2000 #endif
2001 #endif
2002 }
2003
2004 static int
2005 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2006 /* ------------------------------------------------------------------------
2007 Called by EmacsView on mouseMovement events. Passes on
2008 to emacs mainstream code if we moved off of a rect of interest
2009 known as last_mouse_glyph.
2010 ------------------------------------------------------------------------ */
2011 {
2012 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2013 NSRect *r;
2014
2015 // NSTRACE ("note_mouse_movement");
2016
2017 dpyinfo->last_mouse_motion_frame = frame;
2018 r = &dpyinfo->last_mouse_glyph;
2019
2020 /* Note, this doesn't get called for enter/leave, since we don't have a
2021 position. Those are taken care of in the corresponding NSView methods. */
2022
2023 /* has movement gone beyond last rect we were tracking? */
2024 if (x < r->origin.x || x >= r->origin.x + r->size.width
2025 || y < r->origin.y || y >= r->origin.y + r->size.height)
2026 {
2027 ns_update_begin (frame);
2028 frame->mouse_moved = 1;
2029 note_mouse_highlight (frame, x, y);
2030 remember_mouse_glyph (frame, x, y, r);
2031 ns_update_end (frame);
2032 return 1;
2033 }
2034
2035 return 0;
2036 }
2037
2038
2039 static void
2040 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2041 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2042 Time *time)
2043 /* --------------------------------------------------------------------------
2044 External (hook): inform emacs about mouse position and hit parts.
2045 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2046 x & y should be position in the scrollbar (the whole bar, not the handle)
2047 and length of scrollbar respectively
2048 -------------------------------------------------------------------------- */
2049 {
2050 id view;
2051 NSPoint position;
2052 Lisp_Object frame, tail;
2053 struct frame *f;
2054 struct ns_display_info *dpyinfo;
2055
2056 NSTRACE ("ns_mouse_position");
2057
2058 if (*fp == NULL)
2059 {
2060 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2061 return;
2062 }
2063
2064 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2065
2066 block_input ();
2067
2068 /* Clear the mouse-moved flag for every frame on this display. */
2069 FOR_EACH_FRAME (tail, frame)
2070 if (FRAME_NS_P (XFRAME (frame))
2071 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2072 XFRAME (frame)->mouse_moved = 0;
2073
2074 dpyinfo->last_mouse_scroll_bar = nil;
2075 if (dpyinfo->last_mouse_frame
2076 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2077 f = dpyinfo->last_mouse_frame;
2078 else
2079 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2080
2081 if (f && FRAME_NS_P (f))
2082 {
2083 view = FRAME_NS_VIEW (*fp);
2084
2085 position = [[view window] mouseLocationOutsideOfEventStream];
2086 position = [view convertPoint: position fromView: nil];
2087 remember_mouse_glyph (f, position.x, position.y,
2088 &dpyinfo->last_mouse_glyph);
2089 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
2090
2091 if (bar_window) *bar_window = Qnil;
2092 if (part) *part = scroll_bar_above_handle;
2093
2094 if (x) XSETINT (*x, lrint (position.x));
2095 if (y) XSETINT (*y, lrint (position.y));
2096 if (time)
2097 *time = dpyinfo->last_mouse_movement_time;
2098 *fp = f;
2099 }
2100
2101 unblock_input ();
2102 }
2103
2104
2105 static void
2106 ns_frame_up_to_date (struct frame *f)
2107 /* --------------------------------------------------------------------------
2108 External (hook): Fix up mouse highlighting right after a full update.
2109 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2110 -------------------------------------------------------------------------- */
2111 {
2112 NSTRACE ("ns_frame_up_to_date");
2113
2114 if (FRAME_NS_P (f))
2115 {
2116 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2117 if (f == hlinfo->mouse_face_mouse_frame)
2118 {
2119 block_input ();
2120 ns_update_begin(f);
2121 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2122 hlinfo->mouse_face_mouse_x,
2123 hlinfo->mouse_face_mouse_y);
2124 ns_update_end(f);
2125 unblock_input ();
2126 }
2127 }
2128 }
2129
2130
2131 static void
2132 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2133 /* --------------------------------------------------------------------------
2134 External (RIF): set frame mouse pointer type.
2135 -------------------------------------------------------------------------- */
2136 {
2137 NSTRACE ("ns_define_frame_cursor");
2138 if (FRAME_POINTER_TYPE (f) != cursor)
2139 {
2140 EmacsView *view = FRAME_NS_VIEW (f);
2141 FRAME_POINTER_TYPE (f) = cursor;
2142 [[view window] invalidateCursorRectsForView: view];
2143 /* Redisplay assumes this function also draws the changed frame
2144 cursor, but this function doesn't, so do it explicitly. */
2145 x_update_cursor (f, 1);
2146 }
2147 }
2148
2149
2150
2151 /* ==========================================================================
2152
2153 Keyboard handling
2154
2155 ========================================================================== */
2156
2157
2158 static unsigned
2159 ns_convert_key (unsigned code)
2160 /* --------------------------------------------------------------------------
2161 Internal call used by NSView-keyDown.
2162 -------------------------------------------------------------------------- */
2163 {
2164 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2165 unsigned keysym;
2166 /* An array would be faster, but less easy to read. */
2167 for (keysym = 0; keysym < last_keysym; keysym += 2)
2168 if (code == convert_ns_to_X_keysym[keysym])
2169 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2170 return 0;
2171 /* if decide to use keyCode and Carbon table, use this line:
2172 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2173 }
2174
2175
2176 char *
2177 x_get_keysym_name (int keysym)
2178 /* --------------------------------------------------------------------------
2179 Called by keyboard.c. Not sure if the return val is important, except
2180 that it be unique.
2181 -------------------------------------------------------------------------- */
2182 {
2183 static char value[16];
2184 NSTRACE ("x_get_keysym_name");
2185 sprintf (value, "%d", keysym);
2186 return value;
2187 }
2188
2189
2190
2191 /* ==========================================================================
2192
2193 Block drawing operations
2194
2195 ========================================================================== */
2196
2197
2198 static void
2199 ns_redraw_scroll_bars (struct frame *f)
2200 {
2201 int i;
2202 id view;
2203 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2204 NSTRACE ("ns_redraw_scroll_bars");
2205 for (i =[subviews count]-1; i >= 0; i--)
2206 {
2207 view = [subviews objectAtIndex: i];
2208 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2209 [view display];
2210 }
2211 }
2212
2213
2214 void
2215 ns_clear_frame (struct frame *f)
2216 /* --------------------------------------------------------------------------
2217 External (hook): Erase the entire frame
2218 -------------------------------------------------------------------------- */
2219 {
2220 NSView *view = FRAME_NS_VIEW (f);
2221 NSRect r;
2222
2223 NSTRACE ("ns_clear_frame");
2224
2225 /* comes on initial frame because we have
2226 after-make-frame-functions = select-frame */
2227 if (!FRAME_DEFAULT_FACE (f))
2228 return;
2229
2230 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2231
2232 r = [view bounds];
2233
2234 block_input ();
2235 ns_focus (f, &r, 1);
2236 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2237 NSRectFill (r);
2238 ns_unfocus (f);
2239
2240 /* as of 2006/11 or so this is now needed */
2241 ns_redraw_scroll_bars (f);
2242 unblock_input ();
2243 }
2244
2245
2246 static void
2247 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2248 /* --------------------------------------------------------------------------
2249 External (RIF): Clear section of frame
2250 -------------------------------------------------------------------------- */
2251 {
2252 NSRect r = NSMakeRect (x, y, width, height);
2253 NSView *view = FRAME_NS_VIEW (f);
2254 struct face *face = FRAME_DEFAULT_FACE (f);
2255
2256 if (!view || !face)
2257 return;
2258
2259 NSTRACE ("ns_clear_frame_area");
2260
2261 r = NSIntersectionRect (r, [view frame]);
2262 ns_focus (f, &r, 1);
2263 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2264
2265 NSRectFill (r);
2266
2267 ns_unfocus (f);
2268 return;
2269 }
2270
2271 static void
2272 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2273 {
2274 if (FRAME_NS_VIEW (f))
2275 {
2276 ns_focus (f, &dest, 1);
2277 [FRAME_NS_VIEW (f) scrollRect: src
2278 by: NSMakeSize (dest.origin.x - src.origin.x,
2279 dest.origin.y - src.origin.y)];
2280 ns_unfocus (f);
2281 }
2282 }
2283
2284 static void
2285 ns_scroll_run (struct window *w, struct run *run)
2286 /* --------------------------------------------------------------------------
2287 External (RIF): Insert or delete n lines at line vpos
2288 -------------------------------------------------------------------------- */
2289 {
2290 struct frame *f = XFRAME (w->frame);
2291 int x, y, width, height, from_y, to_y, bottom_y;
2292
2293 NSTRACE ("ns_scroll_run");
2294
2295 /* begin copy from other terms */
2296 /* Get frame-relative bounding box of the text display area of W,
2297 without mode lines. Include in this box the left and right
2298 fringe of W. */
2299 window_box (w, ANY_AREA, &x, &y, &width, &height);
2300
2301 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2302 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2303 bottom_y = y + height;
2304
2305 if (to_y < from_y)
2306 {
2307 /* Scrolling up. Make sure we don't copy part of the mode
2308 line at the bottom. */
2309 if (from_y + run->height > bottom_y)
2310 height = bottom_y - from_y;
2311 else
2312 height = run->height;
2313 }
2314 else
2315 {
2316 /* Scrolling down. Make sure we don't copy over the mode line.
2317 at the bottom. */
2318 if (to_y + run->height > bottom_y)
2319 height = bottom_y - to_y;
2320 else
2321 height = run->height;
2322 }
2323 /* end copy from other terms */
2324
2325 if (height == 0)
2326 return;
2327
2328 block_input ();
2329
2330 x_clear_cursor (w);
2331
2332 {
2333 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2334 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2335
2336 ns_copy_bits (f, srcRect , dstRect);
2337 }
2338
2339 unblock_input ();
2340 }
2341
2342
2343 static void
2344 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2345 /* --------------------------------------------------------------------------
2346 External (RIF): preparatory to fringe update after text was updated
2347 -------------------------------------------------------------------------- */
2348 {
2349 struct frame *f;
2350 int width, height;
2351
2352 NSTRACE ("ns_after_update_window_line");
2353
2354 /* begin copy from other terms */
2355 eassert (w);
2356
2357 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2358 desired_row->redraw_fringe_bitmaps_p = 1;
2359
2360 /* When a window has disappeared, make sure that no rest of
2361 full-width rows stays visible in the internal border. */
2362 if (windows_or_buffers_changed
2363 && desired_row->full_width_p
2364 && (f = XFRAME (w->frame),
2365 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2366 width != 0)
2367 && (height = desired_row->visible_height,
2368 height > 0))
2369 {
2370 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2371
2372 block_input ();
2373 ns_clear_frame_area (f, 0, y, width, height);
2374 ns_clear_frame_area (f,
2375 FRAME_PIXEL_WIDTH (f) - width,
2376 y, width, height);
2377 unblock_input ();
2378 }
2379 }
2380
2381
2382 static void
2383 ns_shift_glyphs_for_insert (struct frame *f,
2384 int x, int y, int width, int height,
2385 int shift_by)
2386 /* --------------------------------------------------------------------------
2387 External (RIF): copy an area horizontally, don't worry about clearing src
2388 -------------------------------------------------------------------------- */
2389 {
2390 NSRect srcRect = NSMakeRect (x, y, width, height);
2391 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2392
2393 NSTRACE ("ns_shift_glyphs_for_insert");
2394
2395 ns_copy_bits (f, srcRect, dstRect);
2396 }
2397
2398
2399
2400 /* ==========================================================================
2401
2402 Character encoding and metrics
2403
2404 ========================================================================== */
2405
2406
2407 static void
2408 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2409 /* --------------------------------------------------------------------------
2410 External (RIF); compute left/right overhang of whole string and set in s
2411 -------------------------------------------------------------------------- */
2412 {
2413 struct font *font = s->font;
2414
2415 if (s->char2b)
2416 {
2417 struct font_metrics metrics;
2418 unsigned int codes[2];
2419 codes[0] = *(s->char2b);
2420 codes[1] = *(s->char2b + s->nchars - 1);
2421
2422 font->driver->text_extents (font, codes, 2, &metrics);
2423 s->left_overhang = -metrics.lbearing;
2424 s->right_overhang
2425 = metrics.rbearing > metrics.width
2426 ? metrics.rbearing - metrics.width : 0;
2427 }
2428 else
2429 {
2430 s->left_overhang = 0;
2431 if (EQ (font->driver->type, Qns))
2432 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2433 FONT_HEIGHT (font) * 0.2 : 0;
2434 else
2435 s->right_overhang = 0;
2436 }
2437 }
2438
2439
2440
2441 /* ==========================================================================
2442
2443 Fringe and cursor drawing
2444
2445 ========================================================================== */
2446
2447
2448 extern int max_used_fringe_bitmap;
2449 static void
2450 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2451 struct draw_fringe_bitmap_params *p)
2452 /* --------------------------------------------------------------------------
2453 External (RIF); fringe-related
2454 -------------------------------------------------------------------------- */
2455 {
2456 struct frame *f = XFRAME (WINDOW_FRAME (w));
2457 struct face *face = p->face;
2458 static EmacsImage **bimgs = NULL;
2459 static int nBimgs = 0;
2460
2461 /* grow bimgs if needed */
2462 if (nBimgs < max_used_fringe_bitmap)
2463 {
2464 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2465 memset (bimgs + nBimgs, 0,
2466 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2467 nBimgs = max_used_fringe_bitmap;
2468 }
2469
2470 /* Must clip because of partially visible lines. */
2471 ns_clip_to_row (w, row, ANY_AREA, YES);
2472
2473 if (!p->overlay_p)
2474 {
2475 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2476
2477 if (bx >= 0 && nx > 0)
2478 {
2479 NSRect r = NSMakeRect (bx, by, nx, ny);
2480 NSRectClip (r);
2481 [ns_lookup_indexed_color (face->background, f) set];
2482 NSRectFill (r);
2483 }
2484 }
2485
2486 if (p->which)
2487 {
2488 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2489 EmacsImage *img = bimgs[p->which - 1];
2490
2491 if (!img)
2492 {
2493 unsigned short *bits = p->bits + p->dh;
2494 int len = p->h;
2495 int i;
2496 unsigned char *cbits = xmalloc (len);
2497
2498 for (i = 0; i < len; i++)
2499 cbits[i] = ~(bits[i] & 0xff);
2500 img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2501 fg: 0 bg: 0];
2502 bimgs[p->which - 1] = img;
2503 xfree (cbits);
2504 }
2505
2506 NSRectClip (r);
2507 /* Since we composite the bitmap instead of just blitting it, we need
2508 to erase the whole background. */
2509 [ns_lookup_indexed_color(face->background, f) set];
2510 NSRectFill (r);
2511
2512 {
2513 NSColor *bm_color;
2514 if (!p->cursor_p)
2515 bm_color = ns_lookup_indexed_color(face->foreground, f);
2516 else if (p->overlay_p)
2517 bm_color = ns_lookup_indexed_color(face->background, f);
2518 else
2519 bm_color = f->output_data.ns->cursor_color;
2520 [img setXBMColor: bm_color];
2521 }
2522
2523 #ifdef NS_IMPL_COCOA
2524 [img drawInRect: r
2525 fromRect: NSZeroRect
2526 operation: NSCompositeSourceOver
2527 fraction: 1.0
2528 respectFlipped: YES
2529 hints: nil];
2530 #else
2531 {
2532 NSPoint pt = r.origin;
2533 pt.y += p->h;
2534 [img compositeToPoint: pt operation: NSCompositeSourceOver];
2535 }
2536 #endif
2537 }
2538 ns_unfocus (f);
2539 }
2540
2541
2542 static void
2543 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2544 int x, int y, enum text_cursor_kinds cursor_type,
2545 int cursor_width, bool on_p, bool active_p)
2546 /* --------------------------------------------------------------------------
2547 External call (RIF): draw cursor.
2548 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2549 -------------------------------------------------------------------------- */
2550 {
2551 NSRect r, s;
2552 int fx, fy, h, cursor_height;
2553 struct frame *f = WINDOW_XFRAME (w);
2554 struct glyph *phys_cursor_glyph;
2555 struct glyph *cursor_glyph;
2556 struct face *face;
2557 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2558
2559 /* If cursor is out of bounds, don't draw garbage. This can happen
2560 in mini-buffer windows when switching between echo area glyphs
2561 and mini-buffer. */
2562
2563 NSTRACE ("dumpcursor");
2564
2565 if (!on_p)
2566 return;
2567
2568 w->phys_cursor_type = cursor_type;
2569 w->phys_cursor_on_p = on_p;
2570
2571 if (cursor_type == NO_CURSOR)
2572 {
2573 w->phys_cursor_width = 0;
2574 return;
2575 }
2576
2577 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2578 {
2579 if (glyph_row->exact_window_width_line_p
2580 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2581 {
2582 glyph_row->cursor_in_fringe_p = 1;
2583 draw_fringe_bitmap (w, glyph_row, 0);
2584 }
2585 return;
2586 }
2587
2588 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2589 (other terminals do it the other way round). We must set
2590 w->phys_cursor_width to the cursor width. For bar cursors, that
2591 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2592 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2593
2594 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2595 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2596 if (cursor_type == BAR_CURSOR)
2597 {
2598 if (cursor_width < 1)
2599 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2600 w->phys_cursor_width = cursor_width;
2601 }
2602 /* If we have an HBAR, "cursor_width" MAY specify height. */
2603 else if (cursor_type == HBAR_CURSOR)
2604 {
2605 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2606 if (cursor_height > glyph_row->height)
2607 cursor_height = glyph_row->height;
2608 if (h > cursor_height) // Cursor smaller than line height, move down
2609 fy += h - cursor_height;
2610 h = cursor_height;
2611 }
2612
2613 r.origin.x = fx, r.origin.y = fy;
2614 r.size.height = h;
2615 r.size.width = w->phys_cursor_width;
2616
2617 /* TODO: only needed in rare cases with last-resort font in HELLO..
2618 should we do this more efficiently? */
2619 ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2620
2621
2622 face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2623 if (face && NS_FACE_BACKGROUND (face)
2624 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2625 {
2626 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2627 hollow_color = FRAME_CURSOR_COLOR (f);
2628 }
2629 else
2630 [FRAME_CURSOR_COLOR (f) set];
2631
2632 #ifdef NS_IMPL_COCOA
2633 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2634 atomic. Cleaner ways of doing this should be investigated.
2635 One way would be to set a global variable DRAWING_CURSOR
2636 when making the call to draw_phys..(), don't focus in that
2637 case, then move the ns_unfocus() here after that call. */
2638 NSDisableScreenUpdates ();
2639 #endif
2640
2641 switch (cursor_type)
2642 {
2643 case DEFAULT_CURSOR:
2644 case NO_CURSOR:
2645 break;
2646 case FILLED_BOX_CURSOR:
2647 NSRectFill (r);
2648 break;
2649 case HOLLOW_BOX_CURSOR:
2650 NSRectFill (r);
2651 [hollow_color set];
2652 NSRectFill (NSInsetRect (r, 1, 1));
2653 [FRAME_CURSOR_COLOR (f) set];
2654 break;
2655 case HBAR_CURSOR:
2656 NSRectFill (r);
2657 break;
2658 case BAR_CURSOR:
2659 s = r;
2660 /* If the character under cursor is R2L, draw the bar cursor
2661 on the right of its glyph, rather than on the left. */
2662 cursor_glyph = get_phys_cursor_glyph (w);
2663 if ((cursor_glyph->resolved_level & 1) != 0)
2664 s.origin.x += cursor_glyph->pixel_width - s.size.width;
2665
2666 NSRectFill (s);
2667 break;
2668 }
2669 ns_unfocus (f);
2670
2671 /* draw the character under the cursor */
2672 if (cursor_type != NO_CURSOR)
2673 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2674
2675 #ifdef NS_IMPL_COCOA
2676 NSEnableScreenUpdates ();
2677 #endif
2678
2679 }
2680
2681
2682 static void
2683 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2684 /* --------------------------------------------------------------------------
2685 External (RIF): Draw a vertical line.
2686 -------------------------------------------------------------------------- */
2687 {
2688 struct frame *f = XFRAME (WINDOW_FRAME (w));
2689 struct face *face;
2690 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2691
2692 NSTRACE ("ns_draw_vertical_window_border");
2693
2694 face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2695 if (face)
2696 [ns_lookup_indexed_color(face->foreground, f) set];
2697
2698 ns_focus (f, &r, 1);
2699 NSRectFill(r);
2700 ns_unfocus (f);
2701 }
2702
2703
2704 static void
2705 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2706 /* --------------------------------------------------------------------------
2707 External (RIF): Draw a window divider.
2708 -------------------------------------------------------------------------- */
2709 {
2710 struct frame *f = XFRAME (WINDOW_FRAME (w));
2711 struct face *face;
2712 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2713
2714 NSTRACE ("ns_draw_window_divider");
2715
2716 face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2717 if (face)
2718 [ns_lookup_indexed_color(face->foreground, f) set];
2719
2720 ns_focus (f, &r, 1);
2721 NSRectFill(r);
2722 ns_unfocus (f);
2723 }
2724
2725 static void
2726 ns_show_hourglass (struct frame *f)
2727 {
2728 /* TODO: add NSProgressIndicator to all frames. */
2729 }
2730
2731 static void
2732 ns_hide_hourglass (struct frame *f)
2733 {
2734 /* TODO: remove NSProgressIndicator from all frames. */
2735 }
2736
2737 /* ==========================================================================
2738
2739 Glyph drawing operations
2740
2741 ========================================================================== */
2742
2743 static int
2744 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2745 /* --------------------------------------------------------------------------
2746 Wrapper utility to account for internal border width on full-width lines,
2747 and allow top full-width rows to hit the frame top. nr should be pointer
2748 to two successive NSRects. Number of rects actually used is returned.
2749 -------------------------------------------------------------------------- */
2750 {
2751 int n = get_glyph_string_clip_rects (s, nr, 2);
2752 return n;
2753 }
2754
2755 /* --------------------------------------------------------------------
2756 Draw a wavy line under glyph string s. The wave fills wave_height
2757 pixels from y.
2758
2759 x wave_length = 2
2760 --
2761 y * * * * *
2762 |* * * * * * * * *
2763 wave_height = 3 | * * * *
2764 --------------------------------------------------------------------- */
2765
2766 static void
2767 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2768 {
2769 int wave_height = 3, wave_length = 2;
2770 int y, dx, dy, odd, xmax;
2771 NSPoint a, b;
2772 NSRect waveClip;
2773
2774 dx = wave_length;
2775 dy = wave_height - 1;
2776 y = s->ybase - wave_height + 3;
2777 xmax = x + width;
2778
2779 /* Find and set clipping rectangle */
2780 waveClip = NSMakeRect (x, y, width, wave_height);
2781 [[NSGraphicsContext currentContext] saveGraphicsState];
2782 NSRectClip (waveClip);
2783
2784 /* Draw the waves */
2785 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2786 b.x = a.x + dx;
2787 odd = (int)(a.x/dx) % 2;
2788 a.y = b.y = y + 0.5;
2789
2790 if (odd)
2791 a.y += dy;
2792 else
2793 b.y += dy;
2794
2795 while (a.x <= xmax)
2796 {
2797 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2798 a.x = b.x, a.y = b.y;
2799 b.x += dx, b.y = y + 0.5 + odd*dy;
2800 odd = !odd;
2801 }
2802
2803 /* Restore previous clipping rectangle(s) */
2804 [[NSGraphicsContext currentContext] restoreGraphicsState];
2805 }
2806
2807
2808
2809 void
2810 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2811 NSColor *defaultCol, CGFloat width, CGFloat x)
2812 /* --------------------------------------------------------------------------
2813 Draw underline, overline, and strike-through on glyph string s.
2814 -------------------------------------------------------------------------- */
2815 {
2816 if (s->for_overlaps)
2817 return;
2818
2819 /* Do underline. */
2820 if (face->underline_p)
2821 {
2822 if (s->face->underline_type == FACE_UNDER_WAVE)
2823 {
2824 if (face->underline_defaulted_p)
2825 [defaultCol set];
2826 else
2827 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2828
2829 ns_draw_underwave (s, width, x);
2830 }
2831 else if (s->face->underline_type == FACE_UNDER_LINE)
2832 {
2833
2834 NSRect r;
2835 unsigned long thickness, position;
2836
2837 /* If the prev was underlined, match its appearance. */
2838 if (s->prev && s->prev->face->underline_p
2839 && s->prev->face->underline_type == FACE_UNDER_LINE
2840 && s->prev->underline_thickness > 0)
2841 {
2842 thickness = s->prev->underline_thickness;
2843 position = s->prev->underline_position;
2844 }
2845 else
2846 {
2847 struct font *font;
2848 unsigned long descent;
2849
2850 font=s->font;
2851 descent = s->y + s->height - s->ybase;
2852
2853 /* Use underline thickness of font, defaulting to 1. */
2854 thickness = (font && font->underline_thickness > 0)
2855 ? font->underline_thickness : 1;
2856
2857 /* Determine the offset of underlining from the baseline. */
2858 if (x_underline_at_descent_line)
2859 position = descent - thickness;
2860 else if (x_use_underline_position_properties
2861 && font && font->underline_position >= 0)
2862 position = font->underline_position;
2863 else if (font)
2864 position = lround (font->descent / 2);
2865 else
2866 position = underline_minimum_offset;
2867
2868 position = max (position, underline_minimum_offset);
2869
2870 /* Ensure underlining is not cropped. */
2871 if (descent <= position)
2872 {
2873 position = descent - 1;
2874 thickness = 1;
2875 }
2876 else if (descent < position + thickness)
2877 thickness = 1;
2878 }
2879
2880 s->underline_thickness = thickness;
2881 s->underline_position = position;
2882
2883 r = NSMakeRect (x, s->ybase + position, width, thickness);
2884
2885 if (face->underline_defaulted_p)
2886 [defaultCol set];
2887 else
2888 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2889 NSRectFill (r);
2890 }
2891 }
2892 /* Do overline. We follow other terms in using a thickness of 1
2893 and ignoring overline_margin. */
2894 if (face->overline_p)
2895 {
2896 NSRect r;
2897 r = NSMakeRect (x, s->y, width, 1);
2898
2899 if (face->overline_color_defaulted_p)
2900 [defaultCol set];
2901 else
2902 [ns_lookup_indexed_color (face->overline_color, s->f) set];
2903 NSRectFill (r);
2904 }
2905
2906 /* Do strike-through. We follow other terms for thickness and
2907 vertical position.*/
2908 if (face->strike_through_p)
2909 {
2910 NSRect r;
2911 unsigned long dy;
2912
2913 dy = lrint ((s->height - 1) / 2);
2914 r = NSMakeRect (x, s->y + dy, width, 1);
2915
2916 if (face->strike_through_color_defaulted_p)
2917 [defaultCol set];
2918 else
2919 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2920 NSRectFill (r);
2921 }
2922 }
2923
2924 static void
2925 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2926 char left_p, char right_p)
2927 /* --------------------------------------------------------------------------
2928 Draw an unfilled rect inside r, optionally leaving left and/or right open.
2929 Note we can't just use an NSDrawRect command, because of the possibility
2930 of some sides not being drawn, and because the rect will be filled.
2931 -------------------------------------------------------------------------- */
2932 {
2933 NSRect s = r;
2934 [col set];
2935
2936 /* top, bottom */
2937 s.size.height = thickness;
2938 NSRectFill (s);
2939 s.origin.y += r.size.height - thickness;
2940 NSRectFill (s);
2941
2942 s.size.height = r.size.height;
2943 s.origin.y = r.origin.y;
2944
2945 /* left, right (optional) */
2946 s.size.width = thickness;
2947 if (left_p)
2948 NSRectFill (s);
2949 if (right_p)
2950 {
2951 s.origin.x += r.size.width - thickness;
2952 NSRectFill (s);
2953 }
2954 }
2955
2956
2957 static void
2958 ns_draw_relief (NSRect r, int thickness, char raised_p,
2959 char top_p, char bottom_p, char left_p, char right_p,
2960 struct glyph_string *s)
2961 /* --------------------------------------------------------------------------
2962 Draw a relief rect inside r, optionally leaving some sides open.
2963 Note we can't just use an NSDrawBezel command, because of the possibility
2964 of some sides not being drawn, and because the rect will be filled.
2965 -------------------------------------------------------------------------- */
2966 {
2967 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2968 NSColor *newBaseCol = nil;
2969 NSRect sr = r;
2970
2971 NSTRACE ("ns_draw_relief");
2972
2973 /* set up colors */
2974
2975 if (s->face->use_box_color_for_shadows_p)
2976 {
2977 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2978 }
2979 /* else if (s->first_glyph->type == IMAGE_GLYPH
2980 && s->img->pixmap
2981 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2982 {
2983 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
2984 } */
2985 else
2986 {
2987 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2988 }
2989
2990 if (newBaseCol == nil)
2991 newBaseCol = [NSColor grayColor];
2992
2993 if (newBaseCol != baseCol) /* TODO: better check */
2994 {
2995 [baseCol release];
2996 baseCol = [newBaseCol retain];
2997 [lightCol release];
2998 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2999 [darkCol release];
3000 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3001 }
3002
3003 [(raised_p ? lightCol : darkCol) set];
3004
3005 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3006
3007 /* top */
3008 sr.size.height = thickness;
3009 if (top_p) NSRectFill (sr);
3010
3011 /* left */
3012 sr.size.height = r.size.height;
3013 sr.size.width = thickness;
3014 if (left_p) NSRectFill (sr);
3015
3016 [(raised_p ? darkCol : lightCol) set];
3017
3018 /* bottom */
3019 sr.size.width = r.size.width;
3020 sr.size.height = thickness;
3021 sr.origin.y += r.size.height - thickness;
3022 if (bottom_p) NSRectFill (sr);
3023
3024 /* right */
3025 sr.size.height = r.size.height;
3026 sr.origin.y = r.origin.y;
3027 sr.size.width = thickness;
3028 sr.origin.x += r.size.width - thickness;
3029 if (right_p) NSRectFill (sr);
3030 }
3031
3032
3033 static void
3034 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3035 /* --------------------------------------------------------------------------
3036 Function modeled after x_draw_glyph_string_box ().
3037 Sets up parameters for drawing.
3038 -------------------------------------------------------------------------- */
3039 {
3040 int right_x, last_x;
3041 char left_p, right_p;
3042 struct glyph *last_glyph;
3043 NSRect r;
3044 int thickness;
3045 struct face *face;
3046
3047 if (s->hl == DRAW_MOUSE_FACE)
3048 {
3049 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3050 if (!face)
3051 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3052 }
3053 else
3054 face = s->face;
3055
3056 thickness = face->box_line_width;
3057
3058 NSTRACE ("ns_dumpglyphs_box_or_relief");
3059
3060 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3061 ? WINDOW_RIGHT_EDGE_X (s->w)
3062 : window_box_right (s->w, s->area));
3063 last_glyph = (s->cmp || s->img
3064 ? s->first_glyph : s->first_glyph + s->nchars-1);
3065
3066 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3067 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3068
3069 left_p = (s->first_glyph->left_box_line_p
3070 || (s->hl == DRAW_MOUSE_FACE
3071 && (s->prev == NULL || s->prev->hl != s->hl)));
3072 right_p = (last_glyph->right_box_line_p
3073 || (s->hl == DRAW_MOUSE_FACE
3074 && (s->next == NULL || s->next->hl != s->hl)));
3075
3076 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3077
3078 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3079 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3080 {
3081 ns_draw_box (r, abs (thickness),
3082 ns_lookup_indexed_color (face->box_color, s->f),
3083 left_p, right_p);
3084 }
3085 else
3086 {
3087 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3088 1, 1, left_p, right_p, s);
3089 }
3090 }
3091
3092
3093 static void
3094 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3095 /* --------------------------------------------------------------------------
3096 Modeled after x_draw_glyph_string_background, which draws BG in
3097 certain cases. Others are left to the text rendering routine.
3098 -------------------------------------------------------------------------- */
3099 {
3100 NSTRACE ("ns_maybe_dumpglyphs_background");
3101
3102 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3103 {
3104 int box_line_width = max (s->face->box_line_width, 0);
3105 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3106 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3107 dimensions, since the actual glyphs might be much
3108 smaller. So in that case we always clear the rectangle
3109 with background color. */
3110 || FONT_TOO_HIGH (s->font)
3111 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3112 {
3113 struct face *face;
3114 if (s->hl == DRAW_MOUSE_FACE)
3115 {
3116 face = FACE_FROM_ID (s->f,
3117 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3118 if (!face)
3119 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3120 }
3121 else
3122 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3123 if (!face->stipple)
3124 [(NS_FACE_BACKGROUND (face) != 0
3125 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3126 : FRAME_BACKGROUND_COLOR (s->f)) set];
3127 else
3128 {
3129 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3130 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3131 }
3132
3133 if (s->hl != DRAW_CURSOR)
3134 {
3135 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3136 s->background_width,
3137 s->height-2*box_line_width);
3138 NSRectFill (r);
3139 }
3140
3141 s->background_filled_p = 1;
3142 }
3143 }
3144 }
3145
3146
3147 static void
3148 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3149 /* --------------------------------------------------------------------------
3150 Renders an image and associated borders.
3151 -------------------------------------------------------------------------- */
3152 {
3153 EmacsImage *img = s->img->pixmap;
3154 int box_line_vwidth = max (s->face->box_line_width, 0);
3155 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3156 int bg_x, bg_y, bg_height;
3157 int th;
3158 char raised_p;
3159 NSRect br;
3160 struct face *face;
3161 NSColor *tdCol;
3162
3163 NSTRACE ("ns_dumpglyphs_image");
3164
3165 if (s->face->box != FACE_NO_BOX
3166 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3167 x += abs (s->face->box_line_width);
3168
3169 bg_x = x;
3170 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3171 bg_height = s->height;
3172 /* other terms have this, but was causing problems w/tabbar mode */
3173 /* - 2 * box_line_vwidth; */
3174
3175 if (s->slice.x == 0) x += s->img->hmargin;
3176 if (s->slice.y == 0) y += s->img->vmargin;
3177
3178 /* Draw BG: if we need larger area than image itself cleared, do that,
3179 otherwise, since we composite the image under NS (instead of mucking
3180 with its background color), we must clear just the image area. */
3181 if (s->hl == DRAW_MOUSE_FACE)
3182 {
3183 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3184 if (!face)
3185 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3186 }
3187 else
3188 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3189
3190 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3191
3192 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3193 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3194 {
3195 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3196 s->background_filled_p = 1;
3197 }
3198 else
3199 {
3200 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3201 }
3202
3203 NSRectFill (br);
3204
3205 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3206 if (img != nil)
3207 {
3208 #ifdef NS_IMPL_COCOA
3209 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3210 NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3211 s->slice.width, s->slice.height);
3212 [img drawInRect: dr
3213 fromRect: ir
3214 operation: NSCompositeSourceOver
3215 fraction: 1.0
3216 respectFlipped: YES
3217 hints: nil];
3218 #else
3219 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3220 operation: NSCompositeSourceOver];
3221 #endif
3222 }
3223
3224 if (s->hl == DRAW_CURSOR)
3225 {
3226 [FRAME_CURSOR_COLOR (s->f) set];
3227 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3228 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3229 else
3230 /* Currently on NS img->mask is always 0. Since
3231 get_window_cursor_type specifies a hollow box cursor when on
3232 a non-masked image we never reach this clause. But we put it
3233 in in anticipation of better support for image masks on
3234 NS. */
3235 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3236 }
3237 else
3238 {
3239 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3240 }
3241
3242 /* Draw underline, overline, strike-through. */
3243 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3244
3245 /* Draw relief, if requested */
3246 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3247 {
3248 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3249 {
3250 th = tool_bar_button_relief >= 0 ?
3251 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3252 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3253 }
3254 else
3255 {
3256 th = abs (s->img->relief);
3257 raised_p = (s->img->relief > 0);
3258 }
3259
3260 r.origin.x = x - th;
3261 r.origin.y = y - th;
3262 r.size.width = s->slice.width + 2*th-1;
3263 r.size.height = s->slice.height + 2*th-1;
3264 ns_draw_relief (r, th, raised_p,
3265 s->slice.y == 0,
3266 s->slice.y + s->slice.height == s->img->height,
3267 s->slice.x == 0,
3268 s->slice.x + s->slice.width == s->img->width, s);
3269 }
3270
3271 /* If there is no mask, the background won't be seen,
3272 so draw a rectangle on the image for the cursor.
3273 Do this for all images, getting transparency right is not reliable. */
3274 if (s->hl == DRAW_CURSOR)
3275 {
3276 int thickness = abs (s->img->relief);
3277 if (thickness == 0) thickness = 1;
3278 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3279 }
3280 }
3281
3282
3283 static void
3284 ns_dumpglyphs_stretch (struct glyph_string *s)
3285 {
3286 NSRect r[2];
3287 int n, i;
3288 struct face *face;
3289 NSColor *fgCol, *bgCol;
3290
3291 if (!s->background_filled_p)
3292 {
3293 n = ns_get_glyph_string_clip_rect (s, r);
3294 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3295
3296 ns_focus (s->f, r, n);
3297
3298 if (s->hl == DRAW_MOUSE_FACE)
3299 {
3300 face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3301 if (!face)
3302 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3303 }
3304 else
3305 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3306
3307 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3308 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3309
3310 for (i = 0; i < n; ++i)
3311 {
3312 if (!s->row->full_width_p)
3313 {
3314 int overrun, leftoverrun;
3315
3316 /* truncate to avoid overwriting fringe and/or scrollbar */
3317 overrun = max (0, (s->x + s->background_width)
3318 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3319 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3320 r[i].size.width -= overrun;
3321
3322 /* truncate to avoid overwriting to left of the window box */
3323 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3324 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3325
3326 if (leftoverrun > 0)
3327 {
3328 r[i].origin.x += leftoverrun;
3329 r[i].size.width -= leftoverrun;
3330 }
3331
3332 /* XXX: Try to work between problem where a stretch glyph on
3333 a partially-visible bottom row will clear part of the
3334 modeline, and another where list-buffers headers and similar
3335 rows erroneously have visible_height set to 0. Not sure
3336 where this is coming from as other terms seem not to show. */
3337 r[i].size.height = min (s->height, s->row->visible_height);
3338 }
3339
3340 [bgCol set];
3341
3342 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3343 overwriting cursor (usually when cursor on a tab) */
3344 if (s->hl == DRAW_CURSOR)
3345 {
3346 CGFloat x, width;
3347
3348 x = r[i].origin.x;
3349 width = s->w->phys_cursor_width;
3350 r[i].size.width -= width;
3351 r[i].origin.x += width;
3352
3353 NSRectFill (r[i]);
3354
3355 /* Draw overlining, etc. on the cursor. */
3356 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3357 ns_draw_text_decoration (s, face, bgCol, width, x);
3358 else
3359 ns_draw_text_decoration (s, face, fgCol, width, x);
3360 }
3361 else
3362 {
3363 NSRectFill (r[i]);
3364 }
3365
3366 /* Draw overlining, etc. on the stretch glyph (or the part
3367 of the stretch glyph after the cursor). */
3368 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3369 r[i].origin.x);
3370 }
3371 ns_unfocus (s->f);
3372 s->background_filled_p = 1;
3373 }
3374 }
3375
3376
3377 static void
3378 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3379 {
3380 int i, j, x;
3381 struct font *font = s->font;
3382
3383 /* If first glyph of S has a left box line, start drawing the text
3384 of S to the right of that box line. */
3385 if (s->face && s->face->box != FACE_NO_BOX
3386 && s->first_glyph->left_box_line_p)
3387 x = s->x + eabs (s->face->box_line_width);
3388 else
3389 x = s->x;
3390
3391 /* S is a glyph string for a composition. S->cmp_from is the index
3392 of the first character drawn for glyphs of this composition.
3393 S->cmp_from == 0 means we are drawing the very first character of
3394 this composition. */
3395
3396 /* Draw a rectangle for the composition if the font for the very
3397 first character of the composition could not be loaded. */
3398 if (s->font_not_found_p)
3399 {
3400 if (s->cmp_from == 0)
3401 {
3402 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3403 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3404 }
3405 }
3406 else if (! s->first_glyph->u.cmp.automatic)
3407 {
3408 int y = s->ybase;
3409
3410 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3411 /* TAB in a composition means display glyphs with padding
3412 space on the left or right. */
3413 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3414 {
3415 int xx = x + s->cmp->offsets[j * 2];
3416 int yy = y - s->cmp->offsets[j * 2 + 1];
3417
3418 font->driver->draw (s, j, j + 1, xx, yy, false);
3419 if (s->face->overstrike)
3420 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3421 }
3422 }
3423 else
3424 {
3425 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3426 Lisp_Object glyph;
3427 int y = s->ybase;
3428 int width = 0;
3429
3430 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3431 {
3432 glyph = LGSTRING_GLYPH (gstring, i);
3433 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3434 width += LGLYPH_WIDTH (glyph);
3435 else
3436 {
3437 int xoff, yoff, wadjust;
3438
3439 if (j < i)
3440 {
3441 font->driver->draw (s, j, i, x, y, false);
3442 if (s->face->overstrike)
3443 font->driver->draw (s, j, i, x + 1, y, false);
3444 x += width;
3445 }
3446 xoff = LGLYPH_XOFF (glyph);
3447 yoff = LGLYPH_YOFF (glyph);
3448 wadjust = LGLYPH_WADJUST (glyph);
3449 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3450 if (s->face->overstrike)
3451 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3452 false);
3453 x += wadjust;
3454 j = i + 1;
3455 width = 0;
3456 }
3457 }
3458 if (j < i)
3459 {
3460 font->driver->draw (s, j, i, x, y, false);
3461 if (s->face->overstrike)
3462 font->driver->draw (s, j, i, x + 1, y, false);
3463 }
3464 }
3465 }
3466
3467 static void
3468 ns_draw_glyph_string (struct glyph_string *s)
3469 /* --------------------------------------------------------------------------
3470 External (RIF): Main draw-text call.
3471 -------------------------------------------------------------------------- */
3472 {
3473 /* TODO (optimize): focus for box and contents draw */
3474 NSRect r[2];
3475 int n, flags;
3476 char box_drawn_p = 0;
3477 struct font *font = s->face->font;
3478 if (! font) font = FRAME_FONT (s->f);
3479
3480 NSTRACE ("ns_draw_glyph_string");
3481
3482 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3483 {
3484 int width;
3485 struct glyph_string *next;
3486
3487 for (width = 0, next = s->next;
3488 next && width < s->right_overhang;
3489 width += next->width, next = next->next)
3490 if (next->first_glyph->type != IMAGE_GLYPH)
3491 {
3492 if (next->first_glyph->type != STRETCH_GLYPH)
3493 {
3494 n = ns_get_glyph_string_clip_rect (s->next, r);
3495 ns_focus (s->f, r, n);
3496 ns_maybe_dumpglyphs_background (s->next, 1);
3497 ns_unfocus (s->f);
3498 }
3499 else
3500 {
3501 ns_dumpglyphs_stretch (s->next);
3502 }
3503 next->num_clips = 0;
3504 }
3505 }
3506
3507 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3508 && (s->first_glyph->type == CHAR_GLYPH
3509 || s->first_glyph->type == COMPOSITE_GLYPH))
3510 {
3511 n = ns_get_glyph_string_clip_rect (s, r);
3512 ns_focus (s->f, r, n);
3513 ns_maybe_dumpglyphs_background (s, 1);
3514 ns_dumpglyphs_box_or_relief (s);
3515 ns_unfocus (s->f);
3516 box_drawn_p = 1;
3517 }
3518
3519 switch (s->first_glyph->type)
3520 {
3521
3522 case IMAGE_GLYPH:
3523 n = ns_get_glyph_string_clip_rect (s, r);
3524 ns_focus (s->f, r, n);
3525 ns_dumpglyphs_image (s, r[0]);
3526 ns_unfocus (s->f);
3527 break;
3528
3529 case STRETCH_GLYPH:
3530 ns_dumpglyphs_stretch (s);
3531 break;
3532
3533 case CHAR_GLYPH:
3534 case COMPOSITE_GLYPH:
3535 n = ns_get_glyph_string_clip_rect (s, r);
3536 ns_focus (s->f, r, n);
3537
3538 if (s->for_overlaps || (s->cmp_from > 0
3539 && ! s->first_glyph->u.cmp.automatic))
3540 s->background_filled_p = 1;
3541 else
3542 ns_maybe_dumpglyphs_background
3543 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3544
3545 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3546 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3547 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3548 NS_DUMPGLYPH_NORMAL));
3549
3550 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3551 {
3552 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3553 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3554 NS_FACE_FOREGROUND (s->face) = tmp;
3555 }
3556
3557 {
3558 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3559
3560 if (isComposite)
3561 ns_draw_composite_glyph_string_foreground (s);
3562 else
3563 font->driver->draw
3564 (s, s->cmp_from, s->nchars, s->x, s->ybase,
3565 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3566 || flags == NS_DUMPGLYPH_MOUSEFACE);
3567 }
3568
3569 {
3570 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3571 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3572 s->f)
3573 : FRAME_FOREGROUND_COLOR (s->f));
3574 [col set];
3575
3576 /* Draw underline, overline, strike-through. */
3577 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3578 }
3579
3580 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3581 {
3582 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3583 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3584 NS_FACE_FOREGROUND (s->face) = tmp;
3585 }
3586
3587 ns_unfocus (s->f);
3588 break;
3589
3590 case GLYPHLESS_GLYPH:
3591 n = ns_get_glyph_string_clip_rect (s, r);
3592 ns_focus (s->f, r, n);
3593
3594 if (s->for_overlaps || (s->cmp_from > 0
3595 && ! s->first_glyph->u.cmp.automatic))
3596 s->background_filled_p = 1;
3597 else
3598 ns_maybe_dumpglyphs_background
3599 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3600 /* ... */
3601 /* Not yet implemented. */
3602 /* ... */
3603 ns_unfocus (s->f);
3604 break;
3605
3606 default:
3607 emacs_abort ();
3608 }
3609
3610 /* Draw box if not done already. */
3611 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3612 {
3613 n = ns_get_glyph_string_clip_rect (s, r);
3614 ns_focus (s->f, r, n);
3615 ns_dumpglyphs_box_or_relief (s);
3616 ns_unfocus (s->f);
3617 }
3618
3619 s->num_clips = 0;
3620 }
3621
3622
3623
3624 /* ==========================================================================
3625
3626 Event loop
3627
3628 ========================================================================== */
3629
3630
3631 static void
3632 ns_send_appdefined (int value)
3633 /* --------------------------------------------------------------------------
3634 Internal: post an appdefined event which EmacsApp-sendEvent will
3635 recognize and take as a command to halt the event loop.
3636 -------------------------------------------------------------------------- */
3637 {
3638 /*NSTRACE ("ns_send_appdefined"); */
3639
3640 #ifdef NS_IMPL_GNUSTEP
3641 // GNUstep needs postEvent to happen on the main thread.
3642 if (! [[NSThread currentThread] isMainThread])
3643 {
3644 EmacsApp *app = (EmacsApp *)NSApp;
3645 app->nextappdefined = value;
3646 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3647 withObject:nil
3648 waitUntilDone:YES];
3649 return;
3650 }
3651 #endif
3652
3653 /* Only post this event if we haven't already posted one. This will end
3654 the [NXApp run] main loop after having processed all events queued at
3655 this moment. */
3656
3657 #ifdef NS_IMPL_COCOA
3658 if (! send_appdefined)
3659 {
3660 /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3661 in certain situations (rapid incoming events).
3662 So check if we have one, if not add one. */
3663 NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3664 untilDate:[NSDate distantPast]
3665 inMode:NSDefaultRunLoopMode
3666 dequeue:NO];
3667 if (! appev) send_appdefined = YES;
3668 }
3669 #endif
3670
3671 if (send_appdefined)
3672 {
3673 NSEvent *nxev;
3674
3675 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
3676 send_appdefined = NO;
3677
3678 /* Don't need wakeup timer any more */
3679 if (timed_entry)
3680 {
3681 [timed_entry invalidate];
3682 [timed_entry release];
3683 timed_entry = nil;
3684 }
3685
3686 nxev = [NSEvent otherEventWithType: NSApplicationDefined
3687 location: NSMakePoint (0, 0)
3688 modifierFlags: 0
3689 timestamp: 0
3690 windowNumber: [[NSApp mainWindow] windowNumber]
3691 context: [NSApp context]
3692 subtype: 0
3693 data1: value
3694 data2: 0];
3695
3696 /* Post an application defined event on the event queue. When this is
3697 received the [NXApp run] will return, thus having processed all
3698 events which are currently queued. */
3699 [NSApp postEvent: nxev atStart: NO];
3700 }
3701 }
3702
3703 #ifdef HAVE_NATIVE_FS
3704 static void
3705 check_native_fs ()
3706 {
3707 Lisp_Object frame, tail;
3708
3709 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3710 return;
3711
3712 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3713
3714 FOR_EACH_FRAME (tail, frame)
3715 {
3716 struct frame *f = XFRAME (frame);
3717 if (FRAME_NS_P (f))
3718 {
3719 EmacsView *view = FRAME_NS_VIEW (f);
3720 [view updateCollectionBehavior];
3721 }
3722 }
3723 }
3724 #endif
3725
3726 /* GNUstep does not have cancelTracking. */
3727 #ifdef NS_IMPL_COCOA
3728 /* Check if menu open should be canceled or continued as normal. */
3729 void
3730 ns_check_menu_open (NSMenu *menu)
3731 {
3732 /* Click in menu bar? */
3733 NSArray *a = [[NSApp mainMenu] itemArray];
3734 int i;
3735 BOOL found = NO;
3736
3737 if (menu == nil) // Menu tracking ended.
3738 {
3739 if (menu_will_open_state == MENU_OPENING)
3740 menu_will_open_state = MENU_NONE;
3741 return;
3742 }
3743
3744 for (i = 0; ! found && i < [a count]; i++)
3745 found = menu == [[a objectAtIndex:i] submenu];
3746 if (found)
3747 {
3748 if (menu_will_open_state == MENU_NONE && emacs_event)
3749 {
3750 NSEvent *theEvent = [NSApp currentEvent];
3751 struct frame *emacsframe = SELECTED_FRAME ();
3752
3753 [menu cancelTracking];
3754 menu_will_open_state = MENU_PENDING;
3755 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3756 EV_TRAILER (theEvent);
3757
3758 CGEventRef ourEvent = CGEventCreate (NULL);
3759 menu_mouse_point = CGEventGetLocation (ourEvent);
3760 CFRelease (ourEvent);
3761 }
3762 else if (menu_will_open_state == MENU_OPENING)
3763 {
3764 menu_will_open_state = MENU_NONE;
3765 }
3766 }
3767 }
3768
3769 /* Redo saved menu click if state is MENU_PENDING. */
3770 void
3771 ns_check_pending_open_menu ()
3772 {
3773 if (menu_will_open_state == MENU_PENDING)
3774 {
3775 CGEventSourceRef source
3776 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3777
3778 CGEventRef event = CGEventCreateMouseEvent (source,
3779 kCGEventLeftMouseDown,
3780 menu_mouse_point,
3781 kCGMouseButtonLeft);
3782 CGEventSetType (event, kCGEventLeftMouseDown);
3783 CGEventPost (kCGHIDEventTap, event);
3784 CFRelease (event);
3785 CFRelease (source);
3786
3787 menu_will_open_state = MENU_OPENING;
3788 }
3789 }
3790 #endif /* NS_IMPL_COCOA */
3791
3792 static void
3793 unwind_apploopnr (Lisp_Object not_used)
3794 {
3795 --apploopnr;
3796 n_emacs_events_pending = 0;
3797 ns_finish_events ();
3798 q_event_ptr = NULL;
3799 }
3800
3801 static int
3802 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3803 /* --------------------------------------------------------------------------
3804 External (hook): Post an event to ourself and keep reading events until
3805 we read it back again. In effect process all events which were waiting.
3806 From 21+ we have to manage the event buffer ourselves.
3807 -------------------------------------------------------------------------- */
3808 {
3809 struct input_event ev;
3810 int nevents;
3811
3812 /* NSTRACE ("ns_read_socket"); */
3813
3814 #ifdef HAVE_NATIVE_FS
3815 check_native_fs ();
3816 #endif
3817
3818 if ([NSApp modalWindow] != nil)
3819 return -1;
3820
3821 if (hold_event_q.nr > 0)
3822 {
3823 int i;
3824 for (i = 0; i < hold_event_q.nr; ++i)
3825 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3826 hold_event_q.nr = 0;
3827 return i;
3828 }
3829
3830 block_input ();
3831 n_emacs_events_pending = 0;
3832 ns_init_events (&ev);
3833 q_event_ptr = hold_quit;
3834
3835 /* we manage autorelease pools by allocate/reallocate each time around
3836 the loop; strict nesting is occasionally violated but seems not to
3837 matter.. earlier methods using full nesting caused major memory leaks */
3838 [outerpool release];
3839 outerpool = [[NSAutoreleasePool alloc] init];
3840
3841 /* If have pending open-file requests, attend to the next one of those. */
3842 if (ns_pending_files && [ns_pending_files count] != 0
3843 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3844 {
3845 [ns_pending_files removeObjectAtIndex: 0];
3846 }
3847 /* Deal with pending service requests. */
3848 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3849 && [(EmacsApp *)
3850 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3851 withArg: [ns_pending_service_args objectAtIndex: 0]])
3852 {
3853 [ns_pending_service_names removeObjectAtIndex: 0];
3854 [ns_pending_service_args removeObjectAtIndex: 0];
3855 }
3856 else
3857 {
3858 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3859 /* Run and wait for events. We must always send one NX_APPDEFINED event
3860 to ourself, otherwise [NXApp run] will never exit. */
3861 send_appdefined = YES;
3862 ns_send_appdefined (-1);
3863
3864 if (++apploopnr != 1)
3865 {
3866 emacs_abort ();
3867 }
3868 record_unwind_protect (unwind_apploopnr, Qt);
3869 [NSApp run];
3870 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3871 }
3872
3873 nevents = n_emacs_events_pending;
3874 n_emacs_events_pending = 0;
3875 ns_finish_events ();
3876 q_event_ptr = NULL;
3877 unblock_input ();
3878
3879 return nevents;
3880 }
3881
3882
3883 int
3884 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3885 fd_set *exceptfds, struct timespec const *timeout,
3886 sigset_t const *sigmask)
3887 /* --------------------------------------------------------------------------
3888 Replacement for select, checking for events
3889 -------------------------------------------------------------------------- */
3890 {
3891 int result;
3892 int t, k, nr = 0;
3893 struct input_event event;
3894 char c;
3895
3896 /* NSTRACE ("ns_select"); */
3897
3898 #ifdef HAVE_NATIVE_FS
3899 check_native_fs ();
3900 #endif
3901
3902 if (hold_event_q.nr > 0)
3903 {
3904 /* We already have events pending. */
3905 raise (SIGIO);
3906 errno = EINTR;
3907 return -1;
3908 }
3909
3910 for (k = 0; k < nfds+1; k++)
3911 {
3912 if (readfds && FD_ISSET(k, readfds)) ++nr;
3913 if (writefds && FD_ISSET(k, writefds)) ++nr;
3914 }
3915
3916 if (NSApp == nil
3917 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3918 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3919
3920 [outerpool release];
3921 outerpool = [[NSAutoreleasePool alloc] init];
3922
3923
3924 send_appdefined = YES;
3925 if (nr > 0)
3926 {
3927 pthread_mutex_lock (&select_mutex);
3928 select_nfds = nfds;
3929 select_valid = 0;
3930 if (readfds)
3931 {
3932 select_readfds = *readfds;
3933 select_valid += SELECT_HAVE_READ;
3934 }
3935 if (writefds)
3936 {
3937 select_writefds = *writefds;
3938 select_valid += SELECT_HAVE_WRITE;
3939 }
3940
3941 if (timeout)
3942 {
3943 select_timeout = *timeout;
3944 select_valid += SELECT_HAVE_TMO;
3945 }
3946
3947 pthread_mutex_unlock (&select_mutex);
3948
3949 /* Inform fd_handler that select should be called */
3950 c = 'g';
3951 emacs_write_sig (selfds[1], &c, 1);
3952 }
3953 else if (nr == 0 && timeout)
3954 {
3955 /* No file descriptor, just a timeout, no need to wake fd_handler */
3956 double time = timespectod (*timeout);
3957 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3958 target: NSApp
3959 selector:
3960 @selector (timeout_handler:)
3961 userInfo: 0
3962 repeats: NO]
3963 retain];
3964 }
3965 else /* No timeout and no file descriptors, can this happen? */
3966 {
3967 /* Send appdefined so we exit from the loop */
3968 ns_send_appdefined (-1);
3969 }
3970
3971 block_input ();
3972 ns_init_events (&event);
3973 if (++apploopnr != 1)
3974 {
3975 emacs_abort ();
3976 }
3977
3978 {
3979 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3980 record_unwind_protect (unwind_apploopnr, Qt);
3981 [NSApp run];
3982 unbind_to (specpdl_count, Qnil); /* calls unwind_apploopnr */
3983 }
3984
3985 ns_finish_events ();
3986 if (nr > 0 && readfds)
3987 {
3988 c = 's';
3989 emacs_write_sig (selfds[1], &c, 1);
3990 }
3991 unblock_input ();
3992
3993 t = last_appdefined_event_data;
3994
3995 if (t != NO_APPDEFINED_DATA)
3996 {
3997 last_appdefined_event_data = NO_APPDEFINED_DATA;
3998
3999 if (t == -2)
4000 {
4001 /* The NX_APPDEFINED event we received was a timeout. */
4002 result = 0;
4003 }
4004 else if (t == -1)
4005 {
4006 /* The NX_APPDEFINED event we received was the result of
4007 at least one real input event arriving. */
4008 errno = EINTR;
4009 result = -1;
4010 }
4011 else
4012 {
4013 /* Received back from select () in fd_handler; copy the results */
4014 pthread_mutex_lock (&select_mutex);
4015 if (readfds) *readfds = select_readfds;
4016 if (writefds) *writefds = select_writefds;
4017 pthread_mutex_unlock (&select_mutex);
4018 result = t;
4019 }
4020 }
4021 else
4022 {
4023 errno = EINTR;
4024 result = -1;
4025 }
4026
4027 return result;
4028 }
4029
4030
4031
4032 /* ==========================================================================
4033
4034 Scrollbar handling
4035
4036 ========================================================================== */
4037
4038
4039 static void
4040 ns_set_vertical_scroll_bar (struct window *window,
4041 int portion, int whole, int position)
4042 /* --------------------------------------------------------------------------
4043 External (hook): Update or add scrollbar
4044 -------------------------------------------------------------------------- */
4045 {
4046 Lisp_Object win;
4047 NSRect r, v;
4048 struct frame *f = XFRAME (WINDOW_FRAME (window));
4049 EmacsView *view = FRAME_NS_VIEW (f);
4050 EmacsScroller *bar;
4051 int window_y, window_height;
4052 int top, left, height, width;
4053 BOOL update_p = YES;
4054
4055 /* optimization; display engine sends WAY too many of these.. */
4056 if (!NILP (window->vertical_scroll_bar))
4057 {
4058 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4059 if ([bar checkSamePosition: position portion: portion whole: whole])
4060 {
4061 if (view->scrollbarsNeedingUpdate == 0)
4062 {
4063 if (!windows_or_buffers_changed)
4064 return;
4065 }
4066 else
4067 view->scrollbarsNeedingUpdate--;
4068 update_p = NO;
4069 }
4070 }
4071
4072 NSTRACE ("ns_set_vertical_scroll_bar");
4073
4074 /* Get dimensions. */
4075 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4076 top = window_y;
4077 height = window_height;
4078 width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4079 left = WINDOW_SCROLL_BAR_AREA_X (window);
4080
4081 r = NSMakeRect (left, top, width, height);
4082 /* the parent view is flipped, so we need to flip y value */
4083 v = [view frame];
4084 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4085
4086 XSETWINDOW (win, window);
4087 block_input ();
4088
4089 /* we want at least 5 lines to display a scrollbar */
4090 if (WINDOW_TOTAL_LINES (window) < 5)
4091 {
4092 if (!NILP (window->vertical_scroll_bar))
4093 {
4094 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4095 [bar removeFromSuperview];
4096 wset_vertical_scroll_bar (window, Qnil);
4097 [bar release];
4098 }
4099 ns_clear_frame_area (f, left, top, width, height);
4100 unblock_input ();
4101 return;
4102 }
4103
4104 if (NILP (window->vertical_scroll_bar))
4105 {
4106 if (width > 0 && height > 0)
4107 ns_clear_frame_area (f, left, top, width, height);
4108
4109 bar = [[EmacsScroller alloc] initFrame: r window: win];
4110 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4111 update_p = YES;
4112 }
4113 else
4114 {
4115 NSRect oldRect;
4116 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4117 oldRect = [bar frame];
4118 r.size.width = oldRect.size.width;
4119 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4120 {
4121 if (oldRect.origin.x != r.origin.x)
4122 ns_clear_frame_area (f, left, top, width, height);
4123 [bar setFrame: r];
4124 }
4125 }
4126
4127 if (update_p)
4128 [bar setPosition: position portion: portion whole: whole];
4129 unblock_input ();
4130 }
4131
4132
4133 static void
4134 ns_set_horizontal_scroll_bar (struct window *window,
4135 int portion, int whole, int position)
4136 /* --------------------------------------------------------------------------
4137 External (hook): Update or add scrollbar
4138 -------------------------------------------------------------------------- */
4139 {
4140 Lisp_Object win;
4141 NSRect r, v;
4142 struct frame *f = XFRAME (WINDOW_FRAME (window));
4143 EmacsView *view = FRAME_NS_VIEW (f);
4144 EmacsScroller *bar;
4145 int top, height, left, width;
4146 int window_x, window_width;
4147 BOOL update_p = YES;
4148
4149 /* optimization; display engine sends WAY too many of these.. */
4150 if (!NILP (window->horizontal_scroll_bar))
4151 {
4152 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4153 if ([bar checkSamePosition: position portion: portion whole: whole])
4154 {
4155 if (view->scrollbarsNeedingUpdate == 0)
4156 {
4157 if (!windows_or_buffers_changed)
4158 return;
4159 }
4160 else
4161 view->scrollbarsNeedingUpdate--;
4162 update_p = NO;
4163 }
4164 }
4165
4166 NSTRACE ("ns_set_horizontal_scroll_bar");
4167
4168 /* Get dimensions. */
4169 window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4170 left = window_x;
4171 width = window_width;
4172 height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4173 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4174
4175 r = NSMakeRect (left, top, width, height);
4176 /* the parent view is flipped, so we need to flip y value */
4177 v = [view frame];
4178 /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4179 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4180
4181 XSETWINDOW (win, window);
4182 block_input ();
4183
4184 if (WINDOW_TOTAL_COLS (window) < 5)
4185 {
4186 if (!NILP (window->horizontal_scroll_bar))
4187 {
4188 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4189 [bar removeFromSuperview];
4190 wset_horizontal_scroll_bar (window, Qnil);
4191 }
4192 ns_clear_frame_area (f, left, top, width, height);
4193 unblock_input ();
4194 return;
4195 }
4196
4197 if (NILP (window->horizontal_scroll_bar))
4198 {
4199 if (width > 0 && height > 0)
4200 ns_clear_frame_area (f, left, top, width, height);
4201
4202 bar = [[EmacsScroller alloc] initFrame: r window: win];
4203 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4204 update_p = YES;
4205 }
4206 else
4207 {
4208 NSRect oldRect;
4209 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4210 oldRect = [bar frame];
4211 r.size.width = oldRect.size.width;
4212 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4213 {
4214 if (oldRect.origin.x != r.origin.x)
4215 ns_clear_frame_area (f, left, top, width, height);
4216 [bar setFrame: r];
4217 update_p = YES;
4218 }
4219 }
4220
4221 if (update_p)
4222 [bar setPosition: position portion: portion whole: whole];
4223 unblock_input ();
4224 }
4225
4226
4227 static void
4228 ns_condemn_scroll_bars (struct frame *f)
4229 /* --------------------------------------------------------------------------
4230 External (hook): arrange for all frame's scrollbars to be removed
4231 at next call to judge_scroll_bars, except for those redeemed.
4232 -------------------------------------------------------------------------- */
4233 {
4234 int i;
4235 id view;
4236 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4237
4238 NSTRACE ("ns_condemn_scroll_bars");
4239
4240 for (i =[subviews count]-1; i >= 0; i--)
4241 {
4242 view = [subviews objectAtIndex: i];
4243 if ([view isKindOfClass: [EmacsScroller class]])
4244 [view condemn];
4245 }
4246 }
4247
4248
4249 static void
4250 ns_redeem_scroll_bar (struct window *window)
4251 /* --------------------------------------------------------------------------
4252 External (hook): arrange to spare this window's scrollbar
4253 at next call to judge_scroll_bars.
4254 -------------------------------------------------------------------------- */
4255 {
4256 id bar;
4257 NSTRACE ("ns_redeem_scroll_bar");
4258 if (!NILP (window->vertical_scroll_bar))
4259 {
4260 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4261 [bar reprieve];
4262 }
4263
4264 if (!NILP (window->horizontal_scroll_bar))
4265 {
4266 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4267 [bar reprieve];
4268 }
4269 }
4270
4271
4272 static void
4273 ns_judge_scroll_bars (struct frame *f)
4274 /* --------------------------------------------------------------------------
4275 External (hook): destroy all scrollbars on frame that weren't
4276 redeemed after call to condemn_scroll_bars.
4277 -------------------------------------------------------------------------- */
4278 {
4279 int i;
4280 id view;
4281 EmacsView *eview = FRAME_NS_VIEW (f);
4282 NSArray *subviews = [[eview superview] subviews];
4283 BOOL removed = NO;
4284
4285 NSTRACE ("ns_judge_scroll_bars");
4286 for (i = [subviews count]-1; i >= 0; --i)
4287 {
4288 view = [subviews objectAtIndex: i];
4289 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4290 if ([view judge])
4291 removed = YES;
4292 }
4293
4294 if (removed)
4295 [eview updateFrameSize: NO];
4296 }
4297
4298 /* ==========================================================================
4299
4300 Initialization
4301
4302 ========================================================================== */
4303
4304 int
4305 x_display_pixel_height (struct ns_display_info *dpyinfo)
4306 {
4307 NSArray *screens = [NSScreen screens];
4308 NSEnumerator *enumerator = [screens objectEnumerator];
4309 NSScreen *screen;
4310 NSRect frame;
4311
4312 frame = NSZeroRect;
4313 while ((screen = [enumerator nextObject]) != nil)
4314 frame = NSUnionRect (frame, [screen frame]);
4315
4316 return NSHeight (frame);
4317 }
4318
4319 int
4320 x_display_pixel_width (struct ns_display_info *dpyinfo)
4321 {
4322 NSArray *screens = [NSScreen screens];
4323 NSEnumerator *enumerator = [screens objectEnumerator];
4324 NSScreen *screen;
4325 NSRect frame;
4326
4327 frame = NSZeroRect;
4328 while ((screen = [enumerator nextObject]) != nil)
4329 frame = NSUnionRect (frame, [screen frame]);
4330
4331 return NSWidth (frame);
4332 }
4333
4334
4335 static Lisp_Object ns_string_to_lispmod (const char *s)
4336 /* --------------------------------------------------------------------------
4337 Convert modifier name to lisp symbol
4338 -------------------------------------------------------------------------- */
4339 {
4340 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4341 return Qmeta;
4342 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4343 return Qsuper;
4344 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4345 return Qcontrol;
4346 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4347 return Qalt;
4348 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4349 return Qhyper;
4350 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4351 return Qnone;
4352 else
4353 return Qnil;
4354 }
4355
4356
4357 static void
4358 ns_default (const char *parameter, Lisp_Object *result,
4359 Lisp_Object yesval, Lisp_Object noval,
4360 BOOL is_float, BOOL is_modstring)
4361 /* --------------------------------------------------------------------------
4362 Check a parameter value in user's preferences
4363 -------------------------------------------------------------------------- */
4364 {
4365 const char *value = ns_get_defaults_value (parameter);
4366
4367 if (value)
4368 {
4369 double f;
4370 char *pos;
4371 if (c_strcasecmp (value, "YES") == 0)
4372 *result = yesval;
4373 else if (c_strcasecmp (value, "NO") == 0)
4374 *result = noval;
4375 else if (is_float && (f = strtod (value, &pos), pos != value))
4376 *result = make_float (f);
4377 else if (is_modstring && value)
4378 *result = ns_string_to_lispmod (value);
4379 else fprintf (stderr,
4380 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4381 }
4382 }
4383
4384
4385 static void
4386 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4387 /* --------------------------------------------------------------------------
4388 Initialize global info and storage for display.
4389 -------------------------------------------------------------------------- */
4390 {
4391 NSScreen *screen = [NSScreen mainScreen];
4392 NSWindowDepth depth = [screen depth];
4393
4394 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4395 dpyinfo->resy = 72.27;
4396 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4397 NSColorSpaceFromDepth (depth)]
4398 && ![NSCalibratedWhiteColorSpace isEqualToString:
4399 NSColorSpaceFromDepth (depth)];
4400 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4401 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4402 dpyinfo->color_table->colors = NULL;
4403 dpyinfo->root_window = 42; /* a placeholder.. */
4404 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4405 dpyinfo->n_fonts = 0;
4406 dpyinfo->smallest_font_height = 1;
4407 dpyinfo->smallest_char_width = 1;
4408
4409 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4410 }
4411
4412
4413 /* This and next define (many of the) public functions in this file. */
4414 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4415 with using despite presence in the "system dependent" redisplay
4416 interface. In addition, many of the ns_ methods have code that is
4417 shared with all terms, indicating need for further refactoring. */
4418 extern frame_parm_handler ns_frame_parm_handlers[];
4419 static struct redisplay_interface ns_redisplay_interface =
4420 {
4421 ns_frame_parm_handlers,
4422 x_produce_glyphs,
4423 x_write_glyphs,
4424 x_insert_glyphs,
4425 x_clear_end_of_line,
4426 ns_scroll_run,
4427 ns_after_update_window_line,
4428 ns_update_window_begin,
4429 ns_update_window_end,
4430 0, /* flush_display */
4431 x_clear_window_mouse_face,
4432 x_get_glyph_overhangs,
4433 x_fix_overlapping_area,
4434 ns_draw_fringe_bitmap,
4435 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4436 0, /* destroy_fringe_bitmap */
4437 ns_compute_glyph_string_overhangs,
4438 ns_draw_glyph_string,
4439 ns_define_frame_cursor,
4440 ns_clear_frame_area,
4441 ns_draw_window_cursor,
4442 ns_draw_vertical_window_border,
4443 ns_draw_window_divider,
4444 ns_shift_glyphs_for_insert,
4445 ns_show_hourglass,
4446 ns_hide_hourglass
4447 };
4448
4449
4450 static void
4451 ns_delete_display (struct ns_display_info *dpyinfo)
4452 {
4453 /* TODO... */
4454 }
4455
4456
4457 /* This function is called when the last frame on a display is deleted. */
4458 static void
4459 ns_delete_terminal (struct terminal *terminal)
4460 {
4461 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4462
4463 NSTRACE ("ns_delete_terminal");
4464
4465 /* Protect against recursive calls. delete_frame in
4466 delete_terminal calls us back when it deletes our last frame. */
4467 if (!terminal->name)
4468 return;
4469
4470 block_input ();
4471
4472 x_destroy_all_bitmaps (dpyinfo);
4473 ns_delete_display (dpyinfo);
4474 unblock_input ();
4475 }
4476
4477
4478 static struct terminal *
4479 ns_create_terminal (struct ns_display_info *dpyinfo)
4480 /* --------------------------------------------------------------------------
4481 Set up use of NS before we make the first connection.
4482 -------------------------------------------------------------------------- */
4483 {
4484 struct terminal *terminal;
4485
4486 NSTRACE ("ns_create_terminal");
4487
4488 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4489
4490 terminal->display_info.ns = dpyinfo;
4491 dpyinfo->terminal = terminal;
4492
4493 terminal->clear_frame_hook = ns_clear_frame;
4494 terminal->ring_bell_hook = ns_ring_bell;
4495 terminal->update_begin_hook = ns_update_begin;
4496 terminal->update_end_hook = ns_update_end;
4497 terminal->read_socket_hook = ns_read_socket;
4498 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4499 terminal->mouse_position_hook = ns_mouse_position;
4500 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4501 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4502 terminal->fullscreen_hook = ns_fullscreen_hook;
4503 terminal->menu_show_hook = ns_menu_show;
4504 terminal->popup_dialog_hook = ns_popup_dialog;
4505 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4506 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4507 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4508 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4509 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4510 terminal->delete_frame_hook = x_destroy_window;
4511 terminal->delete_terminal_hook = ns_delete_terminal;
4512 /* Other hooks are NULL by default. */
4513
4514 return terminal;
4515 }
4516
4517
4518 struct ns_display_info *
4519 ns_term_init (Lisp_Object display_name)
4520 /* --------------------------------------------------------------------------
4521 Start the Application and get things rolling.
4522 -------------------------------------------------------------------------- */
4523 {
4524 struct terminal *terminal;
4525 struct ns_display_info *dpyinfo;
4526 static int ns_initialized = 0;
4527 Lisp_Object tmp;
4528
4529 if (ns_initialized) return x_display_list;
4530 ns_initialized = 1;
4531
4532 NSTRACE ("ns_term_init");
4533
4534 [outerpool release];
4535 outerpool = [[NSAutoreleasePool alloc] init];
4536
4537 /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4538 /*GSDebugAllocationActive (YES); */
4539 block_input ();
4540
4541 baud_rate = 38400;
4542 Fset_input_interrupt_mode (Qnil);
4543
4544 if (selfds[0] == -1)
4545 {
4546 if (emacs_pipe (selfds) != 0)
4547 {
4548 fprintf (stderr, "Failed to create pipe: %s\n",
4549 emacs_strerror (errno));
4550 emacs_abort ();
4551 }
4552
4553 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4554 FD_ZERO (&select_readfds);
4555 FD_ZERO (&select_writefds);
4556 pthread_mutex_init (&select_mutex, NULL);
4557 }
4558
4559 ns_pending_files = [[NSMutableArray alloc] init];
4560 ns_pending_service_names = [[NSMutableArray alloc] init];
4561 ns_pending_service_args = [[NSMutableArray alloc] init];
4562
4563 /* Start app and create the main menu, window, view.
4564 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4565 The view will then ask the NSApp to stop and return to Emacs. */
4566 [EmacsApp sharedApplication];
4567 if (NSApp == nil)
4568 return NULL;
4569 [NSApp setDelegate: NSApp];
4570
4571 /* Start the select thread. */
4572 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4573 toTarget:NSApp
4574 withObject:nil];
4575
4576 /* debugging: log all notifications */
4577 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4578 selector: @selector (logNotification:)
4579 name: nil object: nil]; */
4580
4581 dpyinfo = xzalloc (sizeof *dpyinfo);
4582
4583 ns_initialize_display_info (dpyinfo);
4584 terminal = ns_create_terminal (dpyinfo);
4585
4586 terminal->kboard = allocate_kboard (Qns);
4587 /* Don't let the initial kboard remain current longer than necessary.
4588 That would cause problems if a file loaded on startup tries to
4589 prompt in the mini-buffer. */
4590 if (current_kboard == initial_kboard)
4591 current_kboard = terminal->kboard;
4592 terminal->kboard->reference_count++;
4593
4594 dpyinfo->next = x_display_list;
4595 x_display_list = dpyinfo;
4596
4597 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4598
4599 terminal->name = xlispstrdup (display_name);
4600
4601 unblock_input ();
4602
4603 if (!inhibit_x_resources)
4604 {
4605 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4606 Qt, Qnil, NO, NO);
4607 tmp = Qnil;
4608 /* this is a standard variable */
4609 ns_default ("AppleAntiAliasingThreshold", &tmp,
4610 make_float (10.0), make_float (6.0), YES, NO);
4611 ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4612 }
4613
4614 NSTRACE_MSG ("Colors");
4615
4616 {
4617 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4618
4619 if ( cl == nil )
4620 {
4621 Lisp_Object color_file, color_map, color;
4622 unsigned long c;
4623 char *name;
4624
4625 color_file = Fexpand_file_name (build_string ("rgb.txt"),
4626 Fsymbol_value (intern ("data-directory")));
4627
4628 color_map = Fx_load_color_file (color_file);
4629 if (NILP (color_map))
4630 fatal ("Could not read %s.\n", SDATA (color_file));
4631
4632 cl = [[NSColorList alloc] initWithName: @"Emacs"];
4633 for ( ; CONSP (color_map); color_map = XCDR (color_map))
4634 {
4635 color = XCAR (color_map);
4636 name = SSDATA (XCAR (color));
4637 c = XINT (XCDR (color));
4638 [cl setColor:
4639 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4640 green: GREEN_FROM_ULONG (c) / 255.0
4641 blue: BLUE_FROM_ULONG (c) / 255.0
4642 alpha: 1.0]
4643 forKey: [NSString stringWithUTF8String: name]];
4644 }
4645 [cl writeToFile: nil];
4646 }
4647 }
4648
4649 NSTRACE_MSG ("Versions");
4650
4651 {
4652 #ifdef NS_IMPL_GNUSTEP
4653 Vwindow_system_version = build_string (gnustep_base_version);
4654 #else
4655 /*PSnextrelease (128, c); */
4656 char c[DBL_BUFSIZE_BOUND];
4657 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4658 Vwindow_system_version = make_unibyte_string (c, len);
4659 #endif
4660 }
4661
4662 delete_keyboard_wait_descriptor (0);
4663
4664 ns_app_name = [[NSProcessInfo processInfo] processName];
4665
4666 /* Set up OS X app menu */
4667
4668 NSTRACE_MSG ("Menu init");
4669
4670 #ifdef NS_IMPL_COCOA
4671 {
4672 NSMenu *appMenu;
4673 NSMenuItem *item;
4674 /* set up the application menu */
4675 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4676 [svcsMenu setAutoenablesItems: NO];
4677 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4678 [appMenu setAutoenablesItems: NO];
4679 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4680 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4681
4682 [appMenu insertItemWithTitle: @"About Emacs"
4683 action: @selector (orderFrontStandardAboutPanel:)
4684 keyEquivalent: @""
4685 atIndex: 0];
4686 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4687 [appMenu insertItemWithTitle: @"Preferences..."
4688 action: @selector (showPreferencesWindow:)
4689 keyEquivalent: @","
4690 atIndex: 2];
4691 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4692 item = [appMenu insertItemWithTitle: @"Services"
4693 action: @selector (menuDown:)
4694 keyEquivalent: @""
4695 atIndex: 4];
4696 [appMenu setSubmenu: svcsMenu forItem: item];
4697 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4698 [appMenu insertItemWithTitle: @"Hide Emacs"
4699 action: @selector (hide:)
4700 keyEquivalent: @"h"
4701 atIndex: 6];
4702 item = [appMenu insertItemWithTitle: @"Hide Others"
4703 action: @selector (hideOtherApplications:)
4704 keyEquivalent: @"h"
4705 atIndex: 7];
4706 [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4707 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4708 [appMenu insertItemWithTitle: @"Quit Emacs"
4709 action: @selector (terminate:)
4710 keyEquivalent: @"q"
4711 atIndex: 9];
4712
4713 item = [mainMenu insertItemWithTitle: ns_app_name
4714 action: @selector (menuDown:)
4715 keyEquivalent: @""
4716 atIndex: 0];
4717 [mainMenu setSubmenu: appMenu forItem: item];
4718 [dockMenu insertItemWithTitle: @"New Frame"
4719 action: @selector (newFrame:)
4720 keyEquivalent: @""
4721 atIndex: 0];
4722
4723 [NSApp setMainMenu: mainMenu];
4724 [NSApp setAppleMenu: appMenu];
4725 [NSApp setServicesMenu: svcsMenu];
4726 /* Needed at least on Cocoa, to get dock menu to show windows */
4727 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4728
4729 [[NSNotificationCenter defaultCenter]
4730 addObserver: mainMenu
4731 selector: @selector (trackingNotification:)
4732 name: NSMenuDidBeginTrackingNotification object: mainMenu];
4733 [[NSNotificationCenter defaultCenter]
4734 addObserver: mainMenu
4735 selector: @selector (trackingNotification:)
4736 name: NSMenuDidEndTrackingNotification object: mainMenu];
4737 }
4738 #endif /* MAC OS X menu setup */
4739
4740 /* Register our external input/output types, used for determining
4741 applicable services and also drag/drop eligibility. */
4742
4743 NSTRACE_MSG ("Input/output types");
4744
4745 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4746 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4747 retain];
4748 ns_drag_types = [[NSArray arrayWithObjects:
4749 NSStringPboardType,
4750 NSTabularTextPboardType,
4751 NSFilenamesPboardType,
4752 NSURLPboardType, nil] retain];
4753
4754 /* If fullscreen is in init/default-frame-alist, focus isn't set
4755 right for fullscreen windows, so set this. */
4756 [NSApp activateIgnoringOtherApps:YES];
4757
4758 NSTRACE_MSG ("Call NSApp run");
4759
4760 [NSApp run];
4761 ns_do_open_file = YES;
4762
4763 #ifdef NS_IMPL_GNUSTEP
4764 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4765 We must re-catch it so subprocess works. */
4766 catch_child_signal ();
4767 #endif
4768
4769 NSTRACE_MSG ("ns_term_init done");
4770
4771 return dpyinfo;
4772 }
4773
4774
4775 void
4776 ns_term_shutdown (int sig)
4777 {
4778 [[NSUserDefaults standardUserDefaults] synchronize];
4779
4780 /* code not reached in emacs.c after this is called by shut_down_emacs: */
4781 if (STRINGP (Vauto_save_list_file_name))
4782 unlink (SSDATA (Vauto_save_list_file_name));
4783
4784 if (sig == 0 || sig == SIGTERM)
4785 {
4786 [NSApp terminate: NSApp];
4787 }
4788 else // force a stack trace to happen
4789 {
4790 emacs_abort ();
4791 }
4792 }
4793
4794
4795 /* ==========================================================================
4796
4797 EmacsApp implementation
4798
4799 ========================================================================== */
4800
4801
4802 @implementation EmacsApp
4803
4804 - (id)init
4805 {
4806 if ((self = [super init]))
4807 {
4808 #ifdef NS_IMPL_COCOA
4809 self->isFirst = YES;
4810 #endif
4811 #ifdef NS_IMPL_GNUSTEP
4812 self->applicationDidFinishLaunchingCalled = NO;
4813 #endif
4814 }
4815
4816 return self;
4817 }
4818
4819 #ifdef NS_IMPL_COCOA
4820 - (void)run
4821 {
4822 #ifndef NSAppKitVersionNumber10_9
4823 #define NSAppKitVersionNumber10_9 1265
4824 #endif
4825
4826 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4827 {
4828 [super run];
4829 return;
4830 }
4831
4832 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4833
4834 if (isFirst) [self finishLaunching];
4835 isFirst = NO;
4836
4837 shouldKeepRunning = YES;
4838 do
4839 {
4840 [pool release];
4841 pool = [[NSAutoreleasePool alloc] init];
4842
4843 NSEvent *event =
4844 [self nextEventMatchingMask:NSAnyEventMask
4845 untilDate:[NSDate distantFuture]
4846 inMode:NSDefaultRunLoopMode
4847 dequeue:YES];
4848
4849 [self sendEvent:event];
4850 [self updateWindows];
4851 } while (shouldKeepRunning);
4852
4853 [pool release];
4854 }
4855
4856 - (void)stop: (id)sender
4857 {
4858 shouldKeepRunning = NO;
4859 // Stop possible dialog also. Noop if no dialog present.
4860 // The file dialog still leaks 7k - 10k on 10.9 though.
4861 [super stop:sender];
4862 }
4863 #endif /* NS_IMPL_COCOA */
4864
4865 - (void)logNotification: (NSNotification *)notification
4866 {
4867 const char *name = [[notification name] UTF8String];
4868 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4869 && !strstr (name, "WindowNumber"))
4870 NSLog (@"notification: '%@'", [notification name]);
4871 }
4872
4873
4874 - (void)sendEvent: (NSEvent *)theEvent
4875 /* --------------------------------------------------------------------------
4876 Called when NSApp is running for each event received. Used to stop
4877 the loop when we choose, since there's no way to just run one iteration.
4878 -------------------------------------------------------------------------- */
4879 {
4880 int type = [theEvent type];
4881 NSWindow *window = [theEvent window];
4882
4883 /* NSTRACE ("sendEvent"); */
4884 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4885
4886 #ifdef NS_IMPL_GNUSTEP
4887 // Keyboard events aren't propagated to file dialogs for some reason.
4888 if ([NSApp modalWindow] != nil &&
4889 (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4890 {
4891 [[NSApp modalWindow] sendEvent: theEvent];
4892 return;
4893 }
4894 #endif
4895
4896 if (represented_filename != nil && represented_frame)
4897 {
4898 NSString *fstr = represented_filename;
4899 NSView *view = FRAME_NS_VIEW (represented_frame);
4900 #ifdef NS_IMPL_COCOA
4901 /* work around a bug observed on 10.3 and later where
4902 setTitleWithRepresentedFilename does not clear out previous state
4903 if given filename does not exist */
4904 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4905 [[view window] setRepresentedFilename: @""];
4906 #endif
4907 [[view window] setRepresentedFilename: fstr];
4908 [represented_filename release];
4909 represented_filename = nil;
4910 represented_frame = NULL;
4911 }
4912
4913 if (type == NSApplicationDefined)
4914 {
4915 switch ([theEvent data2])
4916 {
4917 #ifdef NS_IMPL_COCOA
4918 case NSAPP_DATA2_RUNASSCRIPT:
4919 ns_run_ascript ();
4920 [self stop: self];
4921 return;
4922 #endif
4923 case NSAPP_DATA2_RUNFILEDIALOG:
4924 ns_run_file_dialog ();
4925 [self stop: self];
4926 return;
4927 }
4928 }
4929
4930 if (type == NSCursorUpdate && window == nil)
4931 {
4932 fprintf (stderr, "Dropping external cursor update event.\n");
4933 return;
4934 }
4935
4936 if (type == NSApplicationDefined)
4937 {
4938 /* Events posted by ns_send_appdefined interrupt the run loop here.
4939 But, if a modal window is up, an appdefined can still come through,
4940 (e.g., from a makeKeyWindow event) but stopping self also stops the
4941 modal loop. Just defer it until later. */
4942 if ([NSApp modalWindow] == nil)
4943 {
4944 last_appdefined_event_data = [theEvent data1];
4945 [self stop: self];
4946 }
4947 else
4948 {
4949 send_appdefined = YES;
4950 }
4951 }
4952
4953
4954 #ifdef NS_IMPL_COCOA
4955 /* If no dialog and none of our frames have focus and it is a move, skip it.
4956 It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4957 such as Wifi, sound, date or similar.
4958 This prevents "spooky" highlighting in the frame under the menu. */
4959 if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4960 {
4961 struct ns_display_info *di;
4962 BOOL has_focus = NO;
4963 for (di = x_display_list; ! has_focus && di; di = di->next)
4964 has_focus = di->x_focus_frame != 0;
4965 if (! has_focus)
4966 return;
4967 }
4968 #endif
4969
4970 [super sendEvent: theEvent];
4971 }
4972
4973
4974 - (void)showPreferencesWindow: (id)sender
4975 {
4976 struct frame *emacsframe = SELECTED_FRAME ();
4977 NSEvent *theEvent = [NSApp currentEvent];
4978
4979 if (!emacs_event)
4980 return;
4981 emacs_event->kind = NS_NONKEY_EVENT;
4982 emacs_event->code = KEY_NS_SHOW_PREFS;
4983 emacs_event->modifiers = 0;
4984 EV_TRAILER (theEvent);
4985 }
4986
4987
4988 - (void)newFrame: (id)sender
4989 {
4990 struct frame *emacsframe = SELECTED_FRAME ();
4991 NSEvent *theEvent = [NSApp currentEvent];
4992
4993 if (!emacs_event)
4994 return;
4995 emacs_event->kind = NS_NONKEY_EVENT;
4996 emacs_event->code = KEY_NS_NEW_FRAME;
4997 emacs_event->modifiers = 0;
4998 EV_TRAILER (theEvent);
4999 }
5000
5001
5002 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5003 - (BOOL) openFile: (NSString *)fileName
5004 {
5005 struct frame *emacsframe = SELECTED_FRAME ();
5006 NSEvent *theEvent = [NSApp currentEvent];
5007
5008 if (!emacs_event)
5009 return NO;
5010
5011 emacs_event->kind = NS_NONKEY_EVENT;
5012 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5013 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5014 ns_input_line = Qnil; /* can be start or cons start,end */
5015 emacs_event->modifiers =0;
5016 EV_TRAILER (theEvent);
5017
5018 return YES;
5019 }
5020
5021
5022 /* **************************************************************************
5023
5024 EmacsApp delegate implementation
5025
5026 ************************************************************************** */
5027
5028 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5029 /* --------------------------------------------------------------------------
5030 When application is loaded, terminate event loop in ns_term_init
5031 -------------------------------------------------------------------------- */
5032 {
5033 NSTRACE ("applicationDidFinishLaunching");
5034 #ifdef NS_IMPL_GNUSTEP
5035 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5036 #endif
5037 [NSApp setServicesProvider: NSApp];
5038
5039 [self antialiasThresholdDidChange:nil];
5040 #ifdef NS_IMPL_COCOA
5041 [[NSNotificationCenter defaultCenter]
5042 addObserver:self
5043 selector:@selector(antialiasThresholdDidChange:)
5044 name:NSAntialiasThresholdChangedNotification
5045 object:nil];
5046 #endif
5047
5048 ns_send_appdefined (-2);
5049 }
5050
5051 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5052 {
5053 #ifdef NS_IMPL_COCOA
5054 macfont_update_antialias_threshold ();
5055 #endif
5056 }
5057
5058
5059 /* Termination sequences:
5060 C-x C-c:
5061 Cmd-Q:
5062 MenuBar | File | Exit:
5063 Select Quit from App menubar:
5064 -terminate
5065 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5066 ns_term_shutdown()
5067
5068 Select Quit from Dock menu:
5069 Logout attempt:
5070 -appShouldTerminate
5071 Cancel -> Nothing else
5072 Accept ->
5073
5074 -terminate
5075 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5076 ns_term_shutdown()
5077
5078 */
5079
5080 - (void) terminate: (id)sender
5081 {
5082 struct frame *emacsframe = SELECTED_FRAME ();
5083
5084 if (!emacs_event)
5085 return;
5086
5087 emacs_event->kind = NS_NONKEY_EVENT;
5088 emacs_event->code = KEY_NS_POWER_OFF;
5089 emacs_event->arg = Qt; /* mark as non-key event */
5090 EV_TRAILER ((id)nil);
5091 }
5092
5093 static bool
5094 runAlertPanel(NSString *title,
5095 NSString *msgFormat,
5096 NSString *defaultButton,
5097 NSString *alternateButton)
5098 {
5099 #if !defined (NS_IMPL_COCOA) || \
5100 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5101 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5102 == NSAlertDefaultReturn;
5103 #else
5104 NSAlert *alert = [[NSAlert alloc] init];
5105 [alert setAlertStyle: NSCriticalAlertStyle];
5106 [alert setMessageText: msgFormat];
5107 [alert addButtonWithTitle: defaultButton];
5108 [alert addButtonWithTitle: alternateButton];
5109 NSInteger ret = [alert runModal];
5110 [alert release];
5111 return ret == NSAlertFirstButtonReturn;
5112 #endif
5113 }
5114
5115
5116 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5117 {
5118 bool ret;
5119
5120 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5121 return NSTerminateNow;
5122
5123 ret = runAlertPanel(ns_app_name,
5124 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5125 @"Save Buffers and Exit", @"Cancel");
5126
5127 if (ret)
5128 return NSTerminateNow;
5129 else
5130 return NSTerminateCancel;
5131 return NSTerminateNow; /* just in case */
5132 }
5133
5134 static int
5135 not_in_argv (NSString *arg)
5136 {
5137 int k;
5138 const char *a = [arg UTF8String];
5139 for (k = 1; k < initial_argc; ++k)
5140 if (strcmp (a, initial_argv[k]) == 0) return 0;
5141 return 1;
5142 }
5143
5144 /* Notification from the Workspace to open a file */
5145 - (BOOL)application: sender openFile: (NSString *)file
5146 {
5147 if (ns_do_open_file || not_in_argv (file))
5148 [ns_pending_files addObject: file];
5149 return YES;
5150 }
5151
5152
5153 /* Open a file as a temporary file */
5154 - (BOOL)application: sender openTempFile: (NSString *)file
5155 {
5156 if (ns_do_open_file || not_in_argv (file))
5157 [ns_pending_files addObject: file];
5158 return YES;
5159 }
5160
5161
5162 /* Notification from the Workspace to open a file noninteractively (?) */
5163 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5164 {
5165 if (ns_do_open_file || not_in_argv (file))
5166 [ns_pending_files addObject: file];
5167 return YES;
5168 }
5169
5170 /* Notification from the Workspace to open multiple files */
5171 - (void)application: sender openFiles: (NSArray *)fileList
5172 {
5173 NSEnumerator *files = [fileList objectEnumerator];
5174 NSString *file;
5175 /* Don't open files from the command line unconditionally,
5176 Cocoa parses the command line wrong, --option value tries to open value
5177 if --option is the last option. */
5178 while ((file = [files nextObject]) != nil)
5179 if (ns_do_open_file || not_in_argv (file))
5180 [ns_pending_files addObject: file];
5181
5182 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5183
5184 }
5185
5186
5187 /* Handle dock menu requests. */
5188 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5189 {
5190 return dockMenu;
5191 }
5192
5193
5194 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5195 - (void)applicationWillBecomeActive: (NSNotification *)notification
5196 {
5197 //ns_app_active=YES;
5198 }
5199 - (void)applicationDidBecomeActive: (NSNotification *)notification
5200 {
5201 NSTRACE ("applicationDidBecomeActive");
5202
5203 #ifdef NS_IMPL_GNUSTEP
5204 if (! applicationDidFinishLaunchingCalled)
5205 [self applicationDidFinishLaunching:notification];
5206 #endif
5207 //ns_app_active=YES;
5208
5209 ns_update_auto_hide_menu_bar ();
5210 // No constraining takes place when the application is not active.
5211 ns_constrain_all_frames ();
5212 }
5213 - (void)applicationDidResignActive: (NSNotification *)notification
5214 {
5215 //ns_app_active=NO;
5216 ns_send_appdefined (-1);
5217 }
5218
5219
5220
5221 /* ==========================================================================
5222
5223 EmacsApp aux handlers for managing event loop
5224
5225 ========================================================================== */
5226
5227
5228 - (void)timeout_handler: (NSTimer *)timedEntry
5229 /* --------------------------------------------------------------------------
5230 The timeout specified to ns_select has passed.
5231 -------------------------------------------------------------------------- */
5232 {
5233 /*NSTRACE ("timeout_handler"); */
5234 ns_send_appdefined (-2);
5235 }
5236
5237 #ifdef NS_IMPL_GNUSTEP
5238 - (void)sendFromMainThread:(id)unused
5239 {
5240 ns_send_appdefined (nextappdefined);
5241 }
5242 #endif
5243
5244 - (void)fd_handler:(id)unused
5245 /* --------------------------------------------------------------------------
5246 Check data waiting on file descriptors and terminate if so
5247 -------------------------------------------------------------------------- */
5248 {
5249 int result;
5250 int waiting = 1, nfds;
5251 char c;
5252
5253 fd_set readfds, writefds, *wfds;
5254 struct timespec timeout, *tmo;
5255 NSAutoreleasePool *pool = nil;
5256
5257 /* NSTRACE ("fd_handler"); */
5258
5259 for (;;)
5260 {
5261 [pool release];
5262 pool = [[NSAutoreleasePool alloc] init];
5263
5264 if (waiting)
5265 {
5266 fd_set fds;
5267 FD_ZERO (&fds);
5268 FD_SET (selfds[0], &fds);
5269 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5270 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5271 waiting = 0;
5272 }
5273 else
5274 {
5275 pthread_mutex_lock (&select_mutex);
5276 nfds = select_nfds;
5277
5278 if (select_valid & SELECT_HAVE_READ)
5279 readfds = select_readfds;
5280 else
5281 FD_ZERO (&readfds);
5282
5283 if (select_valid & SELECT_HAVE_WRITE)
5284 {
5285 writefds = select_writefds;
5286 wfds = &writefds;
5287 }
5288 else
5289 wfds = NULL;
5290 if (select_valid & SELECT_HAVE_TMO)
5291 {
5292 timeout = select_timeout;
5293 tmo = &timeout;
5294 }
5295 else
5296 tmo = NULL;
5297
5298 pthread_mutex_unlock (&select_mutex);
5299
5300 FD_SET (selfds[0], &readfds);
5301 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5302
5303 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5304
5305 if (result == 0)
5306 ns_send_appdefined (-2);
5307 else if (result > 0)
5308 {
5309 if (FD_ISSET (selfds[0], &readfds))
5310 {
5311 if (read (selfds[0], &c, 1) == 1 && c == 's')
5312 waiting = 1;
5313 }
5314 else
5315 {
5316 pthread_mutex_lock (&select_mutex);
5317 if (select_valid & SELECT_HAVE_READ)
5318 select_readfds = readfds;
5319 if (select_valid & SELECT_HAVE_WRITE)
5320 select_writefds = writefds;
5321 if (select_valid & SELECT_HAVE_TMO)
5322 select_timeout = timeout;
5323 pthread_mutex_unlock (&select_mutex);
5324
5325 ns_send_appdefined (result);
5326 }
5327 }
5328 waiting = 1;
5329 }
5330 }
5331 }
5332
5333
5334
5335 /* ==========================================================================
5336
5337 Service provision
5338
5339 ========================================================================== */
5340
5341 /* called from system: queue for next pass through event loop */
5342 - (void)requestService: (NSPasteboard *)pboard
5343 userData: (NSString *)userData
5344 error: (NSString **)error
5345 {
5346 [ns_pending_service_names addObject: userData];
5347 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5348 SSDATA (ns_string_from_pasteboard (pboard))]];
5349 }
5350
5351
5352 /* called from ns_read_socket to clear queue */
5353 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5354 {
5355 struct frame *emacsframe = SELECTED_FRAME ();
5356 NSEvent *theEvent = [NSApp currentEvent];
5357
5358 if (!emacs_event)
5359 return NO;
5360
5361 emacs_event->kind = NS_NONKEY_EVENT;
5362 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5363 ns_input_spi_name = build_string ([name UTF8String]);
5364 ns_input_spi_arg = build_string ([arg UTF8String]);
5365 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5366 EV_TRAILER (theEvent);
5367
5368 return YES;
5369 }
5370
5371
5372 @end /* EmacsApp */
5373
5374
5375
5376 /* ==========================================================================
5377
5378 EmacsView implementation
5379
5380 ========================================================================== */
5381
5382
5383 @implementation EmacsView
5384
5385 /* needed to inform when window closed from LISP */
5386 - (void) setWindowClosing: (BOOL)closing
5387 {
5388 windowClosing = closing;
5389 }
5390
5391
5392 - (void)dealloc
5393 {
5394 NSTRACE ("EmacsView_dealloc");
5395 [toolbar release];
5396 if (fs_state == FULLSCREEN_BOTH)
5397 [nonfs_window release];
5398 [super dealloc];
5399 }
5400
5401
5402 /* called on font panel selection */
5403 - (void)changeFont: (id)sender
5404 {
5405 NSEvent *e = [[self window] currentEvent];
5406 struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5407 struct font *font = face->font;
5408 id newFont;
5409 CGFloat size;
5410 NSFont *nsfont;
5411
5412 NSTRACE ("changeFont");
5413
5414 if (!emacs_event)
5415 return;
5416
5417 #ifdef NS_IMPL_GNUSTEP
5418 nsfont = ((struct nsfont_info *)font)->nsfont;
5419 #endif
5420 #ifdef NS_IMPL_COCOA
5421 nsfont = (NSFont *) macfont_get_nsctfont (font);
5422 #endif
5423
5424 if ((newFont = [sender convertFont: nsfont]))
5425 {
5426 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5427
5428 emacs_event->kind = NS_NONKEY_EVENT;
5429 emacs_event->modifiers = 0;
5430 emacs_event->code = KEY_NS_CHANGE_FONT;
5431
5432 size = [newFont pointSize];
5433 ns_input_fontsize = make_number (lrint (size));
5434 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5435 EV_TRAILER (e);
5436 }
5437 }
5438
5439
5440 - (BOOL)acceptsFirstResponder
5441 {
5442 NSTRACE ("acceptsFirstResponder");
5443 return YES;
5444 }
5445
5446
5447 - (void)resetCursorRects
5448 {
5449 NSRect visible = [self visibleRect];
5450 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5451 NSTRACE ("resetCursorRects");
5452
5453 if (currentCursor == nil)
5454 currentCursor = [NSCursor arrowCursor];
5455
5456 if (!NSIsEmptyRect (visible))
5457 [self addCursorRect: visible cursor: currentCursor];
5458 [currentCursor setOnMouseEntered: YES];
5459 }
5460
5461
5462
5463 /*****************************************************************************/
5464 /* Keyboard handling. */
5465 #define NS_KEYLOG 0
5466
5467 - (void)keyDown: (NSEvent *)theEvent
5468 {
5469 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5470 int code;
5471 unsigned fnKeysym = 0;
5472 static NSMutableArray *nsEvArray;
5473 int left_is_none;
5474 unsigned int flags = [theEvent modifierFlags];
5475
5476 NSTRACE ("keyDown");
5477
5478 /* Rhapsody and OS X give up and down events for the arrow keys */
5479 if (ns_fake_keydown == YES)
5480 ns_fake_keydown = NO;
5481 else if ([theEvent type] != NSKeyDown)
5482 return;
5483
5484 if (!emacs_event)
5485 return;
5486
5487 if (![[self window] isKeyWindow]
5488 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5489 /* we must avoid an infinite loop here. */
5490 && (EmacsView *)[[theEvent window] delegate] != self)
5491 {
5492 /* XXX: There is an occasional condition in which, when Emacs display
5493 updates a different frame from the current one, and temporarily
5494 selects it, then processes some interrupt-driven input
5495 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5496 for some reason that window has its first responder set to the NSView
5497 most recently updated (I guess), which is not the correct one. */
5498 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5499 return;
5500 }
5501
5502 if (nsEvArray == nil)
5503 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5504
5505 [NSCursor setHiddenUntilMouseMoves: YES];
5506
5507 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5508 {
5509 clear_mouse_face (hlinfo);
5510 hlinfo->mouse_face_hidden = 1;
5511 }
5512
5513 if (!processingCompose)
5514 {
5515 /* When using screen sharing, no left or right information is sent,
5516 so use Left key in those cases. */
5517 int is_left_key, is_right_key;
5518
5519 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5520 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5521
5522 /* (Carbon way: [theEvent keyCode]) */
5523
5524 /* is it a "function key"? */
5525 /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5526 flag set (this is probably a bug in the OS).
5527 */
5528 if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5529 {
5530 fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5531 }
5532 if (fnKeysym == 0)
5533 {
5534 fnKeysym = ns_convert_key (code);
5535 }
5536
5537 if (fnKeysym)
5538 {
5539 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5540 because Emacs treats Delete and KP-Delete same (in simple.el). */
5541 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5542 #ifdef NS_IMPL_GNUSTEP
5543 /* GNUstep uses incompatible keycodes, even for those that are
5544 supposed to be hardware independent. Just check for delete.
5545 Keypad delete does not have keysym 0xFFFF.
5546 See http://savannah.gnu.org/bugs/?25395
5547 */
5548 || (fnKeysym == 0xFFFF && code == 127)
5549 #endif
5550 )
5551 code = 0xFF08; /* backspace */
5552 else
5553 code = fnKeysym;
5554 }
5555
5556 /* are there modifiers? */
5557 emacs_event->modifiers = 0;
5558
5559 if (flags & NSHelpKeyMask)
5560 emacs_event->modifiers |= hyper_modifier;
5561
5562 if (flags & NSShiftKeyMask)
5563 emacs_event->modifiers |= shift_modifier;
5564
5565 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5566 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5567 || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5568
5569 if (is_right_key)
5570 emacs_event->modifiers |= parse_solitary_modifier
5571 (EQ (ns_right_command_modifier, Qleft)
5572 ? ns_command_modifier
5573 : ns_right_command_modifier);
5574
5575 if (is_left_key)
5576 {
5577 emacs_event->modifiers |= parse_solitary_modifier
5578 (ns_command_modifier);
5579
5580 /* if super (default), take input manager's word so things like
5581 dvorak / qwerty layout work */
5582 if (EQ (ns_command_modifier, Qsuper)
5583 && !fnKeysym
5584 && [[theEvent characters] length] != 0)
5585 {
5586 /* XXX: the code we get will be unshifted, so if we have
5587 a shift modifier, must convert ourselves */
5588 if (!(flags & NSShiftKeyMask))
5589 code = [[theEvent characters] characterAtIndex: 0];
5590 #if 0
5591 /* this is ugly and also requires linking w/Carbon framework
5592 (for LMGetKbdType) so for now leave this rare (?) case
5593 undealt with.. in future look into CGEvent methods */
5594 else
5595 {
5596 long smv = GetScriptManagerVariable (smKeyScript);
5597 Handle uchrHandle = GetResource
5598 ('uchr', GetScriptVariable (smv, smScriptKeys));
5599 UInt32 dummy = 0;
5600 UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5601 [[theEvent characters] characterAtIndex: 0],
5602 kUCKeyActionDisplay,
5603 (flags & ~NSCommandKeyMask) >> 8,
5604 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5605 &dummy, 1, &dummy, &code);
5606 code &= 0xFF;
5607 }
5608 #endif
5609 }
5610 }
5611
5612 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5613 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5614 || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5615
5616 if (is_right_key)
5617 emacs_event->modifiers |= parse_solitary_modifier
5618 (EQ (ns_right_control_modifier, Qleft)
5619 ? ns_control_modifier
5620 : ns_right_control_modifier);
5621
5622 if (is_left_key)
5623 emacs_event->modifiers |= parse_solitary_modifier
5624 (ns_control_modifier);
5625
5626 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5627 emacs_event->modifiers |=
5628 parse_solitary_modifier (ns_function_modifier);
5629
5630 left_is_none = NILP (ns_alternate_modifier)
5631 || EQ (ns_alternate_modifier, Qnone);
5632
5633 is_right_key = (flags & NSRightAlternateKeyMask)
5634 == NSRightAlternateKeyMask;
5635 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5636 || (! is_right_key
5637 && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5638
5639 if (is_right_key)
5640 {
5641 if ((NILP (ns_right_alternate_modifier)
5642 || EQ (ns_right_alternate_modifier, Qnone)
5643 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5644 && !fnKeysym)
5645 { /* accept pre-interp alt comb */
5646 if ([[theEvent characters] length] > 0)
5647 code = [[theEvent characters] characterAtIndex: 0];
5648 /*HACK: clear lone shift modifier to stop next if from firing */
5649 if (emacs_event->modifiers == shift_modifier)
5650 emacs_event->modifiers = 0;
5651 }
5652 else
5653 emacs_event->modifiers |= parse_solitary_modifier
5654 (EQ (ns_right_alternate_modifier, Qleft)
5655 ? ns_alternate_modifier
5656 : ns_right_alternate_modifier);
5657 }
5658
5659 if (is_left_key) /* default = meta */
5660 {
5661 if (left_is_none && !fnKeysym)
5662 { /* accept pre-interp alt comb */
5663 if ([[theEvent characters] length] > 0)
5664 code = [[theEvent characters] characterAtIndex: 0];
5665 /*HACK: clear lone shift modifier to stop next if from firing */
5666 if (emacs_event->modifiers == shift_modifier)
5667 emacs_event->modifiers = 0;
5668 }
5669 else
5670 emacs_event->modifiers |=
5671 parse_solitary_modifier (ns_alternate_modifier);
5672 }
5673
5674 if (NS_KEYLOG)
5675 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5676 code, fnKeysym, flags, emacs_event->modifiers);
5677
5678 /* if it was a function key or had modifiers, pass it directly to emacs */
5679 if (fnKeysym || (emacs_event->modifiers
5680 && (emacs_event->modifiers != shift_modifier)
5681 && [[theEvent charactersIgnoringModifiers] length] > 0))
5682 /*[[theEvent characters] length] */
5683 {
5684 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5685 if (code < 0x20)
5686 code |= (1<<28)|(3<<16);
5687 else if (code == 0x7f)
5688 code |= (1<<28)|(3<<16);
5689 else if (!fnKeysym)
5690 emacs_event->kind = code > 0xFF
5691 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5692
5693 emacs_event->code = code;
5694 EV_TRAILER (theEvent);
5695 processingCompose = NO;
5696 return;
5697 }
5698 }
5699
5700
5701 if (NS_KEYLOG && !processingCompose)
5702 fprintf (stderr, "keyDown: Begin compose sequence.\n");
5703
5704 processingCompose = YES;
5705 [nsEvArray addObject: theEvent];
5706 [self interpretKeyEvents: nsEvArray];
5707 [nsEvArray removeObject: theEvent];
5708 }
5709
5710
5711 #ifdef NS_IMPL_COCOA
5712 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5713 decided not to send key-down for.
5714 See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5715 This only applies on Tiger and earlier.
5716 If it matches one of these, send it on to keyDown. */
5717 -(void)keyUp: (NSEvent *)theEvent
5718 {
5719 int flags = [theEvent modifierFlags];
5720 int code = [theEvent keyCode];
5721 if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5722 code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5723 {
5724 if (NS_KEYLOG)
5725 fprintf (stderr, "keyUp: passed test");
5726 ns_fake_keydown = YES;
5727 [self keyDown: theEvent];
5728 }
5729 }
5730 #endif
5731
5732
5733 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5734
5735
5736 /* <NSTextInput>: called when done composing;
5737 NOTE: also called when we delete over working text, followed immed.
5738 by doCommandBySelector: deleteBackward: */
5739 - (void)insertText: (id)aString
5740 {
5741 int code;
5742 int len = [(NSString *)aString length];
5743 int i;
5744
5745 if (NS_KEYLOG)
5746 NSLog (@"insertText '%@'\tlen = %d", aString, len);
5747 processingCompose = NO;
5748
5749 if (!emacs_event)
5750 return;
5751
5752 /* first, clear any working text */
5753 if (workingText != nil)
5754 [self deleteWorkingText];
5755
5756 /* now insert the string as keystrokes */
5757 for (i =0; i<len; i++)
5758 {
5759 code = [aString characterAtIndex: i];
5760 /* TODO: still need this? */
5761 if (code == 0x2DC)
5762 code = '~'; /* 0x7E */
5763 if (code != 32) /* Space */
5764 emacs_event->modifiers = 0;
5765 emacs_event->kind
5766 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5767 emacs_event->code = code;
5768 EV_TRAILER ((id)nil);
5769 }
5770 }
5771
5772
5773 /* <NSTextInput>: inserts display of composing characters */
5774 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5775 {
5776 NSString *str = [aString respondsToSelector: @selector (string)] ?
5777 [aString string] : aString;
5778 if (NS_KEYLOG)
5779 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5780 str, (unsigned long)[str length],
5781 (unsigned long)selRange.length,
5782 (unsigned long)selRange.location);
5783
5784 if (workingText != nil)
5785 [self deleteWorkingText];
5786 if ([str length] == 0)
5787 return;
5788
5789 if (!emacs_event)
5790 return;
5791
5792 processingCompose = YES;
5793 workingText = [str copy];
5794 ns_working_text = build_string ([workingText UTF8String]);
5795
5796 emacs_event->kind = NS_TEXT_EVENT;
5797 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5798 EV_TRAILER ((id)nil);
5799 }
5800
5801
5802 /* delete display of composing characters [not in <NSTextInput>] */
5803 - (void)deleteWorkingText
5804 {
5805 if (workingText == nil)
5806 return;
5807 if (NS_KEYLOG)
5808 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5809 [workingText release];
5810 workingText = nil;
5811 processingCompose = NO;
5812
5813 if (!emacs_event)
5814 return;
5815
5816 emacs_event->kind = NS_TEXT_EVENT;
5817 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5818 EV_TRAILER ((id)nil);
5819 }
5820
5821
5822 - (BOOL)hasMarkedText
5823 {
5824 return workingText != nil;
5825 }
5826
5827
5828 - (NSRange)markedRange
5829 {
5830 NSRange rng = workingText != nil
5831 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5832 if (NS_KEYLOG)
5833 NSLog (@"markedRange request");
5834 return rng;
5835 }
5836
5837
5838 - (void)unmarkText
5839 {
5840 if (NS_KEYLOG)
5841 NSLog (@"unmark (accept) text");
5842 [self deleteWorkingText];
5843 processingCompose = NO;
5844 }
5845
5846
5847 /* used to position char selection windows, etc. */
5848 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5849 {
5850 NSRect rect;
5851 NSPoint pt;
5852 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5853 if (NS_KEYLOG)
5854 NSLog (@"firstRectForCharRange request");
5855
5856 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5857 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5858 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5859 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5860 +FRAME_LINE_HEIGHT (emacsframe));
5861
5862 pt = [self convertPoint: pt toView: nil];
5863 pt = [[self window] convertBaseToScreen: pt];
5864 rect.origin = pt;
5865 return rect;
5866 }
5867
5868
5869 - (NSInteger)conversationIdentifier
5870 {
5871 return (NSInteger)self;
5872 }
5873
5874
5875 - (void)doCommandBySelector: (SEL)aSelector
5876 {
5877 if (NS_KEYLOG)
5878 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5879
5880 processingCompose = NO;
5881 if (aSelector == @selector (deleteBackward:))
5882 {
5883 /* happens when user backspaces over an ongoing composition:
5884 throw a 'delete' into the event queue */
5885 if (!emacs_event)
5886 return;
5887 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5888 emacs_event->code = 0xFF08;
5889 EV_TRAILER ((id)nil);
5890 }
5891 }
5892
5893 - (NSArray *)validAttributesForMarkedText
5894 {
5895 static NSArray *arr = nil;
5896 if (arr == nil) arr = [NSArray new];
5897 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5898 return arr;
5899 }
5900
5901 - (NSRange)selectedRange
5902 {
5903 if (NS_KEYLOG)
5904 NSLog (@"selectedRange request");
5905 return NSMakeRange (NSNotFound, 0);
5906 }
5907
5908 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5909 GNUSTEP_GUI_MINOR_VERSION > 22
5910 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5911 #else
5912 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5913 #endif
5914 {
5915 if (NS_KEYLOG)
5916 NSLog (@"characterIndexForPoint request");
5917 return 0;
5918 }
5919
5920 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5921 {
5922 static NSAttributedString *str = nil;
5923 if (str == nil) str = [NSAttributedString new];
5924 if (NS_KEYLOG)
5925 NSLog (@"attributedSubstringFromRange request");
5926 return str;
5927 }
5928
5929 /* End <NSTextInput> impl. */
5930 /*****************************************************************************/
5931
5932
5933 /* This is what happens when the user presses a mouse button. */
5934 - (void)mouseDown: (NSEvent *)theEvent
5935 {
5936 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5937 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5938
5939 NSTRACE ("mouseDown");
5940
5941 [self deleteWorkingText];
5942
5943 if (!emacs_event)
5944 return;
5945
5946 dpyinfo->last_mouse_frame = emacsframe;
5947 /* appears to be needed to prevent spurious movement events generated on
5948 button clicks */
5949 emacsframe->mouse_moved = 0;
5950
5951 if ([theEvent type] == NSScrollWheel)
5952 {
5953 CGFloat delta = [theEvent deltaY];
5954 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5955 if (delta == 0)
5956 {
5957 delta = [theEvent deltaX];
5958 if (delta == 0)
5959 {
5960 NSTRACE ("deltaIsZero");
5961 return;
5962 }
5963 emacs_event->kind = HORIZ_WHEEL_EVENT;
5964 }
5965 else
5966 emacs_event->kind = WHEEL_EVENT;
5967
5968 emacs_event->code = 0;
5969 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5970 ((delta > 0) ? up_modifier : down_modifier);
5971 }
5972 else
5973 {
5974 emacs_event->kind = MOUSE_CLICK_EVENT;
5975 emacs_event->code = EV_BUTTON (theEvent);
5976 emacs_event->modifiers = EV_MODIFIERS (theEvent)
5977 | EV_UDMODIFIERS (theEvent);
5978 }
5979 XSETINT (emacs_event->x, lrint (p.x));
5980 XSETINT (emacs_event->y, lrint (p.y));
5981 EV_TRAILER (theEvent);
5982 }
5983
5984
5985 - (void)rightMouseDown: (NSEvent *)theEvent
5986 {
5987 NSTRACE ("rightMouseDown");
5988 [self mouseDown: theEvent];
5989 }
5990
5991
5992 - (void)otherMouseDown: (NSEvent *)theEvent
5993 {
5994 NSTRACE ("otherMouseDown");
5995 [self mouseDown: theEvent];
5996 }
5997
5998
5999 - (void)mouseUp: (NSEvent *)theEvent
6000 {
6001 NSTRACE ("mouseUp");
6002 [self mouseDown: theEvent];
6003 }
6004
6005
6006 - (void)rightMouseUp: (NSEvent *)theEvent
6007 {
6008 NSTRACE ("rightMouseUp");
6009 [self mouseDown: theEvent];
6010 }
6011
6012
6013 - (void)otherMouseUp: (NSEvent *)theEvent
6014 {
6015 NSTRACE ("otherMouseUp");
6016 [self mouseDown: theEvent];
6017 }
6018
6019
6020 - (void) scrollWheel: (NSEvent *)theEvent
6021 {
6022 NSTRACE ("scrollWheel");
6023 [self mouseDown: theEvent];
6024 }
6025
6026
6027 /* Tell emacs the mouse has moved. */
6028 - (void)mouseMoved: (NSEvent *)e
6029 {
6030 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6031 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6032 Lisp_Object frame;
6033 NSPoint pt;
6034
6035 // NSTRACE ("mouseMoved");
6036
6037 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6038 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6039 dpyinfo->last_mouse_motion_x = pt.x;
6040 dpyinfo->last_mouse_motion_y = pt.y;
6041
6042 /* update any mouse face */
6043 if (hlinfo->mouse_face_hidden)
6044 {
6045 hlinfo->mouse_face_hidden = 0;
6046 clear_mouse_face (hlinfo);
6047 }
6048
6049 /* tooltip handling */
6050 previous_help_echo_string = help_echo_string;
6051 help_echo_string = Qnil;
6052
6053 if (!NILP (Vmouse_autoselect_window))
6054 {
6055 NSTRACE ("mouse_autoselect_window");
6056 static Lisp_Object last_mouse_window;
6057 Lisp_Object window
6058 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6059
6060 if (WINDOWP (window)
6061 && !EQ (window, last_mouse_window)
6062 && !EQ (window, selected_window)
6063 && (focus_follows_mouse
6064 || (EQ (XWINDOW (window)->frame,
6065 XWINDOW (selected_window)->frame))))
6066 {
6067 NSTRACE ("in_window");
6068 emacs_event->kind = SELECT_WINDOW_EVENT;
6069 emacs_event->frame_or_window = window;
6070 EV_TRAILER2 (e);
6071 }
6072 /* Remember the last window where we saw the mouse. */
6073 last_mouse_window = window;
6074 }
6075
6076 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6077 help_echo_string = previous_help_echo_string;
6078
6079 XSETFRAME (frame, emacsframe);
6080 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6081 {
6082 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6083 (note_mouse_highlight), which is called through the
6084 note_mouse_movement () call above */
6085 any_help_event_p = YES;
6086 gen_help_event (help_echo_string, frame, help_echo_window,
6087 help_echo_object, help_echo_pos);
6088 }
6089
6090 if (emacsframe->mouse_moved && send_appdefined)
6091 ns_send_appdefined (-1);
6092 }
6093
6094
6095 - (void)mouseDragged: (NSEvent *)e
6096 {
6097 NSTRACE ("mouseDragged");
6098 [self mouseMoved: e];
6099 }
6100
6101
6102 - (void)rightMouseDragged: (NSEvent *)e
6103 {
6104 NSTRACE ("rightMouseDragged");
6105 [self mouseMoved: e];
6106 }
6107
6108
6109 - (void)otherMouseDragged: (NSEvent *)e
6110 {
6111 NSTRACE ("otherMouseDragged");
6112 [self mouseMoved: e];
6113 }
6114
6115
6116 - (BOOL)windowShouldClose: (id)sender
6117 {
6118 NSEvent *e =[[self window] currentEvent];
6119
6120 NSTRACE ("windowShouldClose");
6121 windowClosing = YES;
6122 if (!emacs_event)
6123 return NO;
6124 emacs_event->kind = DELETE_WINDOW_EVENT;
6125 emacs_event->modifiers = 0;
6126 emacs_event->code = 0;
6127 EV_TRAILER (e);
6128 /* Don't close this window, let this be done from lisp code. */
6129 return NO;
6130 }
6131
6132 - (void) updateFrameSize: (BOOL) delay;
6133 {
6134 NSWindow *window = [self window];
6135 NSRect wr = [window frame];
6136 int extra = 0;
6137 int oldc = cols, oldr = rows;
6138 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6139 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6140 int neww, newh;
6141
6142 NSTRACE ("updateFrameSize");
6143 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6144 NSTRACE_RECT ("Original frame", wr);
6145
6146 if (! [self isFullscreen])
6147 {
6148 #ifdef NS_IMPL_GNUSTEP
6149 // GNUstep does not always update the tool bar height. Force it.
6150 if (toolbar && [toolbar isVisible])
6151 update_frame_tool_bar (emacsframe);
6152 #endif
6153
6154 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6155 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6156 }
6157
6158 if (wait_for_tool_bar)
6159 {
6160 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6161 return;
6162 wait_for_tool_bar = NO;
6163 }
6164
6165 neww = (int)wr.size.width - emacsframe->border_width;
6166 newh = (int)wr.size.height - extra;
6167
6168 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6169 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6170
6171 if (cols < MINWIDTH)
6172 cols = MINWIDTH;
6173
6174 if (rows < MINHEIGHT)
6175 rows = MINHEIGHT;
6176
6177 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6178 {
6179 NSView *view = FRAME_NS_VIEW (emacsframe);
6180 NSWindow *win = [view window];
6181
6182 change_frame_size (emacsframe,
6183 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6184 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6185 0, delay, 0, 1);
6186 SET_FRAME_GARBAGED (emacsframe);
6187 cancel_mouse_face (emacsframe);
6188
6189 wr = NSMakeRect (0, 0, neww, newh);
6190 NSTRACE_RECT ("setFrame", wr);
6191 [view setFrame: wr];
6192 [self windowDidMove:nil]; // Update top/left.
6193 }
6194 }
6195
6196 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6197 /* normalize frame to gridded text size */
6198 {
6199 int extra = 0;
6200
6201 NSTRACE ("windowWillResize: toSize: " NSTRACE_FMT_SIZE,
6202 NSTRACE_ARG_SIZE (frameSize));
6203 NSTRACE_RECT ("[sender frame]", [sender frame]);
6204 NSTRACE_FSTYPE ("fs_state", fs_state);
6205
6206 if (fs_state == FULLSCREEN_MAXIMIZED
6207 && (maximized_width != (int)frameSize.width
6208 || maximized_height != (int)frameSize.height))
6209 [self setFSValue: FULLSCREEN_NONE];
6210 else if (fs_state == FULLSCREEN_WIDTH
6211 && maximized_width != (int)frameSize.width)
6212 [self setFSValue: FULLSCREEN_NONE];
6213 else if (fs_state == FULLSCREEN_HEIGHT
6214 && maximized_height != (int)frameSize.height)
6215 [self setFSValue: FULLSCREEN_NONE];
6216
6217 if (fs_state == FULLSCREEN_NONE)
6218 maximized_width = maximized_height = -1;
6219
6220 if (! [self isFullscreen])
6221 {
6222 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6223 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6224 }
6225
6226 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6227 if (cols < MINWIDTH)
6228 cols = MINWIDTH;
6229
6230 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6231 frameSize.height - extra);
6232 if (rows < MINHEIGHT)
6233 rows = MINHEIGHT;
6234 #ifdef NS_IMPL_COCOA
6235 {
6236 /* this sets window title to have size in it; the wm does this under GS */
6237 NSRect r = [[self window] frame];
6238 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6239 {
6240 if (old_title != 0)
6241 {
6242 xfree (old_title);
6243 old_title = 0;
6244 }
6245 }
6246 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6247 {
6248 char *size_title;
6249 NSWindow *window = [self window];
6250 if (old_title == 0)
6251 {
6252 char *t = strdup ([[[self window] title] UTF8String]);
6253 char *pos = strstr (t, " — ");
6254 if (pos)
6255 *pos = '\0';
6256 old_title = t;
6257 }
6258 size_title = xmalloc (strlen (old_title) + 40);
6259 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6260 [window setTitle: [NSString stringWithUTF8String: size_title]];
6261 [window display];
6262 xfree (size_title);
6263 }
6264 }
6265 #endif /* NS_IMPL_COCOA */
6266
6267 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6268
6269 /* Restrict the new size to the text gird.
6270
6271 Don't restict the width if the user only adjusted the height, and
6272 vice versa. (Without this, the frame would shrink, and move
6273 slightly, if the window was resized by dragging one of its
6274 borders.) */
6275 if (!frame_resize_pixelwise)
6276 {
6277 NSRect r = [[self window] frame];
6278
6279 if (r.size.width != frameSize.width)
6280 {
6281 frameSize.width =
6282 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6283 }
6284
6285 if (r.size.height != frameSize.height)
6286 {
6287 frameSize.height =
6288 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6289 }
6290 }
6291
6292 NSTRACE_RETURN_SIZE (frameSize);
6293
6294 return frameSize;
6295 }
6296
6297
6298 - (void)windowDidResize: (NSNotification *)notification
6299 {
6300 NSTRACE ("windowDidResize");
6301
6302 if (! [self fsIsNative])
6303 {
6304 NSWindow *theWindow = [notification object];
6305 /* We can get notification on the non-FS window when in
6306 fullscreen mode. */
6307 if ([self window] != theWindow) return;
6308 }
6309
6310 NSTRACE_RECT ("frame", [[notification object] frame]);
6311
6312 #ifdef NS_IMPL_GNUSTEP
6313 NSWindow *theWindow = [notification object];
6314
6315 /* In GNUstep, at least currently, it's possible to get a didResize
6316 without getting a willResize.. therefore we need to act as if we got
6317 the willResize now */
6318 NSSize sz = [theWindow frame].size;
6319 sz = [self windowWillResize: theWindow toSize: sz];
6320 #endif /* NS_IMPL_GNUSTEP */
6321
6322 if (cols > 0 && rows > 0)
6323 {
6324 [self updateFrameSize: YES];
6325 }
6326
6327 ns_send_appdefined (-1);
6328 }
6329
6330 #ifdef NS_IMPL_COCOA
6331 - (void)viewDidEndLiveResize
6332 {
6333 [super viewDidEndLiveResize];
6334 if (old_title != 0)
6335 {
6336 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6337 xfree (old_title);
6338 old_title = 0;
6339 }
6340 maximizing_resize = NO;
6341 }
6342 #endif /* NS_IMPL_COCOA */
6343
6344
6345 - (void)windowDidBecomeKey: (NSNotification *)notification
6346 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6347 {
6348 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6349 struct frame *old_focus = dpyinfo->x_focus_frame;
6350
6351 NSTRACE ("windowDidBecomeKey");
6352
6353 if (emacsframe != old_focus)
6354 dpyinfo->x_focus_frame = emacsframe;
6355
6356 ns_frame_rehighlight (emacsframe);
6357
6358 if (emacs_event)
6359 {
6360 emacs_event->kind = FOCUS_IN_EVENT;
6361 EV_TRAILER ((id)nil);
6362 }
6363 }
6364
6365
6366 - (void)windowDidResignKey: (NSNotification *)notification
6367 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6368 {
6369 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6370 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6371 NSTRACE ("windowDidResignKey");
6372
6373 if (is_focus_frame)
6374 dpyinfo->x_focus_frame = 0;
6375
6376 emacsframe->mouse_moved = 0;
6377 ns_frame_rehighlight (emacsframe);
6378
6379 /* FIXME: for some reason needed on second and subsequent clicks away
6380 from sole-frame Emacs to get hollow box to show */
6381 if (!windowClosing && [[self window] isVisible] == YES)
6382 {
6383 x_update_cursor (emacsframe, 1);
6384 x_set_frame_alpha (emacsframe);
6385 }
6386
6387 if (any_help_event_p)
6388 {
6389 Lisp_Object frame;
6390 XSETFRAME (frame, emacsframe);
6391 help_echo_string = Qnil;
6392 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6393 }
6394
6395 if (emacs_event && is_focus_frame)
6396 {
6397 [self deleteWorkingText];
6398 emacs_event->kind = FOCUS_OUT_EVENT;
6399 EV_TRAILER ((id)nil);
6400 }
6401 }
6402
6403
6404 - (void)windowWillMiniaturize: sender
6405 {
6406 NSTRACE ("windowWillMiniaturize");
6407 }
6408
6409
6410 - (BOOL)isFlipped
6411 {
6412 return YES;
6413 }
6414
6415
6416 - (BOOL)isOpaque
6417 {
6418 return NO;
6419 }
6420
6421
6422 - initFrameFromEmacs: (struct frame *)f
6423 {
6424 NSRect r, wr;
6425 Lisp_Object tem;
6426 NSWindow *win;
6427 NSColor *col;
6428 NSString *name;
6429
6430 NSTRACE ("initFrameFromEmacs");
6431
6432 windowClosing = NO;
6433 processingCompose = NO;
6434 scrollbarsNeedingUpdate = 0;
6435 fs_state = FULLSCREEN_NONE;
6436 fs_before_fs = next_maximized = -1;
6437 #ifdef HAVE_NATIVE_FS
6438 fs_is_native = ns_use_native_fullscreen;
6439 #else
6440 fs_is_native = NO;
6441 #endif
6442 maximized_width = maximized_height = -1;
6443 nonfs_window = nil;
6444
6445 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6446
6447 ns_userRect = NSMakeRect (0, 0, 0, 0);
6448 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6449 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6450 [self initWithFrame: r];
6451 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6452
6453 FRAME_NS_VIEW (f) = self;
6454 emacsframe = f;
6455 #ifdef NS_IMPL_COCOA
6456 old_title = 0;
6457 maximizing_resize = NO;
6458 #endif
6459
6460 win = [[EmacsWindow alloc]
6461 initWithContentRect: r
6462 styleMask: (NSResizableWindowMask |
6463 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6464 NSTitledWindowMask |
6465 #endif
6466 NSMiniaturizableWindowMask |
6467 NSClosableWindowMask)
6468 backing: NSBackingStoreBuffered
6469 defer: YES];
6470
6471 #ifdef HAVE_NATIVE_FS
6472 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6473 #endif
6474
6475 wr = [win frame];
6476 bwidth = f->border_width = wr.size.width - r.size.width;
6477 tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6478
6479 [win setAcceptsMouseMovedEvents: YES];
6480 [win setDelegate: self];
6481 #if !defined (NS_IMPL_COCOA) || \
6482 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6483 [win useOptimizedDrawing: YES];
6484 #endif
6485
6486 [[win contentView] addSubview: self];
6487
6488 if (ns_drag_types)
6489 [self registerForDraggedTypes: ns_drag_types];
6490
6491 tem = f->name;
6492 name = [NSString stringWithUTF8String:
6493 NILP (tem) ? "Emacs" : SSDATA (tem)];
6494 [win setTitle: name];
6495
6496 /* toolbar support */
6497 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6498 [NSString stringWithFormat: @"Emacs Frame %d",
6499 ns_window_num]];
6500 [win setToolbar: toolbar];
6501 [toolbar setVisible: NO];
6502
6503 /* Don't set frame garbaged until tool bar is up to date?
6504 This avoids an extra clear and redraw (flicker) at frame creation. */
6505 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6506 else wait_for_tool_bar = NO;
6507
6508
6509 #ifdef NS_IMPL_COCOA
6510 {
6511 NSButton *toggleButton;
6512 toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6513 [toggleButton setTarget: self];
6514 [toggleButton setAction: @selector (toggleToolbar: )];
6515 }
6516 #endif
6517 FRAME_TOOLBAR_HEIGHT (f) = 0;
6518
6519 tem = f->icon_name;
6520 if (!NILP (tem))
6521 [win setMiniwindowTitle:
6522 [NSString stringWithUTF8String: SSDATA (tem)]];
6523
6524 {
6525 NSScreen *screen = [win screen];
6526
6527 if (screen != 0)
6528 {
6529 NSPoint pt = NSMakePoint
6530 (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6531 IN_BOUND (-SCREENMAX,
6532 [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6533
6534 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
6535
6536 [win setFrameTopLeftPoint: pt];
6537
6538 NSTRACE_RECT ("new frame", [win frame]);
6539 }
6540 }
6541
6542 [win makeFirstResponder: self];
6543
6544 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6545 (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6546 [win setBackgroundColor: col];
6547 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6548 [win setOpaque: NO];
6549
6550 #if !defined (NS_IMPL_COCOA) || \
6551 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6552 [self allocateGState];
6553 #endif
6554 [NSApp registerServicesMenuSendTypes: ns_send_types
6555 returnTypes: nil];
6556
6557 ns_window_num++;
6558 return self;
6559 }
6560
6561
6562 - (void)windowDidMove: sender
6563 {
6564 NSWindow *win = [self window];
6565 NSRect r = [win frame];
6566 NSArray *screens = [NSScreen screens];
6567 NSScreen *screen = [screens objectAtIndex: 0];
6568
6569 NSTRACE ("windowDidMove");
6570
6571 if (!emacsframe->output_data.ns)
6572 return;
6573 if (screen != nil)
6574 {
6575 emacsframe->left_pos = r.origin.x;
6576 emacsframe->top_pos =
6577 [screen frame].size.height - (r.origin.y + r.size.height);
6578 }
6579 }
6580
6581
6582 /* Called AFTER method below, but before our windowWillResize call there leads
6583 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
6584 location so set_window_size moves the frame. */
6585 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6586 {
6587 NSTRACE (("[windowShouldZoom:win toFrame:" NSTRACE_FMT_RECT "]"
6588 NSTRACE_FMT_RETURN "YES"),
6589 NSTRACE_ARG_RECT (newFrame));
6590
6591 emacsframe->output_data.ns->zooming = 1;
6592 return YES;
6593 }
6594
6595
6596 /* Override to do something slightly nonstandard, but nice. First click on
6597 zoom button will zoom vertically. Second will zoom completely. Third
6598 returns to original. */
6599 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6600 defaultFrame:(NSRect)defaultFrame
6601 {
6602 // TODO: Rename to "currentFrame" and assign "result" properly in
6603 // all paths.
6604 NSRect result = [sender frame];
6605
6606 NSTRACE (("[windowWillUseStandardFrame: defaultFrame:"
6607 NSTRACE_FMT_RECT "]"),
6608 NSTRACE_ARG_RECT (defaultFrame));
6609 NSTRACE_FSTYPE ("fs_state", fs_state);
6610 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6611 NSTRACE_FSTYPE ("next_maximized", next_maximized);
6612 NSTRACE_RECT ("ns_userRect", ns_userRect);
6613 NSTRACE_RECT ("[sender frame]", [sender frame]);
6614
6615 if (fs_before_fs != -1) /* Entering fullscreen */
6616 {
6617 NSTRACE_MSG ("Entering fullscreen");
6618 result = defaultFrame;
6619 }
6620 else
6621 {
6622 // Save the window size and position (frame) before the resize.
6623 if (fs_state != FULLSCREEN_MAXIMIZED
6624 && fs_state != FULLSCREEN_WIDTH)
6625 {
6626 ns_userRect.size.width = result.size.width;
6627 ns_userRect.origin.x = result.origin.x;
6628 }
6629
6630 if (fs_state != FULLSCREEN_MAXIMIZED
6631 && fs_state != FULLSCREEN_HEIGHT)
6632 {
6633 ns_userRect.size.height = result.size.height;
6634 ns_userRect.origin.y = result.origin.y;
6635 }
6636
6637 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6638
6639 if (next_maximized == FULLSCREEN_HEIGHT
6640 || (next_maximized == -1
6641 && abs ((int)(defaultFrame.size.height - result.size.height))
6642 > FRAME_LINE_HEIGHT (emacsframe)))
6643 {
6644 /* first click */
6645 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6646 maximized_height = result.size.height = defaultFrame.size.height;
6647 maximized_width = -1;
6648 result.origin.y = defaultFrame.origin.y;
6649 if (ns_userRect.size.height != 0)
6650 {
6651 result.origin.x = ns_userRect.origin.x;
6652 result.size.width = ns_userRect.size.width;
6653 }
6654 [self setFSValue: FULLSCREEN_HEIGHT];
6655 #ifdef NS_IMPL_COCOA
6656 maximizing_resize = YES;
6657 #endif
6658 }
6659 else if (next_maximized == FULLSCREEN_WIDTH)
6660 {
6661 NSTRACE_MSG ("FULLSCREEN_WIDTH");
6662 maximized_width = result.size.width = defaultFrame.size.width;
6663 maximized_height = -1;
6664 result.origin.x = defaultFrame.origin.x;
6665 if (ns_userRect.size.width != 0)
6666 {
6667 result.origin.y = ns_userRect.origin.y;
6668 result.size.height = ns_userRect.size.height;
6669 }
6670 [self setFSValue: FULLSCREEN_WIDTH];
6671 }
6672 else if (next_maximized == FULLSCREEN_MAXIMIZED
6673 || (next_maximized == -1
6674 && abs ((int)(defaultFrame.size.width - result.size.width))
6675 > FRAME_COLUMN_WIDTH (emacsframe)))
6676 {
6677 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
6678
6679 result = defaultFrame; /* second click */
6680 maximized_width = result.size.width;
6681 maximized_height = result.size.height;
6682 [self setFSValue: FULLSCREEN_MAXIMIZED];
6683 #ifdef NS_IMPL_COCOA
6684 maximizing_resize = YES;
6685 #endif
6686 }
6687 else
6688 {
6689 /* restore */
6690 NSTRACE_MSG ("Restore");
6691 result = ns_userRect.size.height ? ns_userRect : result;
6692 NSTRACE_RECT ("restore (2)", result);
6693 ns_userRect = NSMakeRect (0, 0, 0, 0);
6694 #ifdef NS_IMPL_COCOA
6695 maximizing_resize = fs_state != FULLSCREEN_NONE;
6696 #endif
6697 [self setFSValue: FULLSCREEN_NONE];
6698 maximized_width = maximized_height = -1;
6699 }
6700 }
6701
6702 if (fs_before_fs == -1) next_maximized = -1;
6703
6704 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
6705 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
6706 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
6707 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
6708
6709 [self windowWillResize: sender toSize: result.size];
6710
6711 NSTRACE_RETURN_RECT (result);
6712
6713 return result;
6714 }
6715
6716
6717 - (void)windowDidDeminiaturize: sender
6718 {
6719 NSTRACE ("windowDidDeminiaturize");
6720 if (!emacsframe->output_data.ns)
6721 return;
6722
6723 SET_FRAME_ICONIFIED (emacsframe, 0);
6724 SET_FRAME_VISIBLE (emacsframe, 1);
6725 windows_or_buffers_changed = 63;
6726
6727 if (emacs_event)
6728 {
6729 emacs_event->kind = DEICONIFY_EVENT;
6730 EV_TRAILER ((id)nil);
6731 }
6732 }
6733
6734
6735 - (void)windowDidExpose: sender
6736 {
6737 NSTRACE ("windowDidExpose");
6738 if (!emacsframe->output_data.ns)
6739 return;
6740
6741 SET_FRAME_VISIBLE (emacsframe, 1);
6742 SET_FRAME_GARBAGED (emacsframe);
6743
6744 if (send_appdefined)
6745 ns_send_appdefined (-1);
6746 }
6747
6748
6749 - (void)windowDidMiniaturize: sender
6750 {
6751 NSTRACE ("windowDidMiniaturize");
6752 if (!emacsframe->output_data.ns)
6753 return;
6754
6755 SET_FRAME_ICONIFIED (emacsframe, 1);
6756 SET_FRAME_VISIBLE (emacsframe, 0);
6757
6758 if (emacs_event)
6759 {
6760 emacs_event->kind = ICONIFY_EVENT;
6761 EV_TRAILER ((id)nil);
6762 }
6763 }
6764
6765 #ifdef HAVE_NATIVE_FS
6766 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6767 willUseFullScreenPresentationOptions:
6768 (NSApplicationPresentationOptions)proposedOptions
6769 {
6770 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6771 }
6772 #endif
6773
6774 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6775 {
6776 NSTRACE ("windowWillEnterFullScreen");
6777 fs_before_fs = fs_state;
6778 }
6779
6780 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6781 {
6782 NSTRACE ("windowDidEnterFullScreen");
6783 [self setFSValue: FULLSCREEN_BOTH];
6784 if (! [self fsIsNative])
6785 {
6786 [self windowDidBecomeKey:notification];
6787 [nonfs_window orderOut:self];
6788 }
6789 else
6790 {
6791 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6792 #ifdef NS_IMPL_COCOA
6793 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6794 unsigned val = (unsigned)[NSApp presentationOptions];
6795
6796 // OSX 10.7 bug fix, the menu won't appear without this.
6797 // val is non-zero on other OSX versions.
6798 if (val == 0)
6799 {
6800 NSApplicationPresentationOptions options
6801 = NSApplicationPresentationAutoHideDock
6802 | NSApplicationPresentationAutoHideMenuBar
6803 | NSApplicationPresentationFullScreen
6804 | NSApplicationPresentationAutoHideToolbar;
6805
6806 [NSApp setPresentationOptions: options];
6807 }
6808 #endif
6809 #endif
6810 [toolbar setVisible:tbar_visible];
6811 }
6812 }
6813
6814 - (void)windowWillExitFullScreen:(NSNotification *)notification
6815 {
6816 NSTRACE ("windowWillExitFullScreen");
6817
6818 if (next_maximized != -1)
6819 fs_before_fs = next_maximized;
6820 }
6821
6822 - (void)windowDidExitFullScreen:(NSNotification *)notification
6823 {
6824 NSTRACE ("windowDidExitFullScreen");
6825
6826 [self setFSValue: fs_before_fs];
6827 fs_before_fs = -1;
6828 #ifdef HAVE_NATIVE_FS
6829 [self updateCollectionBehavior];
6830 #endif
6831 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6832 {
6833 [toolbar setVisible:YES];
6834 update_frame_tool_bar (emacsframe);
6835 [self updateFrameSize:YES];
6836 [[self window] display];
6837 }
6838 else
6839 [toolbar setVisible:NO];
6840
6841 if (next_maximized != -1)
6842 [[self window] performZoom:self];
6843 }
6844
6845 - (BOOL)fsIsNative
6846 {
6847 return fs_is_native;
6848 }
6849
6850 - (BOOL)isFullscreen
6851 {
6852 if (! fs_is_native) return nonfs_window != nil;
6853 #ifdef HAVE_NATIVE_FS
6854 return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6855 #else
6856 return NO;
6857 #endif
6858 }
6859
6860 #ifdef HAVE_NATIVE_FS
6861 - (void)updateCollectionBehavior
6862 {
6863 if (! [self isFullscreen])
6864 {
6865 NSWindow *win = [self window];
6866 NSWindowCollectionBehavior b = [win collectionBehavior];
6867 if (ns_use_native_fullscreen)
6868 b |= NSWindowCollectionBehaviorFullScreenPrimary;
6869 else
6870 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6871
6872 [win setCollectionBehavior: b];
6873 fs_is_native = ns_use_native_fullscreen;
6874 }
6875 }
6876 #endif
6877
6878 - (void)toggleFullScreen: (id)sender
6879 {
6880 NSWindow *w, *fw;
6881 BOOL onFirstScreen;
6882 struct frame *f;
6883 NSRect r, wr;
6884 NSColor *col;
6885
6886 NSTRACE ("toggleFullScreen");
6887
6888 if (fs_is_native)
6889 {
6890 #ifdef HAVE_NATIVE_FS
6891 [[self window] toggleFullScreen:sender];
6892 #endif
6893 return;
6894 }
6895
6896 w = [self window];
6897 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6898 f = emacsframe;
6899 wr = [w frame];
6900 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6901 (FRAME_DEFAULT_FACE (f)),
6902 f);
6903
6904 if (fs_state != FULLSCREEN_BOTH)
6905 {
6906 NSScreen *screen = [w screen];
6907
6908 #if defined (NS_IMPL_COCOA) && \
6909 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6910 /* Hide ghost menu bar on secondary monitor? */
6911 if (! onFirstScreen)
6912 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6913 #endif
6914 /* Hide dock and menubar if we are on the primary screen. */
6915 if (onFirstScreen)
6916 {
6917 #ifdef NS_IMPL_COCOA
6918 NSApplicationPresentationOptions options
6919 = NSApplicationPresentationAutoHideDock
6920 | NSApplicationPresentationAutoHideMenuBar;
6921
6922 [NSApp setPresentationOptions: options];
6923 #else
6924 [NSMenu setMenuBarVisible:NO];
6925 #endif
6926 }
6927
6928 fw = [[EmacsFSWindow alloc]
6929 initWithContentRect:[w contentRectForFrameRect:wr]
6930 styleMask:NSBorderlessWindowMask
6931 backing:NSBackingStoreBuffered
6932 defer:YES
6933 screen:screen];
6934
6935 [fw setContentView:[w contentView]];
6936 [fw setTitle:[w title]];
6937 [fw setDelegate:self];
6938 [fw setAcceptsMouseMovedEvents: YES];
6939 #if !defined (NS_IMPL_COCOA) || \
6940 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6941 [fw useOptimizedDrawing: YES];
6942 #endif
6943 [fw setBackgroundColor: col];
6944 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6945 [fw setOpaque: NO];
6946
6947 f->border_width = 0;
6948 FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6949 tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6950 FRAME_TOOLBAR_HEIGHT (f) = 0;
6951
6952 nonfs_window = w;
6953
6954 [self windowWillEnterFullScreen:nil];
6955 [fw makeKeyAndOrderFront:NSApp];
6956 [fw makeFirstResponder:self];
6957 [w orderOut:self];
6958 r = [fw frameRectForContentRect:[screen frame]];
6959 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6960 [self windowDidEnterFullScreen:nil];
6961 [fw display];
6962 }
6963 else
6964 {
6965 fw = w;
6966 w = nonfs_window;
6967 nonfs_window = nil;
6968
6969 if (onFirstScreen)
6970 {
6971 #ifdef NS_IMPL_COCOA
6972 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6973 #else
6974 [NSMenu setMenuBarVisible:YES];
6975 #endif
6976 }
6977
6978 [w setContentView:[fw contentView]];
6979 [w setBackgroundColor: col];
6980 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6981 [w setOpaque: NO];
6982
6983 f->border_width = bwidth;
6984 FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6985 if (FRAME_EXTERNAL_TOOL_BAR (f))
6986 FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6987
6988 [self windowWillExitFullScreen:nil];
6989 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6990 [fw close];
6991 [w makeKeyAndOrderFront:NSApp];
6992 [self windowDidExitFullScreen:nil];
6993 [self updateFrameSize:YES];
6994 }
6995 }
6996
6997 - (void)handleFS
6998 {
6999 NSTRACE ("handleFS");
7000
7001 if (fs_state != emacsframe->want_fullscreen)
7002 {
7003 if (fs_state == FULLSCREEN_BOTH)
7004 {
7005 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7006 [self toggleFullScreen:self];
7007 }
7008
7009 switch (emacsframe->want_fullscreen)
7010 {
7011 case FULLSCREEN_BOTH:
7012 NSTRACE_MSG ("FULLSCREEN_BOTH");
7013 [self toggleFullScreen:self];
7014 break;
7015 case FULLSCREEN_WIDTH:
7016 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7017 next_maximized = FULLSCREEN_WIDTH;
7018 if (fs_state != FULLSCREEN_BOTH)
7019 [[self window] performZoom:self];
7020 break;
7021 case FULLSCREEN_HEIGHT:
7022 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7023 next_maximized = FULLSCREEN_HEIGHT;
7024 if (fs_state != FULLSCREEN_BOTH)
7025 [[self window] performZoom:self];
7026 break;
7027 case FULLSCREEN_MAXIMIZED:
7028 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7029 next_maximized = FULLSCREEN_MAXIMIZED;
7030 if (fs_state != FULLSCREEN_BOTH)
7031 [[self window] performZoom:self];
7032 break;
7033 case FULLSCREEN_NONE:
7034 NSTRACE_MSG ("FULLSCREEN_NONE");
7035 if (fs_state != FULLSCREEN_BOTH)
7036 {
7037 next_maximized = FULLSCREEN_NONE;
7038 [[self window] performZoom:self];
7039 }
7040 break;
7041 }
7042
7043 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7044 }
7045
7046 }
7047
7048 - (void) setFSValue: (int)value
7049 {
7050 NSTRACE ("setFSValue");
7051 NSTRACE_FSTYPE ("value", value);
7052
7053 Lisp_Object lval = Qnil;
7054 switch (value)
7055 {
7056 case FULLSCREEN_BOTH:
7057 lval = Qfullboth;
7058 break;
7059 case FULLSCREEN_WIDTH:
7060 lval = Qfullwidth;
7061 break;
7062 case FULLSCREEN_HEIGHT:
7063 lval = Qfullheight;
7064 break;
7065 case FULLSCREEN_MAXIMIZED:
7066 lval = Qmaximized;
7067 break;
7068 }
7069 store_frame_param (emacsframe, Qfullscreen, lval);
7070 fs_state = value;
7071 }
7072
7073 - (void)mouseEntered: (NSEvent *)theEvent
7074 {
7075 NSTRACE ("mouseEntered");
7076 if (emacsframe)
7077 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7078 = EV_TIMESTAMP (theEvent);
7079 }
7080
7081
7082 - (void)mouseExited: (NSEvent *)theEvent
7083 {
7084 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7085
7086 NSTRACE ("mouseExited");
7087
7088 if (!hlinfo)
7089 return;
7090
7091 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7092 = EV_TIMESTAMP (theEvent);
7093
7094 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7095 {
7096 clear_mouse_face (hlinfo);
7097 hlinfo->mouse_face_mouse_frame = 0;
7098 }
7099 }
7100
7101
7102 - menuDown: sender
7103 {
7104 NSTRACE ("menuDown");
7105 if (context_menu_value == -1)
7106 context_menu_value = [sender tag];
7107 else
7108 {
7109 NSInteger tag = [sender tag];
7110 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7111 emacsframe->menu_bar_vector,
7112 (void *)tag);
7113 }
7114
7115 ns_send_appdefined (-1);
7116 return self;
7117 }
7118
7119
7120 - (EmacsToolbar *)toolbar
7121 {
7122 return toolbar;
7123 }
7124
7125
7126 /* this gets called on toolbar button click */
7127 - toolbarClicked: (id)item
7128 {
7129 NSEvent *theEvent;
7130 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7131
7132 NSTRACE ("toolbarClicked");
7133
7134 if (!emacs_event)
7135 return self;
7136
7137 /* send first event (for some reason two needed) */
7138 theEvent = [[self window] currentEvent];
7139 emacs_event->kind = TOOL_BAR_EVENT;
7140 XSETFRAME (emacs_event->arg, emacsframe);
7141 EV_TRAILER (theEvent);
7142
7143 emacs_event->kind = TOOL_BAR_EVENT;
7144 /* XSETINT (emacs_event->code, 0); */
7145 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7146 idx + TOOL_BAR_ITEM_KEY);
7147 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7148 EV_TRAILER (theEvent);
7149 return self;
7150 }
7151
7152
7153 - toggleToolbar: (id)sender
7154 {
7155 if (!emacs_event)
7156 return self;
7157
7158 emacs_event->kind = NS_NONKEY_EVENT;
7159 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7160 EV_TRAILER ((id)nil);
7161 return self;
7162 }
7163
7164
7165 - (void)drawRect: (NSRect)rect
7166 {
7167 int x = NSMinX (rect), y = NSMinY (rect);
7168 int width = NSWidth (rect), height = NSHeight (rect);
7169
7170 NSTRACE ("drawRect");
7171 NSTRACE_RECT ("input", rect);
7172
7173 if (!emacsframe || !emacsframe->output_data.ns)
7174 return;
7175
7176 ns_clear_frame_area (emacsframe, x, y, width, height);
7177 block_input ();
7178 expose_frame (emacsframe, x, y, width, height);
7179 unblock_input ();
7180
7181 /*
7182 drawRect: may be called (at least in OS X 10.5) for invisible
7183 views as well for some reason. Thus, do not infer visibility
7184 here.
7185
7186 emacsframe->async_visible = 1;
7187 emacsframe->async_iconified = 0;
7188 */
7189 }
7190
7191
7192 /* NSDraggingDestination protocol methods. Actually this is not really a
7193 protocol, but a category of Object. O well... */
7194
7195 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7196 {
7197 NSTRACE ("draggingEntered");
7198 return NSDragOperationGeneric;
7199 }
7200
7201
7202 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7203 {
7204 return YES;
7205 }
7206
7207
7208 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7209 {
7210 id pb;
7211 int x, y;
7212 NSString *type;
7213 NSEvent *theEvent = [[self window] currentEvent];
7214 NSPoint position;
7215 NSDragOperation op = [sender draggingSourceOperationMask];
7216 int modifiers = 0;
7217
7218 NSTRACE ("performDragOperation");
7219
7220 if (!emacs_event)
7221 return NO;
7222
7223 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7224 x = lrint (position.x); y = lrint (position.y);
7225
7226 pb = [sender draggingPasteboard];
7227 type = [pb availableTypeFromArray: ns_drag_types];
7228
7229 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7230 // URL drags contain all operations (0xf), don't allow all to be set.
7231 (op & 0xf) != 0xf)
7232 {
7233 if (op & NSDragOperationLink)
7234 modifiers |= NSControlKeyMask;
7235 if (op & NSDragOperationCopy)
7236 modifiers |= NSAlternateKeyMask;
7237 if (op & NSDragOperationGeneric)
7238 modifiers |= NSCommandKeyMask;
7239 }
7240
7241 modifiers = EV_MODIFIERS2 (modifiers);
7242 if (type == 0)
7243 {
7244 return NO;
7245 }
7246 else if ([type isEqualToString: NSFilenamesPboardType])
7247 {
7248 NSArray *files;
7249 NSEnumerator *fenum;
7250 NSString *file;
7251
7252 if (!(files = [pb propertyListForType: type]))
7253 return NO;
7254
7255 fenum = [files objectEnumerator];
7256 while ( (file = [fenum nextObject]) )
7257 {
7258 emacs_event->kind = DRAG_N_DROP_EVENT;
7259 XSETINT (emacs_event->x, x);
7260 XSETINT (emacs_event->y, y);
7261 ns_input_file = append2 (ns_input_file,
7262 build_string ([file UTF8String]));
7263 emacs_event->modifiers = modifiers;
7264 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7265 EV_TRAILER (theEvent);
7266 }
7267 return YES;
7268 }
7269 else if ([type isEqualToString: NSURLPboardType])
7270 {
7271 NSURL *url = [NSURL URLFromPasteboard: pb];
7272 if (url == nil) return NO;
7273
7274 emacs_event->kind = DRAG_N_DROP_EVENT;
7275 XSETINT (emacs_event->x, x);
7276 XSETINT (emacs_event->y, y);
7277 emacs_event->modifiers = modifiers;
7278 emacs_event->arg = list2 (Qurl,
7279 build_string ([[url absoluteString]
7280 UTF8String]));
7281 EV_TRAILER (theEvent);
7282
7283 if ([url isFileURL] != NO)
7284 {
7285 NSString *file = [url path];
7286 ns_input_file = append2 (ns_input_file,
7287 build_string ([file UTF8String]));
7288 }
7289 return YES;
7290 }
7291 else if ([type isEqualToString: NSStringPboardType]
7292 || [type isEqualToString: NSTabularTextPboardType])
7293 {
7294 NSString *data;
7295
7296 if (! (data = [pb stringForType: type]))
7297 return NO;
7298
7299 emacs_event->kind = DRAG_N_DROP_EVENT;
7300 XSETINT (emacs_event->x, x);
7301 XSETINT (emacs_event->y, y);
7302 emacs_event->modifiers = modifiers;
7303 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7304 EV_TRAILER (theEvent);
7305 return YES;
7306 }
7307 else
7308 {
7309 fprintf (stderr, "Invalid data type in dragging pasteboard");
7310 return NO;
7311 }
7312 }
7313
7314
7315 - (id) validRequestorForSendType: (NSString *)typeSent
7316 returnType: (NSString *)typeReturned
7317 {
7318 NSTRACE ("validRequestorForSendType");
7319 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7320 && typeReturned == nil)
7321 {
7322 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7323 return self;
7324 }
7325
7326 return [super validRequestorForSendType: typeSent
7327 returnType: typeReturned];
7328 }
7329
7330
7331 /* The next two methods are part of NSServicesRequests informal protocol,
7332 supposedly called when a services menu item is chosen from this app.
7333 But this should not happen because we override the services menu with our
7334 own entries which call ns-perform-service.
7335 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7336 So let's at least stub them out until further investigation can be done. */
7337
7338 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7339 {
7340 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7341 be written into the buffer in place of the existing selection..
7342 ordinary service calls go through functions defined in ns-win.el */
7343 return NO;
7344 }
7345
7346 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7347 {
7348 NSArray *typesDeclared;
7349 Lisp_Object val;
7350
7351 /* We only support NSStringPboardType */
7352 if ([types containsObject:NSStringPboardType] == NO) {
7353 return NO;
7354 }
7355
7356 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7357 if (CONSP (val) && SYMBOLP (XCAR (val)))
7358 {
7359 val = XCDR (val);
7360 if (CONSP (val) && NILP (XCDR (val)))
7361 val = XCAR (val);
7362 }
7363 if (! STRINGP (val))
7364 return NO;
7365
7366 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7367 [pb declareTypes:typesDeclared owner:nil];
7368 ns_string_to_pasteboard (pb, val);
7369 return YES;
7370 }
7371
7372
7373 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7374 (gives a miniaturized version of the window); currently we use the latter for
7375 frames whose active buffer doesn't correspond to any file
7376 (e.g., '*scratch*') */
7377 - setMiniwindowImage: (BOOL) setMini
7378 {
7379 id image = [[self window] miniwindowImage];
7380 NSTRACE ("setMiniwindowImage");
7381
7382 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7383 about "AppleDockIconEnabled" notwithstanding, however the set message
7384 below has its effect nonetheless. */
7385 if (image != emacsframe->output_data.ns->miniimage)
7386 {
7387 if (image && [image isKindOfClass: [EmacsImage class]])
7388 [image release];
7389 [[self window] setMiniwindowImage:
7390 setMini ? emacsframe->output_data.ns->miniimage : nil];
7391 }
7392
7393 return self;
7394 }
7395
7396
7397 - (void) setRows: (int) r andColumns: (int) c
7398 {
7399 rows = r;
7400 cols = c;
7401 }
7402
7403 - (int) fullscreenState
7404 {
7405 return fs_state;
7406 }
7407
7408 @end /* EmacsView */
7409
7410
7411
7412 /* ==========================================================================
7413
7414 EmacsWindow implementation
7415
7416 ========================================================================== */
7417
7418 @implementation EmacsWindow
7419
7420 #ifdef NS_IMPL_COCOA
7421 - (id)accessibilityAttributeValue:(NSString *)attribute
7422 {
7423 Lisp_Object str = Qnil;
7424 struct frame *f = SELECTED_FRAME ();
7425 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7426
7427 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7428 return NSAccessibilityTextFieldRole;
7429
7430 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7431 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7432 {
7433 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7434 }
7435 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7436 {
7437 if (! NILP (BVAR (curbuf, mark_active)))
7438 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7439
7440 if (NILP (str))
7441 {
7442 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7443 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7444 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7445
7446 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7447 str = make_uninit_multibyte_string (range, byte_range);
7448 else
7449 str = make_uninit_string (range);
7450 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7451 Is this a problem? */
7452 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7453 }
7454 }
7455
7456
7457 if (! NILP (str))
7458 {
7459 if (CONSP (str) && SYMBOLP (XCAR (str)))
7460 {
7461 str = XCDR (str);
7462 if (CONSP (str) && NILP (XCDR (str)))
7463 str = XCAR (str);
7464 }
7465 if (STRINGP (str))
7466 {
7467 const char *utfStr = SSDATA (str);
7468 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7469 return nsStr;
7470 }
7471 }
7472
7473 return [super accessibilityAttributeValue:attribute];
7474 }
7475 #endif /* NS_IMPL_COCOA */
7476
7477 /* Constrain size and placement of a frame.
7478
7479 By returning the original "frameRect", the frame is not
7480 contrained. This can lead to unwanted situations where, for
7481 example, the menu bar covers the frame.
7482
7483 The default implementation (accessed using "super") constrains the
7484 frame to the visible area of SCREEN, minus the menu bar (if
7485 present) and the Dock. Note that default implementation also calls
7486 windowWillResize, with the frame it thinks should have. (This can
7487 make the frame exit maximized mode.)
7488
7489 Note that this should work in situations where multiple monitors
7490 are present. Common configurations are side-by-side monitors and a
7491 monitor on top of another (e.g. when a laptop is placed under a
7492 large screen). */
7493 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7494 {
7495 NSTRACE ("constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:",
7496 NSTRACE_ARG_RECT (frameRect));
7497
7498 #ifdef NS_IMPL_COCOA
7499 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7500 // If separate spaces is on, it is like each screen is independent. There is
7501 // no spanning of frames across screens.
7502 if ([NSScreen screensHaveSeparateSpaces])
7503 {
7504 NSTRACE_MSG ("Screens have separate spaces");
7505 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7506 NSTRACE_RETURN_RECT (frameRect);
7507 return frameRect;
7508 }
7509 #endif
7510 #endif
7511
7512 return constrain_frame_rect(frameRect);
7513 }
7514
7515
7516 - (void)performZoom:(id)sender
7517 {
7518 NSTRACE ("performZoom");
7519
7520 return [super performZoom:sender];
7521 }
7522
7523 - (void)zoom:(id)sender
7524 {
7525 struct frame * f = SELECTED_FRAME ();
7526
7527 NSTRACE ("zoom");
7528
7529 ns_update_auto_hide_menu_bar();
7530
7531 // Below are three zoom implementations. In the final commit, the
7532 // idea is that the last should be included.
7533
7534 #if 0
7535 // Native zoom done using the standard zoom animation. Size of the
7536 // resulting frame reduced to accomodate the Dock and, if present,
7537 // the menu-bar.
7538 [super zoom:sender];
7539
7540 #elsif 0
7541 // Native zoom done using the standard zoom animation, plus an
7542 // explicit resize to cover the full screen.
7543 [super zoom:sender];
7544
7545 // After the native zoom, resize the resulting frame to fill the
7546 // entire screen, except the menu-bar.
7547 //
7548 // This works for all practical purposes. (The only minor oddity is
7549 // when transiting from full-height frame to a maximized, the
7550 // animation reduces the height of the frame slighty (to the 4
7551 // pixels needed to accomodate the Doc) before it snaps back into
7552 // full height. The user would need a very trained eye to spot
7553 // this.)
7554 NSScreen * screen = [self screen];
7555 if (screen != nil)
7556 {
7557 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7558
7559 NSTRACE_FSTYPE ("fullscreenState", fs_state);
7560
7561 NSRect sr = [screen frame];
7562 NSRect wr = [self frame];
7563 NSTRACE_RECT ("Rect after zoom", wr);
7564
7565 NSRect newWr = wr;
7566
7567 if (fs_state == FULLSCREEN_MAXIMIZED
7568 || fs_state == FULLSCREEN_HEIGHT)
7569 {
7570 newWr.origin.x = 0;
7571 newWr.size.height = sr.size.height - ns_menu_bar_height(screen);
7572 }
7573
7574 if (fs_state == FULLSCREEN_MAXIMIZED
7575 || fs_state == FULLSCREEN_WIDTH)
7576 {
7577 newWr.origin.y = 0;
7578 newWr.size.width = sr.size.width;
7579 }
7580
7581 if (newWr.size.width != wr.size.width
7582 || newWr.size.height != wr.size.height
7583 || newWr.origin.x != wr.origin.x
7584 || newWr.origin.y != wr.origin.y)
7585 {
7586 NSTRACE_RECT ("Corrected rect", newWr);
7587 [self setFrame: newWr display: NO];
7588 }
7589 }
7590 #else
7591 // Non-native zoom which is done instantaneous. The resulting frame
7592 // covert the entire scrren, except the menu-bar, if present.
7593 NSScreen * screen = [self screen];
7594 if (screen != nil)
7595 {
7596 NSRect sr = [screen frame];
7597 sr.size.height -= ns_menu_bar_height (screen);
7598
7599 sr = [[self delegate] windowWillUseStandardFrame:self
7600 defaultFrame:sr];
7601 [self setFrame: sr display: NO];
7602 }
7603 #endif
7604 }
7605
7606 @end /* EmacsWindow */
7607
7608
7609 @implementation EmacsFSWindow
7610
7611 - (BOOL)canBecomeKeyWindow
7612 {
7613 return YES;
7614 }
7615
7616 - (BOOL)canBecomeMainWindow
7617 {
7618 return YES;
7619 }
7620
7621 @end
7622
7623 /* ==========================================================================
7624
7625 EmacsScroller implementation
7626
7627 ========================================================================== */
7628
7629
7630 @implementation EmacsScroller
7631
7632 /* for repeat button push */
7633 #define SCROLL_BAR_FIRST_DELAY 0.5
7634 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7635
7636 + (CGFloat) scrollerWidth
7637 {
7638 /* TODO: if we want to allow variable widths, this is the place to do it,
7639 however neither GNUstep nor Cocoa support it very well */
7640 CGFloat r;
7641 #if !defined (NS_IMPL_COCOA) || \
7642 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7643 r = [NSScroller scrollerWidth];
7644 #else
7645 r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7646 scrollerStyle: NSScrollerStyleLegacy];
7647 #endif
7648 return r;
7649 }
7650
7651
7652 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7653 {
7654 NSTRACE ("EmacsScroller_initFrame");
7655
7656 r.size.width = [EmacsScroller scrollerWidth];
7657 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7658 [self setContinuous: YES];
7659 [self setEnabled: YES];
7660
7661 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7662 locked against the top and bottom edges, and right edge on OS X, where
7663 scrollers are on right. */
7664 #ifdef NS_IMPL_GNUSTEP
7665 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7666 #else
7667 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7668 #endif
7669
7670 window = XWINDOW (nwin);
7671 condemned = NO;
7672 pixel_height = NSHeight (r);
7673 if (pixel_height == 0) pixel_height = 1;
7674 min_portion = 20 / pixel_height;
7675
7676 frame = XFRAME (window->frame);
7677 if (FRAME_LIVE_P (frame))
7678 {
7679 int i;
7680 EmacsView *view = FRAME_NS_VIEW (frame);
7681 NSView *sview = [[view window] contentView];
7682 NSArray *subs = [sview subviews];
7683
7684 /* disable optimization stopping redraw of other scrollbars */
7685 view->scrollbarsNeedingUpdate = 0;
7686 for (i =[subs count]-1; i >= 0; i--)
7687 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7688 view->scrollbarsNeedingUpdate++;
7689 [sview addSubview: self];
7690 }
7691
7692 /* [self setFrame: r]; */
7693
7694 return self;
7695 }
7696
7697
7698 - (void)setFrame: (NSRect)newRect
7699 {
7700 NSTRACE ("EmacsScroller_setFrame");
7701 /* block_input (); */
7702 pixel_height = NSHeight (newRect);
7703 if (pixel_height == 0) pixel_height = 1;
7704 min_portion = 20 / pixel_height;
7705 [super setFrame: newRect];
7706 /* unblock_input (); */
7707 }
7708
7709
7710 - (void)dealloc
7711 {
7712 NSTRACE ("EmacsScroller_dealloc");
7713 if (window)
7714 wset_vertical_scroll_bar (window, Qnil);
7715 window = 0;
7716 [super dealloc];
7717 }
7718
7719
7720 - condemn
7721 {
7722 NSTRACE ("condemn");
7723 condemned =YES;
7724 return self;
7725 }
7726
7727
7728 - reprieve
7729 {
7730 NSTRACE ("reprieve");
7731 condemned =NO;
7732 return self;
7733 }
7734
7735
7736 -(bool)judge
7737 {
7738 NSTRACE ("judge");
7739 bool ret = condemned;
7740 if (condemned)
7741 {
7742 EmacsView *view;
7743 block_input ();
7744 /* ensure other scrollbar updates after deletion */
7745 view = (EmacsView *)FRAME_NS_VIEW (frame);
7746 if (view != nil)
7747 view->scrollbarsNeedingUpdate++;
7748 if (window)
7749 wset_vertical_scroll_bar (window, Qnil);
7750 window = 0;
7751 [self removeFromSuperview];
7752 [self release];
7753 unblock_input ();
7754 }
7755 return ret;
7756 }
7757
7758
7759 - (void)resetCursorRects
7760 {
7761 NSRect visible = [self visibleRect];
7762 NSTRACE ("resetCursorRects");
7763
7764 if (!NSIsEmptyRect (visible))
7765 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7766 [[NSCursor arrowCursor] setOnMouseEntered: YES];
7767 }
7768
7769
7770 - (int) checkSamePosition: (int) position portion: (int) portion
7771 whole: (int) whole
7772 {
7773 return em_position ==position && em_portion ==portion && em_whole ==whole
7774 && portion != whole; /* needed for resize empty buf */
7775 }
7776
7777
7778 - setPosition: (int)position portion: (int)portion whole: (int)whole
7779 {
7780 NSTRACE ("setPosition");
7781
7782 em_position = position;
7783 em_portion = portion;
7784 em_whole = whole;
7785
7786 if (portion >= whole)
7787 {
7788 #ifdef NS_IMPL_COCOA
7789 [self setKnobProportion: 1.0];
7790 [self setDoubleValue: 1.0];
7791 #else
7792 [self setFloatValue: 0.0 knobProportion: 1.0];
7793 #endif
7794 }
7795 else
7796 {
7797 float pos;
7798 CGFloat por;
7799 portion = max ((float)whole*min_portion/pixel_height, portion);
7800 pos = (float)position / (whole - portion);
7801 por = (CGFloat)portion/whole;
7802 #ifdef NS_IMPL_COCOA
7803 [self setKnobProportion: por];
7804 [self setDoubleValue: pos];
7805 #else
7806 [self setFloatValue: pos knobProportion: por];
7807 #endif
7808 }
7809
7810 return self;
7811 }
7812
7813 /* set up emacs_event */
7814 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7815 {
7816 Lisp_Object win;
7817 if (!emacs_event)
7818 return;
7819
7820 emacs_event->part = last_hit_part;
7821 emacs_event->code = 0;
7822 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7823 XSETWINDOW (win, window);
7824 emacs_event->frame_or_window = win;
7825 emacs_event->timestamp = EV_TIMESTAMP (e);
7826 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7827 emacs_event->arg = Qnil;
7828 XSETINT (emacs_event->x, loc * pixel_height);
7829 XSETINT (emacs_event->y, pixel_height-20);
7830
7831 if (q_event_ptr)
7832 {
7833 n_emacs_events_pending++;
7834 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7835 }
7836 else
7837 hold_event (emacs_event);
7838 EVENT_INIT (*emacs_event);
7839 ns_send_appdefined (-1);
7840 }
7841
7842
7843 /* called manually thru timer to implement repeated button action w/hold-down */
7844 - repeatScroll: (NSTimer *)scrollEntry
7845 {
7846 NSEvent *e = [[self window] currentEvent];
7847 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
7848 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7849
7850 /* clear timer if need be */
7851 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7852 {
7853 [scroll_repeat_entry invalidate];
7854 [scroll_repeat_entry release];
7855 scroll_repeat_entry = nil;
7856
7857 if (inKnob)
7858 return self;
7859
7860 scroll_repeat_entry
7861 = [[NSTimer scheduledTimerWithTimeInterval:
7862 SCROLL_BAR_CONTINUOUS_DELAY
7863 target: self
7864 selector: @selector (repeatScroll:)
7865 userInfo: 0
7866 repeats: YES]
7867 retain];
7868 }
7869
7870 [self sendScrollEventAtLoc: 0 fromEvent: e];
7871 return self;
7872 }
7873
7874
7875 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
7876 mouseDragged events without going into a modal loop. */
7877 - (void)mouseDown: (NSEvent *)e
7878 {
7879 NSRect sr, kr;
7880 /* hitPart is only updated AFTER event is passed on */
7881 NSScrollerPart part = [self testPart: [e locationInWindow]];
7882 CGFloat inc = 0.0, loc, kloc, pos;
7883 int edge = 0;
7884
7885 NSTRACE ("EmacsScroller_mouseDown");
7886
7887 switch (part)
7888 {
7889 case NSScrollerDecrementPage:
7890 last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7891 case NSScrollerIncrementPage:
7892 last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7893 case NSScrollerDecrementLine:
7894 last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7895 case NSScrollerIncrementLine:
7896 last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7897 case NSScrollerKnob:
7898 last_hit_part = scroll_bar_handle; break;
7899 case NSScrollerKnobSlot: /* GNUstep-only */
7900 last_hit_part = scroll_bar_move_ratio; break;
7901 default: /* NSScrollerNoPart? */
7902 fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7903 (long) part);
7904 return;
7905 }
7906
7907 if (inc != 0.0)
7908 {
7909 pos = 0; /* ignored */
7910
7911 /* set a timer to repeat, as we can't let superclass do this modally */
7912 scroll_repeat_entry
7913 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7914 target: self
7915 selector: @selector (repeatScroll:)
7916 userInfo: 0
7917 repeats: YES]
7918 retain];
7919 }
7920 else
7921 {
7922 /* handle, or on GNUstep possibly slot */
7923 NSEvent *fake_event;
7924
7925 /* compute float loc in slot and mouse offset on knob */
7926 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7927 toView: nil];
7928 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7929 if (loc <= 0.0)
7930 {
7931 loc = 0.0;
7932 edge = -1;
7933 }
7934 else if (loc >= NSHeight (sr))
7935 {
7936 loc = NSHeight (sr);
7937 edge = 1;
7938 }
7939
7940 if (edge)
7941 kloc = 0.5 * edge;
7942 else
7943 {
7944 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7945 toView: nil];
7946 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7947 }
7948 last_mouse_offset = kloc;
7949
7950 /* if knob, tell emacs a location offset by knob pos
7951 (to indicate top of handle) */
7952 if (part == NSScrollerKnob)
7953 pos = (loc - last_mouse_offset) / NSHeight (sr);
7954 else
7955 /* else this is a slot click on GNUstep: go straight there */
7956 pos = loc / NSHeight (sr);
7957
7958 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7959 fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7960 location: [e locationInWindow]
7961 modifierFlags: [e modifierFlags]
7962 timestamp: [e timestamp]
7963 windowNumber: [e windowNumber]
7964 context: [e context]
7965 eventNumber: [e eventNumber]
7966 clickCount: [e clickCount]
7967 pressure: [e pressure]];
7968 [super mouseUp: fake_event];
7969 }
7970
7971 if (part != NSScrollerKnob)
7972 [self sendScrollEventAtLoc: pos fromEvent: e];
7973 }
7974
7975
7976 /* Called as we manually track scroller drags, rather than superclass. */
7977 - (void)mouseDragged: (NSEvent *)e
7978 {
7979 NSRect sr;
7980 double loc, pos;
7981
7982 NSTRACE ("EmacsScroller_mouseDragged");
7983
7984 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7985 toView: nil];
7986 loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7987
7988 if (loc <= 0.0)
7989 {
7990 loc = 0.0;
7991 }
7992 else if (loc >= NSHeight (sr) + last_mouse_offset)
7993 {
7994 loc = NSHeight (sr) + last_mouse_offset;
7995 }
7996
7997 pos = (loc - last_mouse_offset) / NSHeight (sr);
7998 [self sendScrollEventAtLoc: pos fromEvent: e];
7999 }
8000
8001
8002 - (void)mouseUp: (NSEvent *)e
8003 {
8004 if (scroll_repeat_entry)
8005 {
8006 [scroll_repeat_entry invalidate];
8007 [scroll_repeat_entry release];
8008 scroll_repeat_entry = nil;
8009 }
8010 last_hit_part = scroll_bar_above_handle;
8011 }
8012
8013
8014 /* treat scrollwheel events in the bar as though they were in the main window */
8015 - (void) scrollWheel: (NSEvent *)theEvent
8016 {
8017 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8018 [view mouseDown: theEvent];
8019 }
8020
8021 @end /* EmacsScroller */
8022
8023
8024 #ifdef NS_IMPL_GNUSTEP
8025 /* Dummy class to get rid of startup warnings. */
8026 @implementation EmacsDocument
8027
8028 @end
8029 #endif
8030
8031
8032 /* ==========================================================================
8033
8034 Font-related functions; these used to be in nsfaces.m
8035
8036 ========================================================================== */
8037
8038
8039 Lisp_Object
8040 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8041 {
8042 struct font *font = XFONT_OBJECT (font_object);
8043 EmacsView *view = FRAME_NS_VIEW (f);
8044 int font_ascent, font_descent;
8045
8046 if (fontset < 0)
8047 fontset = fontset_from_font (font_object);
8048 FRAME_FONTSET (f) = fontset;
8049
8050 if (FRAME_FONT (f) == font)
8051 /* This font is already set in frame F. There's nothing more to
8052 do. */
8053 return font_object;
8054
8055 FRAME_FONT (f) = font;
8056
8057 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8058 FRAME_COLUMN_WIDTH (f) = font->average_width;
8059 get_font_ascent_descent (font, &font_ascent, &font_descent);
8060 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8061
8062 /* Compute the scroll bar width in character columns. */
8063 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8064 {
8065 int wid = FRAME_COLUMN_WIDTH (f);
8066 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8067 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8068 }
8069 else
8070 {
8071 int wid = FRAME_COLUMN_WIDTH (f);
8072 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8073 }
8074
8075 /* Compute the scroll bar height in character lines. */
8076 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8077 {
8078 int height = FRAME_LINE_HEIGHT (f);
8079 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8080 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8081 }
8082 else
8083 {
8084 int height = FRAME_LINE_HEIGHT (f);
8085 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8086 }
8087
8088 /* Now make the frame display the given font. */
8089 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8090 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8091 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8092 false, Qfont);
8093
8094 return font_object;
8095 }
8096
8097
8098 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8099 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8100 in 1.43. */
8101
8102 const char *
8103 ns_xlfd_to_fontname (const char *xlfd)
8104 /* --------------------------------------------------------------------------
8105 Convert an X font name (XLFD) to an NS font name.
8106 Only family is used.
8107 The string returned is temporarily allocated.
8108 -------------------------------------------------------------------------- */
8109 {
8110 char *name = xmalloc (180);
8111 int i, len;
8112 const char *ret;
8113
8114 if (!strncmp (xlfd, "--", 2))
8115 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8116 else
8117 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8118
8119 /* stopgap for malformed XLFD input */
8120 if (strlen (name) == 0)
8121 strcpy (name, "Monaco");
8122
8123 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8124 also uppercase after '-' or ' ' */
8125 name[0] = c_toupper (name[0]);
8126 for (len =strlen (name), i =0; i<len; i++)
8127 {
8128 if (name[i] == '$')
8129 {
8130 name[i] = '-';
8131 if (i+1<len)
8132 name[i+1] = c_toupper (name[i+1]);
8133 }
8134 else if (name[i] == '_')
8135 {
8136 name[i] = ' ';
8137 if (i+1<len)
8138 name[i+1] = c_toupper (name[i+1]);
8139 }
8140 }
8141 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8142 ret = [[NSString stringWithUTF8String: name] UTF8String];
8143 xfree (name);
8144 return ret;
8145 }
8146
8147
8148 void
8149 syms_of_nsterm (void)
8150 {
8151 NSTRACE ("syms_of_nsterm");
8152
8153 ns_antialias_threshold = 10.0;
8154
8155 /* from 23+ we need to tell emacs what modifiers there are.. */
8156 DEFSYM (Qmodifier_value, "modifier-value");
8157 DEFSYM (Qalt, "alt");
8158 DEFSYM (Qhyper, "hyper");
8159 DEFSYM (Qmeta, "meta");
8160 DEFSYM (Qsuper, "super");
8161 DEFSYM (Qcontrol, "control");
8162 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8163
8164 DEFSYM (Qfile, "file");
8165 DEFSYM (Qurl, "url");
8166
8167 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8168 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8169 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8170 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8171 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8172
8173 DEFVAR_LISP ("ns-input-file", ns_input_file,
8174 "The file specified in the last NS event.");
8175 ns_input_file =Qnil;
8176
8177 DEFVAR_LISP ("ns-working-text", ns_working_text,
8178 "String for visualizing working composition sequence.");
8179 ns_working_text =Qnil;
8180
8181 DEFVAR_LISP ("ns-input-font", ns_input_font,
8182 "The font specified in the last NS event.");
8183 ns_input_font =Qnil;
8184
8185 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8186 "The fontsize specified in the last NS event.");
8187 ns_input_fontsize =Qnil;
8188
8189 DEFVAR_LISP ("ns-input-line", ns_input_line,
8190 "The line specified in the last NS event.");
8191 ns_input_line =Qnil;
8192
8193 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8194 "The service name specified in the last NS event.");
8195 ns_input_spi_name =Qnil;
8196
8197 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8198 "The service argument specified in the last NS event.");
8199 ns_input_spi_arg =Qnil;
8200
8201 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8202 "This variable describes the behavior of the alternate or option key.\n\
8203 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8204 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8205 at all, allowing it to be used at a lower level for accented character entry.");
8206 ns_alternate_modifier = Qmeta;
8207
8208 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8209 "This variable describes the behavior of the right alternate or option key.\n\
8210 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8211 Set to left means be the same key as `ns-alternate-modifier'.\n\
8212 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8213 at all, allowing it to be used at a lower level for accented character entry.");
8214 ns_right_alternate_modifier = Qleft;
8215
8216 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8217 "This variable describes the behavior of the command key.\n\
8218 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8219 ns_command_modifier = Qsuper;
8220
8221 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8222 "This variable describes the behavior of the right command key.\n\
8223 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8224 Set to left means be the same key as `ns-command-modifier'.\n\
8225 Set to none means that the command / option key is not interpreted by Emacs\n\
8226 at all, allowing it to be used at a lower level for accented character entry.");
8227 ns_right_command_modifier = Qleft;
8228
8229 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8230 "This variable describes the behavior of the control key.\n\
8231 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8232 ns_control_modifier = Qcontrol;
8233
8234 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8235 "This variable describes the behavior of the right control key.\n\
8236 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8237 Set to left means be the same key as `ns-control-modifier'.\n\
8238 Set to none means that the control / option key is not interpreted by Emacs\n\
8239 at all, allowing it to be used at a lower level for accented character entry.");
8240 ns_right_control_modifier = Qleft;
8241
8242 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8243 "This variable describes the behavior of the function key (on laptops).\n\
8244 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8245 Set to none means that the function key is not interpreted by Emacs at all,\n\
8246 allowing it to be used at a lower level for accented character entry.");
8247 ns_function_modifier = Qnone;
8248
8249 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8250 "Non-nil (the default) means to render text antialiased.");
8251 ns_antialias_text = Qt;
8252
8253 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8254 "Whether to confirm application quit using dialog.");
8255 ns_confirm_quit = Qnil;
8256
8257 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8258 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8259 Only works on OSX 10.6 or later. */);
8260 ns_auto_hide_menu_bar = Qnil;
8261
8262 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8263 doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8264 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8265 multiple monitors, but lacks tool bar. This variable is ignored on OSX < 10.7.
8266 Default is t for OSX >= 10.7, nil otherwise. */);
8267 #ifdef HAVE_NATIVE_FS
8268 ns_use_native_fullscreen = YES;
8269 #else
8270 ns_use_native_fullscreen = NO;
8271 #endif
8272 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8273
8274 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8275 doc: /*Non-nil means use animation on non-native fullscreen.
8276 For native fullscreen, this does nothing.
8277 Default is nil. */);
8278 ns_use_fullscreen_animation = NO;
8279
8280 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8281 doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8282 Note that this does not apply to images.
8283 This variable is ignored on OSX < 10.7 and GNUstep. */);
8284 ns_use_srgb_colorspace = YES;
8285
8286 /* TODO: move to common code */
8287 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8288 doc: /* Which toolkit scroll bars Emacs uses, if any.
8289 A value of nil means Emacs doesn't use toolkit scroll bars.
8290 With the X Window system, the value is a symbol describing the
8291 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8292 With MS Windows or Nextstep, the value is t. */);
8293 Vx_toolkit_scroll_bars = Qt;
8294
8295 DEFVAR_BOOL ("x-use-underline-position-properties",
8296 x_use_underline_position_properties,
8297 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8298 A value of nil means ignore them. If you encounter fonts with bogus
8299 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8300 to 4.1, set this to nil. */);
8301 x_use_underline_position_properties = 0;
8302
8303 DEFVAR_BOOL ("x-underline-at-descent-line",
8304 x_underline_at_descent_line,
8305 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8306 A value of nil means to draw the underline according to the value of the
8307 variable `x-use-underline-position-properties', which is usually at the
8308 baseline level. The default value is nil. */);
8309 x_underline_at_descent_line = 0;
8310
8311 /* Tell Emacs about this window system. */
8312 Fprovide (Qns, Qnil);
8313
8314 DEFSYM (Qcocoa, "cocoa");
8315 DEFSYM (Qgnustep, "gnustep");
8316
8317 #ifdef NS_IMPL_COCOA
8318 Fprovide (Qcocoa, Qnil);
8319 syms_of_macfont ();
8320 #else
8321 Fprovide (Qgnustep, Qnil);
8322 syms_of_nsfont ();
8323 #endif
8324
8325 }