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