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