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