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