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