From 1535c81f77153dd61426246be2e8afd33fa6909a Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sat, 5 Jun 2021 12:39:46 +0100 Subject: [PATCH] Tidy up NS port OS window handling * src/nsterm.h (EmacsWindow): Move above EmacsView definition and add new method definitions. (EmacsView): Remove redundant bwidth variable, and change NSWindow to EmacsWindow. (EmacsFSWindow): Delete definition. * src/nsterm.m (ns_set_undecorated): Rewrite to work in GNUstep using the new OS window creating methods. ([EmacsView initFrameFromEmacs:]): Move all NSWindow related code to new init method in EmacsWindow, and use said method. ([EmacsView toggleFullScreen:]): Use EmacsWindow instead of NSWindow. ([EmacsWindow initWithEmacsFrame:]): ([EmacsWindow initWithEmacsFrame:fullscreen:screen:]): ([EmacsWindow borderWidth]): New methods. (EmacsFSWindow): Remove implementation. --- src/nsfns.m | 4 - src/nsterm.h | 42 +++---- src/nsterm.m | 319 +++++++++++++++++++++++++-------------------------- 3 files changed, 175 insertions(+), 190 deletions(-) diff --git a/src/nsfns.m b/src/nsfns.m index 454a6fdab62..c40367703db 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -947,11 +947,7 @@ frame_parm_handler ns_frame_parm_handlers[] = 0, /* x_set_sticky */ 0, /* x_set_tool_bar_position */ 0, /* x_set_inhibit_double_buffering */ -#ifdef NS_IMPL_COCOA ns_set_undecorated, -#else - 0, /* ns_set_undecorated */ -#endif ns_set_parent_frame, 0, /* x_set_skip_taskbar */ ns_set_no_focus_on_map, diff --git a/src/nsterm.h b/src/nsterm.h index c61c6986556..40206cc4ded 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -406,6 +406,24 @@ typedef id instancetype; @end #endif +/* EmacsWindow */ +@interface EmacsWindow : NSWindow +{ + NSPoint grabOffset; +} + +#ifdef NS_IMPL_GNUSTEP +- (NSInteger) orderedIndex; +#endif + +- (instancetype)initWithEmacsFrame:(struct frame *)f; +- (instancetype)initWithEmacsFrame:(struct frame *)f fullscreen:(BOOL)fullscreen screen:(NSScreen *)screen; +- (NSInteger)borderWidth; +- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above; +- (void)setAppearance; +@end + + /* ========================================================================== The main Emacs view @@ -429,9 +447,8 @@ typedef id instancetype; NSString *workingText; BOOL processingCompose; int fs_state, fs_before_fs, next_maximized; - int bwidth; int maximized_width, maximized_height; - NSWindow *nonfs_window; + EmacsWindow *nonfs_window; BOOL fs_is_native; @public struct frame *emacsframe; @@ -485,27 +502,6 @@ typedef id instancetype; @end -/* Small utility used for processing resize events under Cocoa. */ -@interface EmacsWindow : NSWindow -{ - NSPoint grabOffset; -} - -#ifdef NS_IMPL_GNUSTEP -- (NSInteger) orderedIndex; -#endif - -- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above; -- (void)setAppearance; -@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 b2ee459c427..569365d5e48 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1720,7 +1720,6 @@ ns_set_window_size (struct frame *f, unblock_input (); } -#ifdef NS_IMPL_COCOA void ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) /* -------------------------------------------------------------------------- @@ -1730,45 +1729,37 @@ ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu dragged, resized, iconified, maximized or deleted with the mouse. If nil, draw the frame with all the elements listed above unless these have been suspended via window manager settings. - - GNUStep cannot change an existing window's style. -------------------------------------------------------------------------- */ { - EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); - NSWindow *window = [view window]; - NSTRACE ("ns_set_undecorated"); if (!EQ (new_value, old_value)) { + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *oldWindow = [view window]; + NSWindow *newWindow; + block_input (); - if (NILP (new_value)) - { - FRAME_UNDECORATED (f) = false; - [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS) - ^ FRAME_UNDECORATED_FLAGS)]; + FRAME_UNDECORATED (f) = !NILP (new_value); - [view createToolbar: f]; - } - else - { - [window setToolbar: nil]; - /* Do I need to release the toolbar here? */ + newWindow = [[EmacsWindow alloc] initWithEmacsFrame:f]; - FRAME_UNDECORATED (f) = true; - [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS) - ^ FRAME_DECORATED_FLAGS)]; - } + if (!FRAME_UNDECORATED (f)) + [view createToolbar: f]; + + if ([oldWindow isKeyWindow]) + [newWindow makeKeyAndOrderFront:NSApp]; - /* At this point it seems we don't have an active NSResponder, - so some key presses (TAB) are swallowed by the system. */ - [window makeFirstResponder: view]; + [newWindow setIsVisible:[oldWindow isVisible]]; + if ([oldWindow isMiniaturized]) + [newWindow miniaturize:NSApp]; + + [oldWindow close]; unblock_input (); } } -#endif /* NS_IMPL_COCOA */ void ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) @@ -7239,12 +7230,6 @@ not_in_argv (NSString *arg) - (instancetype) initFrameFromEmacs: (struct frame *)f { - NSRect r, wr; - Lisp_Object tem; - EmacsWindow *win; - NSColor *col; - NSString *name; - NSTRACE ("[EmacsView initFrameFromEmacs:]"); NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines); @@ -7266,9 +7251,9 @@ not_in_argv (NSString *arg) nonfs_window = nil; ns_userRect = NSMakeRect (0, 0, 0, 0); - r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines)); - [self initWithFrame: r]; + [self initWithFrame: + NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))]; [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; FRAME_NS_VIEW (f) = self; @@ -7278,37 +7263,7 @@ not_in_argv (NSString *arg) maximizing_resize = NO; #endif - win = [[EmacsWindow alloc] - initWithContentRect: r - styleMask: (FRAME_UNDECORATED (f) - ? FRAME_UNDECORATED_FLAGS - : FRAME_DECORATED_FLAGS) - backing: NSBackingStoreBuffered - defer: YES]; - -#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) -#endif - if (FRAME_PARENT_FRAME (f)) - [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - else - [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; -#endif - - wr = [win frame]; - bwidth = f->border_width = wr.size.width - r.size.width; - - [win setAcceptsMouseMovedEvents: YES]; - [win setDelegate: self]; -#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 -#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 - if ([win respondsToSelector: @selector(useOptimizedDrawing:)]) -#endif - [win useOptimizedDrawing: YES]; -#endif - - [[win contentView] addSubview: self]; + [[EmacsWindow alloc] initWithEmacsFrame:f]; #ifdef NS_IMPL_COCOA /* These settings mean AppKit will retain the contents of the frame @@ -7324,65 +7279,10 @@ not_in_argv (NSString *arg) if (ns_drag_types) [self registerForDraggedTypes: ns_drag_types]; - tem = f->name; - name = NILP (tem) ? @"Emacs" : [NSString stringWithLispString:tem]; - [win setTitle: name]; - /* toolbar support */ if (! FRAME_UNDECORATED (f)) [self createToolbar: f]; - - [win setAppearance]; - -#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 - if ([win respondsToSelector: @selector(titlebarAppearsTransparent)]) - win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f); -#endif - - tem = f->icon_name; - if (!NILP (tem)) - [win setMiniwindowTitle: - [NSString stringWithLispString:tem]]; - - if (FRAME_PARENT_FRAME (f) != NULL) - { - NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; - [parent addChildWindow: win - ordered: NSWindowAbove]; - } - - if (FRAME_Z_GROUP (f) != z_group_none) - win.level = NSNormalWindowLevel - + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1); - - { - NSScreen *screen = [win screen]; - - if (screen != 0) - { - NSPoint pt = NSMakePoint - (IN_BOUND (-SCREENMAX, f->left_pos - + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), - IN_BOUND (-SCREENMAX, - NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos, - SCREENMAX)); - - [win setFrameTopLeftPoint: pt]; - - NSTRACE_RECT ("new frame", [win frame]); - } - } - - [win makeFirstResponder: self]; - - col = ns_lookup_indexed_color (NS_FACE_BACKGROUND - (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)), - emacsframe); - [win setBackgroundColor: col]; - if ([col alphaComponent] != (EmacsCGFloat) 1.0) - [win setOpaque: NO]; - #if !defined (NS_IMPL_COCOA) \ || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 @@ -7400,14 +7300,6 @@ not_in_argv (NSString *arg) selector:@selector (viewDidResize:) name:NSViewFrameDidChangeNotification object:nil]; - /* macOS Sierra automatically enables tabbed windows. We can't - allow this to be enabled until it's available on a Free system. - Currently it only happens by accident and is buggy anyway. */ -#ifdef NS_IMPL_COCOA - if ([win respondsToSelector: @selector(setTabbingMode:)]) - [win setTabbingMode: NSWindowTabbingModeDisallowed]; -#endif - ns_window_num++; return self; } @@ -7797,7 +7689,7 @@ not_in_argv (NSString *arg) - (void)toggleFullScreen: (id)sender { - NSWindow *w, *fw; + EmacsWindow *w, *fw; BOOL onFirstScreen; struct frame *f; NSRect r, wr; @@ -7816,7 +7708,7 @@ not_in_argv (NSString *arg) return; } - w = [self window]; + w = (EmacsWindow *)[self window]; onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]]; f = emacsframe; wr = [w frame]; @@ -7851,27 +7743,9 @@ not_in_argv (NSString *arg) #endif } - fw = [[EmacsFSWindow alloc] - initWithContentRect:[w contentRectForFrameRect:wr] - styleMask:NSWindowStyleMaskBorderless - backing:NSBackingStoreBuffered - defer:YES - screen:screen]; - - [fw setContentView:[w contentView]]; - [fw setTitle:[w title]]; - [fw setDelegate:self]; - [fw setAcceptsMouseMovedEvents: YES]; -#if !defined (NS_IMPL_COCOA) \ - || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 -#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 - if ([fw respondsToSelector: @selector(useOptimizedDrawing:)]) -#endif - [fw useOptimizedDrawing: YES]; -#endif - [fw setBackgroundColor: col]; - if ([col alphaComponent] != (EmacsCGFloat) 1.0) - [fw setOpaque: NO]; + fw = [[EmacsWindow alloc] initWithEmacsFrame:emacsframe + fullscreen:YES + screen:screen]; f->border_width = 0; @@ -7879,7 +7753,6 @@ not_in_argv (NSString *arg) [self windowWillEnterFullScreen]; [fw makeKeyAndOrderFront:NSApp]; - [fw makeFirstResponder:self]; [w orderOut:self]; r = [fw frameRectForContentRect:[screen frame]]; [fw setFrame: r display:YES animate:ns_use_fullscreen_animation]; @@ -7906,7 +7779,7 @@ not_in_argv (NSString *arg) if ([col alphaComponent] != (EmacsCGFloat) 1.0) [w setOpaque: NO]; - f->border_width = bwidth; + f->border_width = [w borderWidth]; // To do: consider using [NSNotificationCenter postNotificationName:] to // send notifications. @@ -8483,6 +8356,133 @@ not_in_argv (NSString *arg) @implementation EmacsWindow + +- (instancetype) initWithEmacsFrame:(struct frame *)f +{ + return [self initWithEmacsFrame:f fullscreen:NO screen:nil]; +} + + +- (instancetype) initWithEmacsFrame:(struct frame *)f + fullscreen:(BOOL)fullscreen + screen:(NSScreen *)screen +{ + NSWindowStyleMask styleMask; + + NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]"); + + if (fullscreen) + styleMask = NSWindowStyleMaskBorderless; + else if (FRAME_UNDECORATED (f)) + styleMask = FRAME_UNDECORATED_FLAGS; + else + styleMask = FRAME_DECORATED_FLAGS; + + + self = [super initWithContentRect: + NSMakeRect (0, 0, + FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), + FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines)) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:YES + screen:screen]; + if (self) + { + NSString *name; + NSColor *col; + NSScreen *screen = [self screen]; + EmacsView *view = FRAME_NS_VIEW (f); + + [self setDelegate:view]; + [[self contentView] addSubview:view]; + [self makeFirstResponder:view]; + +#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 +#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 + if ([self respondsToSelector: @selector(useOptimizedDrawing:)]) +#endif + [self useOptimizedDrawing:YES]; +#endif + + [self setAcceptsMouseMovedEvents:YES]; + + name = NILP (f->name) ? @"Emacs" : [NSString stringWithLispString:f->name]; + [self setTitle:name]; + + if (!NILP (f->icon_name)) + [self setMiniwindowTitle: + [NSString stringWithLispString:f->icon_name]]; + + [self setAppearance]; + +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 + if ([self respondsToSelector:@selector(titlebarAppearsTransparent)]) + [self setTitlebarAppearsTransparent:FRAME_NS_TRANSPARENT_TITLEBAR (f)]; +#endif + + #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) +#endif + if (FRAME_PARENT_FRAME (f)) + [self setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + else + [self setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; +#endif + + if (FRAME_PARENT_FRAME (f) != NULL) + { + NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; + [parent addChildWindow:self + ordered:NSWindowAbove]; + } + + if (FRAME_Z_GROUP (f) != z_group_none) + [self setLevel:NSNormalWindowLevel + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1)]; + + if (screen != 0) + { + NSPoint pt = NSMakePoint + (IN_BOUND (-SCREENMAX, f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), + IN_BOUND (-SCREENMAX, + NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos, + SCREENMAX)); + + [self setFrameTopLeftPoint:pt]; + + NSTRACE_RECT ("new frame", [self frame]); + } + + f->border_width = [self borderWidth]; + + col = ns_lookup_indexed_color (NS_FACE_BACKGROUND + (FACE_FROM_ID (f, DEFAULT_FACE_ID)), + f); + [self setBackgroundColor:col]; + if ([col alphaComponent] != (EmacsCGFloat) 1.0) + [self setOpaque:NO]; + + /* macOS Sierra automatically enables tabbed windows. We can't + allow this to be enabled until it's available on a Free system. + Currently it only happens by accident and is buggy anyway. */ +#ifdef NS_IMPL_COCOA + if ([self respondsToSelector:@selector(setTabbingMode:)]) + [self setTabbingMode:NSWindowTabbingModeDisallowed]; +#endif + } + + return self; +} + + +- (NSInteger) borderWidth +{ + return NSWidth ([self frame]) - NSWidth ([[self contentView] frame]); +} + + /* It seems the only way to reorder child frames is by removing them from the parent and then reattaching them in the correct order. */ @@ -8892,22 +8892,15 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c) { return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe); } -@end /* EmacsWindow */ - - -@implementation EmacsFSWindow - -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - (BOOL)canBecomeMainWindow + /* Required for fullscreen and undecorated windows. */ { return YES; } -@end +@end /* EmacsWindow */ + /* ========================================================================== -- 2.39.2