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