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