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