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