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