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