From: Jan Djärv Date: Sun, 30 Sep 2012 12:50:09 +0000 (+0200) Subject: Add support for fullscreen in the NS port. X-Git-Tag: emacs-24.2.90~244^2 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=dd946752ab8810149a66a3eff469eb128709972d;p=emacs.git Add support for fullscreen in the NS port. * etc/NEWS: The NS port supports fullscreen. * src/nsfns.m (ns_frame_parm_handlers): Add x_set_fullscreen. * src/nsterm.h (MAC_OS_X_VERSION_10_7, MAC_OS_X_VERSION_10_8): New. (EmacsView): Add variables for fullscreen. (handleFS, setFSValue, toggleFullScreen): New in EmacsView. (EmacsFSWindow): New interface for fullscreen. * src/nsterm.m (NEW_STYLE_FS): New define. (ns_fullscreen_hook, windowWillEnterFullScreen) (windowDidEnterFullScreen, windowWillExitFullScreen) (windowDidExitFullScreen, toggleFullScreen, handleFS) (setFSValue): New functions. (EmacsFSWindow): New implementation. (canBecomeKeyWindow): New function for EmacsFSWindow. (ns_create_terminal): Set fullscreen_hook to ns_fullscreen_hook. (dealloc): Release nonfs_window if in fullscreen. (updateFrameSize:): Call windowDidMove to update top/left. (windowWillResize:toSize:): Check if frame is still maximized. (initFrameFromEmacs:): Initialize fs_state, fs_before_fs, next_maximized, maximized_width, maximized_height and nonfs_window. Call setCollectionBehavior if NEW_STYLE_FS. Initialize bwidth and tbar_height. (windowWillUseStandardFrame:defaultFrame:): Update frame parameter fullscreen. Set maximized_width/height. Act on next_maximized. --- diff --git a/etc/ChangeLog b/etc/ChangeLog index 6f2b178fcd7..2c1e3758ea0 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,7 @@ +2012-09-30 Jan Djärv + + * NEWS: The NS port supports fullscreen. + 2012-09-17 Glenn Morris * refcards/emacsver.tex: New file. diff --git a/etc/NEWS b/etc/NEWS index 0aff5e40251..e6f09d83f43 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -187,6 +187,8 @@ The PCL-CVS commands are still available via the keyboard. --- *** New input method `vietnamese-vni'. +** The NS port supports fullscreen. + * Editing Changes in Emacs 24.3 diff --git a/src/ChangeLog b/src/ChangeLog index 1f240b219e0..6aaa6bc88f8 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,30 @@ +2012-09-30 Jan Djärv + + * nsfns.m (ns_frame_parm_handlers): Add x_set_fullscreen. + + * nsterm.m (NEW_STYLE_FS): New define. + (ns_fullscreen_hook, windowWillEnterFullScreen) + (windowDidEnterFullScreen, windowWillExitFullScreen) + (windowDidExitFullScreen, toggleFullScreen, handleFS) + (setFSValue): New functions. + (EmacsFSWindow): New implementation. + (canBecomeKeyWindow): New function for EmacsFSWindow. + (ns_create_terminal): Set fullscreen_hook to ns_fullscreen_hook. + (dealloc): Release nonfs_window if in fullscreen. + (updateFrameSize:): Call windowDidMove to update top/left. + (windowWillResize:toSize:): Check if frame is still maximized. + (initFrameFromEmacs:): Initialize fs_state, fs_before_fs, + next_maximized, maximized_width, maximized_height and nonfs_window. + Call setCollectionBehavior if NEW_STYLE_FS. Initialize bwidth and + tbar_height. + (windowWillUseStandardFrame:defaultFrame:): Update frame parameter + fullscreen. Set maximized_width/height. Act on next_maximized. + + * nsterm.h (MAC_OS_X_VERSION_10_7, MAC_OS_X_VERSION_10_8): New. + (EmacsView): Add variables for fullscreen. + (handleFS, setFSValue, toggleFullScreen): New in EmacsView. + (EmacsFSWindow): New interface for fullscreen. + 2012-09-30 Juanma Barranquero * makefile.w32-in ($(BLD)/profiler.$(O)): Update dependencies. diff --git a/src/nsfns.m b/src/nsfns.m index 94ace360438..c96ec99ed2e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1018,7 +1018,7 @@ frame_parm_handler ns_frame_parm_handlers[] = x_set_fringe_width, /* generic OK */ x_set_fringe_width, /* generic OK */ 0, /* x_set_wait_for_wm, will ignore */ - 0, /* x_set_fullscreen will ignore */ + x_set_fullscreen, /* generic OK */ x_set_font_backend, /* generic OK */ x_set_alpha, 0, /* x_set_sticky */ diff --git a/src/nsterm.h b/src/nsterm.h index 97fc6be20e5..f06e0cb0f7f 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -38,6 +38,12 @@ along with GNU Emacs. If not, see . */ #ifndef MAC_OS_X_VERSION_10_6 #define MAC_OS_X_VERSION_10_6 1060 #endif +#ifndef MAC_OS_X_VERSION_10_7 +#define MAC_OS_X_VERSION_10_7 1070 +#endif +#ifndef MAC_OS_X_VERSION_10_8 +#define MAC_OS_X_VERSION_10_8 1080 +#endif #endif /* NS_IMPL_COCOA */ #ifdef __OBJC__ @@ -80,6 +86,9 @@ along with GNU Emacs. If not, see . */ BOOL windowClosing; NSString *workingText; BOOL processingCompose; + int fs_state, fs_before_fs, next_maximized, tbar_height, bwidth; + int maximized_width, maximized_height; + NSWindow *nonfs_window; @public struct frame *emacsframe; int rows, cols; @@ -104,6 +113,9 @@ along with GNU Emacs. If not, see . */ - (EmacsToolbar *) toolbar; - (void) deleteWorkingText; - (void) updateFrameSize: (BOOL) delay; +- (void) handleFS; +- (void) setFSValue: (int)value; +- (void) toggleFullScreen: (id) sender; #ifdef NS_IMPL_GNUSTEP /* Not declared, but useful. */ @@ -120,6 +132,12 @@ along with GNU Emacs. If not, see . */ @end +/* Fullscreen version of the above. */ +@interface EmacsFSWindow : EmacsWindow +{ +} +@end + /* ========================================================================== The main menu implementation diff --git a/src/nsterm.m b/src/nsterm.m index 5af3c2e2ae1..d41c38f4e40 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -72,6 +72,11 @@ int term_trace_num = 0; #define NSTRACE(x) #endif +#if defined (NS_IMPL_COCOA) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 +#define NEW_STYLE_FS +#endif + extern NSString *NSMenuDidBeginTrackingNotification; /* ========================================================================== @@ -1306,6 +1311,17 @@ x_set_window_size (struct frame *f, int change_grav, int cols, int rows) } +static void +ns_fullscreen_hook (FRAME_PTR f) +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + + if (! f->async_visible) return; + + block_input (); + [view handleFS]; + unblock_input (); +} /* ========================================================================== @@ -3932,7 +3948,7 @@ ns_create_terminal (struct ns_display_info *dpyinfo) terminal->frame_rehighlight_hook = ns_frame_rehighlight; terminal->frame_raise_lower_hook = ns_frame_raise_lower; - terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */ + terminal->fullscreen_hook = ns_fullscreen_hook; terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar; terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars; @@ -4687,6 +4703,8 @@ not_in_argv (NSString *arg) { NSTRACE (EmacsView_dealloc); [toolbar release]; + if (fs_state == FULLSCREEN_BOTH) + [nonfs_window release]; [super dealloc]; } @@ -5405,6 +5423,7 @@ not_in_argv (NSString *arg) SET_FRAME_GARBAGED (emacsframe); cancel_mouse_face (emacsframe); [view setFrame: NSMakeRect (0, 0, neww, newh)]; + [self windowDidMove:nil]; // Update top/left. } } @@ -5414,6 +5433,19 @@ not_in_argv (NSString *arg) NSTRACE (windowWillResize); /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */ + if (fs_state == FULLSCREEN_MAXIMIZED + && (maximized_width != (int)frameSize.width + || maximized_height != (int)frameSize.height)) + [self setFSValue: FULLSCREEN_NONE]; + else if (fs_state == FULLSCREEN_WIDTH + && maximized_width != (int)frameSize.width) + [self setFSValue: FULLSCREEN_NONE]; + else if (fs_state == FULLSCREEN_HEIGHT + && maximized_height != (int)frameSize.height) + [self setFSValue: FULLSCREEN_NONE]; + if (fs_state == FULLSCREEN_NONE) + maximized_width = maximized_height = -1; + cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, #ifdef NS_IMPL_GNUSTEP frameSize.width + 3); @@ -5595,6 +5627,10 @@ not_in_argv (NSString *arg) windowClosing = NO; processingCompose = NO; scrollbarsNeedingUpdate = 0; + fs_state = FULLSCREEN_NONE; + fs_before_fs = next_maximized = -1; + maximized_width = maximized_height = -1; + nonfs_window = nil; /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */ @@ -5619,9 +5655,13 @@ not_in_argv (NSString *arg) backing: NSBackingStoreBuffered defer: YES]; +#ifdef NEW_STYLE_FS + [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; +#endif + wr = [win frame]; - f->border_width = wr.size.width - r.size.width; - FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height; + bwidth = f->border_width = wr.size.width - r.size.width; + tbar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height; [win setAcceptsMouseMovedEvents: YES]; [win setDelegate: self]; @@ -5727,27 +5767,50 @@ not_in_argv (NSString *arg) NSTRACE (windowWillUseStandardFrame); - if (abs (defaultFrame.size.height - result.size.height) - > FRAME_LINE_HEIGHT (emacsframe)) + if (fs_before_fs != -1) /* Entering fullscreen */ + { + result = defaultFrame; + } + else if (next_maximized == FULLSCREEN_HEIGHT + || (next_maximized == -1 + && abs (defaultFrame.size.height - result.size.height) + > FRAME_LINE_HEIGHT (emacsframe))) { /* first click */ ns_userRect = result; - result.size.height = defaultFrame.size.height; + maximized_height = result.size.height = defaultFrame.size.height; + maximized_width = -1; result.origin.y = defaultFrame.origin.y; + [self setFSValue: FULLSCREEN_HEIGHT]; + } + else if (next_maximized == FULLSCREEN_WIDTH) + { + ns_userRect = result; + maximized_width = result.size.width = defaultFrame.size.width; + maximized_height = -1; + result.origin.x = defaultFrame.origin.x; + [self setFSValue: FULLSCREEN_WIDTH]; + } + else if (next_maximized == FULLSCREEN_MAXIMIZED + || (next_maximized == -1 + && abs (defaultFrame.size.width - result.size.width) + > FRAME_COLUMN_WIDTH (emacsframe))) + { + result = defaultFrame; /* second click */ + maximized_width = result.size.width; + maximized_height = result.size.height; + [self setFSValue: FULLSCREEN_MAXIMIZED]; } else { - if (abs (defaultFrame.size.width - result.size.width) - > FRAME_COLUMN_WIDTH (emacsframe)) - result = defaultFrame; /* second click */ - else - { - /* restore */ - result = ns_userRect.size.height ? ns_userRect : result; - ns_userRect = NSMakeRect (0, 0, 0, 0); - } + /* restore */ + result = ns_userRect.size.height ? ns_userRect : result; + ns_userRect = NSMakeRect (0, 0, 0, 0); + [self setFSValue: FULLSCREEN_NONE]; + maximized_width = maximized_width = -1; } + if (fs_before_fs == -1) next_maximized = -1; [self windowWillResize: sender toSize: result.size]; return result; } @@ -5799,6 +5862,200 @@ not_in_argv (NSString *arg) } } +- (void)windowWillEnterFullScreen:(NSNotification *)notification +{ + fs_before_fs = fs_state; +} + +- (void)windowDidEnterFullScreen:(NSNotification *)notification +{ + [self setFSValue: FULLSCREEN_BOTH]; +#ifndef NEW_STYLE_FS + fprintf(stderr, "%s %d\n", __func__, FRAME_PIXEL_WIDTH (emacsframe)); + [self windowDidBecomeKey:notification]; +#endif +} + +- (void)windowWillExitFullScreen:(NSNotification *)notification +{ + if (next_maximized != -1) + fs_before_fs = next_maximized; +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification +{ + [self setFSValue: fs_before_fs]; + fs_before_fs = -1; + if (next_maximized != -1) + [[self window] performZoom:self]; +} + +- (void)toggleFullScreen: (id)sender +{ + /* Bugs remain: + 1) Having fullscreen in initial/default frame alist. + 2) Fullscreen in default frame alist only applied to first frame. + */ + +#ifdef NEW_STYLE_FS + [[self window] toggleFullScreen:sender]; +#else + NSWindow *w = [self window], *fw; + BOOL onFirstScreen = [[w screen] + isEqual:[[NSScreen screens] objectAtIndex:0]]; + struct frame *f = emacsframe; + NSSize sz; + NSRect r; + NSColor *col = ns_lookup_indexed_color (NS_FACE_BACKGROUND + (FRAME_DEFAULT_FACE (f)), + f); + + sz.width = FRAME_COLUMN_WIDTH (f); + sz.height = FRAME_LINE_HEIGHT (f); + + if (fs_state != FULLSCREEN_BOTH) + { + /* Hide dock and menubar if we are on the primary screen. */ + if (onFirstScreen) + { +#if defined (NS_IMPL_COCOA) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + NSApplicationPresentationOptions options + = NSApplicationPresentationAutoHideDock + | NSApplicationPresentationAutoHideMenuBar; + + [NSApp setPresentationOptions: options]; +#else + [NSMenu setMenuBarVisible:NO]; +#endif + } + + fw = [[EmacsFSWindow alloc] + initWithContentRect:[w contentRectForFrameRect:[w frame]] + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES + screen:[w screen]]; + + [fw setContentView:[w contentView]]; + [fw setTitle:[w title]]; + [fw makeKeyAndOrderFront:NSApp]; + [fw setDelegate:self]; + [fw makeFirstResponder:self]; + [fw setAcceptsMouseMovedEvents: YES]; + [fw useOptimizedDrawing: YES]; + [fw setResizeIncrements: sz]; + [fw setBackgroundColor: col]; + if ([col alphaComponent] != 1.0) + [fw setOpaque: NO]; + + f->border_width = 0; + FRAME_NS_TITLEBAR_HEIGHT (f) = 0; + + nonfs_window = w; + [self windowWillEnterFullScreen:nil]; + [w orderOut:self]; + r = [fw frameRectForContentRect:[[fw screen] frame]]; + [fw setFrame: r display:YES animate:YES]; + [self windowDidEnterFullScreen:nil]; + } + else + { + fw = w; + w = nonfs_window; + + if (onFirstScreen) + { +#if defined (NS_IMPL_COCOA) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + [NSApp setPresentationOptions: NSApplicationPresentationDefault]; +#else + [NSMenu setMenuBarVisible:YES]; +#endif + } + + [w setContentView:[fw contentView]]; + [w setResizeIncrements: sz]; + [w setBackgroundColor: col]; + if ([col alphaComponent] != 1.0) + [w setOpaque: NO]; + + f->border_width = bwidth; + FRAME_NS_TITLEBAR_HEIGHT (f) = tbar_height; + + [self windowWillExitFullScreen:nil]; + [fw setFrame: [w frame] display:YES animate:YES]; + [fw close]; + [w makeKeyAndOrderFront:NSApp]; + [self windowDidExitFullScreen:nil]; + } +#endif +} + +- (void)handleFS +{ + if (fs_state != emacsframe->want_fullscreen) + { + if (fs_state == FULLSCREEN_BOTH) + { + [self toggleFullScreen:self]; + } + + switch (emacsframe->want_fullscreen) + { + case FULLSCREEN_BOTH: + [self toggleFullScreen:self]; + break; + case FULLSCREEN_WIDTH: + next_maximized = FULLSCREEN_WIDTH; + if (fs_state != FULLSCREEN_BOTH) + [[self window] performZoom:self]; + break; + case FULLSCREEN_HEIGHT: + next_maximized = FULLSCREEN_HEIGHT; + if (fs_state != FULLSCREEN_BOTH) + [[self window] performZoom:self]; + break; + case FULLSCREEN_MAXIMIZED: + next_maximized = FULLSCREEN_MAXIMIZED; + if (fs_state != FULLSCREEN_BOTH) + [[self window] performZoom:self]; + break; + case FULLSCREEN_NONE: + if (fs_state != FULLSCREEN_BOTH) + { + next_maximized = FULLSCREEN_NONE; + [[self window] performZoom:self]; + } + break; + } + + emacsframe->want_fullscreen = FULLSCREEN_NONE; + } + +} + +- (void) setFSValue: (int)value +{ + Lisp_Object lval = Qnil; + switch (value) + { + case FULLSCREEN_BOTH: + lval = Qfullboth; + break; + case FULLSCREEN_WIDTH: + lval = Qfullwidth; + break; + case FULLSCREEN_HEIGHT: + lval = Qfullheight; + break; + case FULLSCREEN_MAXIMIZED: + lval = Qmaximized; + break; + } + store_frame_param (emacsframe, Qfullscreen, lval); + fs_state = value; +} - (void)mouseEntered: (NSEvent *)theEvent { @@ -6290,6 +6547,15 @@ not_in_argv (NSString *arg) @end /* EmacsWindow */ +@implementation EmacsFSWindow + +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +@end + /* ========================================================================== EmacsScroller implementation