X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/8f50130c565eaf0ad7c49e4ad044c3291ecdfa71..ef884f239fea782ea5888d567b3c13c0b87ed5ea:/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m index 1d64594306..c75b17135e 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1,6 +1,7 @@ /* NeXT/Open/GNUstep / MacOSX communication module. - Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2011 - Free Software Foundation, Inc. + +Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -64,6 +65,7 @@ int term_trace_num = 0; #define NSTRACE(x) #endif +extern NSString *NSMenuDidBeginTrackingNotification; /* ========================================================================== @@ -181,7 +183,6 @@ static NSTimer *timed_entry = 0; static NSTimer *fd_entry = nil; static NSTimer *scroll_repeat_entry = nil; static fd_set select_readfds, t_readfds; -static struct timeval select_timeout; static int select_nfds; static NSAutoreleasePool *outerpool; static struct input_event *emacs_event = NULL; @@ -336,11 +337,18 @@ ns_init_paths (void) /*NSLog (@"loadPath: '%@'\n", resourcePaths); */ } + /* Normally, Emacs does not add its own bin/ directory to the PATH. + However, a self-contained NS build has a different layout, with + bin/ and libexec/ subdirectories in the directory that contains + Emacs.app itself. + We put libexec first, because init_callproc_1 uses the first + element to initialize exec-directory. An alternative would be + for init_callproc to check for invocation-directory/libexec. */ if (!getenv ("EMACSPATH")) { NSArray *paths = [binDir stringsByAppendingPaths: - [NSArray arrayWithObjects: @"bin", - @"lib-exec", nil]]; + [NSArray arrayWithObjects: @"libexec", + @"bin", nil]]; NSEnumerator *pathEnum = [paths objectEnumerator]; resourcePaths = @""; while (resourcePath = [pathEnum nextObject]) @@ -370,48 +378,6 @@ ns_init_paths (void) setenv ("EMACSDOC", [resourcePath UTF8String], 1); } } - - if (!getenv ("INFOPATH")) - { - resourcePath = [resourceDir stringByAppendingPathComponent: @"info"]; - if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir]) - if (isDir) - setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"] - UTF8String], 1); - /* Note, extra colon needed to cause merge w/later user additions. */ - } -} - - -static int -timeval_subtract (struct timeval *result, struct timeval x, struct timeval y) -/* -------------------------------------------------------------------------- - Subtract the `struct timeval' values X and Y, storing the result in RESULT. - Return 1 if the difference is negative, otherwise 0. - -------------------------------------------------------------------------- */ -{ - /* Perform the carry for the later subtraction by updating y. - This is safer because on some systems - the tv_sec member is unsigned. */ - if (x.tv_usec < y.tv_usec) - { - int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; - y.tv_usec -= 1000000 * nsec; - y.tv_sec += nsec; - } - if (x.tv_usec - y.tv_usec > 1000000) - { - int nsec = (y.tv_usec - x.tv_usec) / 1000000; - y.tv_usec += 1000000 * nsec; - y.tv_sec -= nsec; - } - - /* Compute the time remaining to wait. tv_usec is certainly positive. */ - result->tv_sec = x.tv_sec - y.tv_sec; - result->tv_usec = x.tv_usec - y.tv_usec; - - /* Return indication of whether the result should be considered negative. */ - return x.tv_sec < y.tv_sec; } static void @@ -420,29 +386,24 @@ ns_timeout (int usecs) Blocking timer utility used by ns_ring_bell -------------------------------------------------------------------------- */ { - struct timeval wakeup; + EMACS_TIME wakeup, delay; EMACS_GET_TIME (wakeup); - - /* Compute time to wait until, propagating carry from usecs. */ - wakeup.tv_usec += usecs; - wakeup.tv_sec += (wakeup.tv_usec / 1000000); - wakeup.tv_usec %= 1000000; + EMACS_SET_SECS_USECS (delay, 0, usecs); + EMACS_ADD_TIME (wakeup, wakeup, delay); /* Keep waiting until past the time wakeup. */ while (1) { - struct timeval timeout; + EMACS_TIME timeout; EMACS_GET_TIME (timeout); - - /* In effect, timeout = wakeup - timeout. - Break if result would be negative. */ - if (timeval_subtract (&timeout, wakeup, timeout)) + if (EMACS_TIME_LE (wakeup, timeout)) break; + EMACS_SUB_TIME (timeout, wakeup, timeout); /* Try to wait that long--but we might wake up sooner. */ - select (0, NULL, NULL, NULL, &timeout); + pselect (0, NULL, NULL, NULL, &timeout, NULL); } } @@ -1156,11 +1117,14 @@ x_free_frame_resources (struct frame *f) hlinfo->mouse_face_mouse_frame = 0; } - xfree (f->output_data.ns); + if (f->output_data.ns->miniimage != nil) + [f->output_data.ns->miniimage release]; [[view window] close]; [view release]; + xfree (f->output_data.ns); + UNBLOCK_INPUT; } @@ -1351,7 +1315,7 @@ ns_index_color (NSColor *color, struct frame *f) { struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table; ptrdiff_t idx; - NSNumber *index; + ptrdiff_t i; if (!color_table->colors) { @@ -1364,21 +1328,13 @@ ns_index_color (NSColor *color, struct frame *f) } /* do we already have this color ? */ - { - ptrdiff_t i; - for (i = 1; i < color_table->avail; i++) - { - if (color_table->colors[i] && [color_table->colors[i] isEqual: color]) - { - [color_table->colors[i] retain]; - return i; - } - } - } + for (i = 1; i < color_table->avail; i++) + if (color_table->colors[i] && [color_table->colors[i] isEqual: color]) + return i; if ([color_table->empty_indices count] > 0) { - index = [color_table->empty_indices anyObject]; + NSNumber *index = [color_table->empty_indices anyObject]; [color_table->empty_indices removeObject: index]; idx = [index unsignedLongValue]; } @@ -1411,20 +1367,20 @@ ns_free_indexed_color (unsigned long idx, struct frame *f) color_table = FRAME_NS_DISPLAY_INFO (f)->color_table; if (idx <= 0 || idx >= color_table->size) { - message1("ns_free_indexed_color: Color index out of range.\n"); + message1 ("ns_free_indexed_color: Color index out of range.\n"); return; } index = [NSNumber numberWithUnsignedInt: idx]; if ([color_table->empty_indices containsObject: index]) { - message1("ns_free_indexed_color: attempt to free already freed color.\n"); + message1 ("ns_free_indexed_color: attempt to free already freed color.\n"); return; } color = color_table->colors[idx]; [color release]; color_table->colors[idx] = nil; - [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]]; + [color_table->empty_indices addObject: index]; /*fprintf(stderr, "color_table: FREED %d\n",idx);*/ } @@ -2152,7 +2108,7 @@ ns_after_update_window_line (struct glyph_row *desired_row) NSTRACE (ns_after_update_window_line); /* begin copy from other terms */ - xassert (w); + eassert (w); if (!desired_row->mode_line_p && !w->pseudo_window_p) desired_row->redraw_fringe_bitmaps_p = 1; @@ -2601,6 +2557,60 @@ ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr) return n; } +/* -------------------------------------------------------------------- + Draw a wavy line under glyph string s. The wave fills wave_height + pixels from y. + + x wave_length = 3 + -- + y * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + --------------------------------------------------------------------- */ + +static void +ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x) +{ + int wave_height = 3, wave_length = 3; + int y, dx, dy, odd, xmax; + NSPoint a, b; + NSRect waveClip; + + dx = wave_length; + dy = wave_height - 1; + y = s->ybase + 1; + xmax = x + width; + + /* Find and set clipping rectangle */ + waveClip = NSMakeRect (x, y, width, wave_height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (waveClip); + + /* Draw the waves */ + a.x = x - ((int)(x) % dx); + b.x = a.x + dx; + odd = (int)(a.x/dx) % 2; + a.y = b.y = y; + + if (odd) + a.y += dy; + else + b.y += dy; + + while (a.x <= xmax) + { + [NSBezierPath strokeLineFromPoint:a toPoint:b]; + a.x = b.x, a.y = b.y; + b.x += dx, b.y = y + odd*dy; + odd = !odd; + } + + /* Restore previous clipping rectangle(s) */ + [[NSGraphicsContext currentContext] restoreGraphicsState]; +} + + + void ns_draw_text_decoration (struct glyph_string *s, struct face *face, NSColor *defaultCol, CGFloat width, CGFloat x) @@ -2614,63 +2624,75 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, /* Do underline. */ if (face->underline_p) { - NSRect r; - unsigned long thickness, position; - - /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->underline_thickness > 0) + if (s->face->underline_type == FACE_UNDER_WAVE) { - thickness = s->prev->underline_thickness; - position = s->prev->underline_position; + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + + ns_draw_underwave (s, width, x); } - else + else if (s->face->underline_type == FACE_UNDER_LINE) { - struct font *font; - unsigned long descent; - - font=s->font; - descent = s->y + s->height - s->ybase; - - /* Use underline thickness of font, defaulting to 1. */ - thickness = (font && font->underline_thickness > 0) - ? font->underline_thickness : 1; - - /* Determine the offset of underlining from the baseline. */ - if (x_underline_at_descent_line) - position = descent - thickness; - else if (x_use_underline_position_properties - && font && font->underline_position >= 0) - position = font->underline_position; - else if (font) - position = lround (font->descent / 2); - else - position = underline_minimum_offset; - position = max (position, underline_minimum_offset); + NSRect r; + unsigned long thickness, position; - /* Ensure underlining is not cropped. */ - if (descent <= position) + /* If the prev was underlined, match its appearance. */ + if (s->prev && s->prev->face->underline_p + && s->prev->underline_thickness > 0) { - position = descent - 1; - thickness = 1; + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; } - else if (descent < position + thickness) - thickness = 1; - } + else + { + struct font *font; + unsigned long descent; + + font=s->font; + descent = s->y + s->height - s->ybase; + + /* Use underline thickness of font, defaulting to 1. */ + thickness = (font && font->underline_thickness > 0) + ? font->underline_thickness : 1; + + /* Determine the offset of underlining from the baseline. */ + if (x_underline_at_descent_line) + position = descent - thickness; + else if (x_use_underline_position_properties + && font && font->underline_position >= 0) + position = font->underline_position; + else if (font) + position = lround (font->descent / 2); + else + position = underline_minimum_offset; - s->underline_thickness = thickness; - s->underline_position = position; + position = max (position, underline_minimum_offset); - r = NSMakeRect (x, s->ybase + position, width, thickness); + /* Ensure underlining is not cropped. */ + if (descent <= position) + { + position = descent - 1; + thickness = 1; + } + else if (descent < position + thickness) + thickness = 1; + } - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - NSRectFill (r); - } + s->underline_thickness = thickness; + s->underline_position = position; + + r = NSMakeRect (x, s->ybase + position, width, thickness); + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + NSRectFill (r); + } + } /* Do overline. We follow other terms in using a thickness of 1 and ignoring overline_margin. */ if (face->overline_p) @@ -3477,7 +3499,7 @@ ns_read_socket (struct terminal *terminal, int expected, int ns_select (int nfds, fd_set *readfds, fd_set *writefds, - fd_set *exceptfds, struct timeval *timeout) + fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask) /* -------------------------------------------------------------------------- Replacement for select, checking for events -------------------------------------------------------------------------- */ @@ -3485,12 +3507,14 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, int result; double time; NSEvent *ev; + struct timespec select_timeout; + /* NSTRACE (ns_select); */ if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO && [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */) - return select (nfds, readfds, writefds, exceptfds, timeout); + return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask); /* Save file descriptor set, which gets overwritten in calls to select () Note, this is called from process.c, and only readfds is ever set */ @@ -3503,8 +3527,9 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, select_nfds = 0; /* Try an initial select for pending data on input files */ - select_timeout.tv_sec = select_timeout.tv_usec = 0; - result = select (nfds, readfds, writefds, exceptfds, &select_timeout); + select_timeout.tv_sec = select_timeout.tv_nsec = 0; + result = pselect (nfds, readfds, writefds, exceptfds, + &select_timeout, sigmask); if (result) return result; @@ -3513,7 +3538,7 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, /* set a timeout and run the main AppKit event loop while continuing to monitor the files */ - time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0; + time = EMACS_TIME_TO_DOUBLE (*timeout); timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time target: NSApp selector: @selector (timeout_handler:) @@ -3521,7 +3546,7 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, repeats: YES] /* for safe removal */ retain]; - /* set a periodic task to try the select () again */ + /* set a periodic task to try the pselect () again */ fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1 target: NSApp selector: @selector (fd_handler:) @@ -3563,7 +3588,7 @@ ns_select (int nfds, fd_set *readfds, fd_set *writefds, } else { - /* Received back from select () in fd_handler; copy the results */ + /* Received back from pselect () in fd_handler; copy the results */ if (readfds) memcpy (readfds, &select_readfds, sizeof (fd_set)); return t; @@ -4203,6 +4228,15 @@ ns_term_init (Lisp_Object display_name) [NSApp setServicesMenu: svcsMenu]; /* Needed at least on Cocoa, to get dock menu to show windows */ [NSApp setWindowsMenu: [[NSMenu alloc] init]]; + + [[NSNotificationCenter defaultCenter] + addObserver: mainMenu + selector: @selector (trackingNotification:) + name: NSMenuDidBeginTrackingNotification object: mainMenu]; + [[NSNotificationCenter defaultCenter] + addObserver: mainMenu + selector: @selector (trackingNotification:) + name: NSMenuDidEndTrackingNotification object: mainMenu]; } #endif /* MAC OS X menu setup */ @@ -4534,6 +4568,7 @@ ns_term_shutdown (int sig) -------------------------------------------------------------------------- */ { int result; + struct timespec select_timeout; /* NSTRACE (fd_handler); */ if (select_nfds == 0) @@ -4541,9 +4576,8 @@ ns_term_shutdown (int sig) memcpy (&t_readfds, &select_readfds, sizeof (fd_set)); - select_timeout.tv_sec = select_timeout.tv_usec = 0; - result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, - &select_timeout); + select_timeout.tv_sec = select_timeout.tv_nsec = 0; + result = pselect (select_nfds, &t_readfds, NULL, NULL, &select_timeout, NULL); if (result) { memcpy (&select_readfds, &t_readfds, sizeof (fd_set)); @@ -6032,11 +6066,15 @@ ns_term_shutdown (int sig) restrict the height to just one monitor. So we override this. */ - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen { - /* When making the frame visible for the first time, we want to - constrain. Other times not. */ + /* When making the frame visible for the first time or if there is just + one screen, we want to constrain. Other times not. */ + NSUInteger nr_screens = [[NSScreen screens] count]; struct frame *f = ((EmacsView *)[self delegate])->emacsframe; NSTRACE (constrainFrameRect); + if (nr_screens == 1) + return [super constrainFrameRect:frameRect toScreen:screen]; + if (f->output_data.ns->dont_constrain || ns_menu_bar_should_be_hidden ()) return frameRect; @@ -6731,12 +6769,12 @@ Only works on OSX 10.6 or later. */); /* TODO: move to common code */ DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, - doc: /* If not nil, Emacs uses toolkit scroll bars. */); -#ifdef USE_TOOLKIT_SCROLL_BARS + doc: /* Which toolkit scroll bars Emacs uses, if any. +A value of nil means Emacs doesn't use toolkit scroll bars. +With the X Window system, the value is a symbol describing the +X toolkit. Possible values are: gtk, motif, xaw, or xaw3d. +With MS Windows or Nextstep, the value is t. */); Vx_toolkit_scroll_bars = Qt; -#else - Vx_toolkit_scroll_bars = Qnil; -#endif DEFVAR_BOOL ("x-use-underline-position-properties", x_use_underline_position_properties,