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