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