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