Skip to content

Commit

Permalink
macOS: Fix window shadows not being drawn for transparent windows
Browse files Browse the repository at this point in the history
Re-organize the whole infrastructure for setting window chrome, doing it
in a single function that has access to all settings.

Fixes #2827
Fixes #6416
  • Loading branch information
kovidgoyal committed Jul 4, 2023
1 parent b9bb924 commit d3f14ff
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 182 deletions.
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Detailed list of changes

- Fix a regression in 0.27.0 that broke setting of specific edge padding/margin via remote control (:iss:`6333`)

- macOS: Fix window shadows not being drawn for transparent windows (:iss:`2827`, :pull:`6416`)

0.28.1 [2023-04-21]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
114 changes: 90 additions & 24 deletions glfw/cocoa_window.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================

#include "internal.h"
#include "../kitty/monotonic.h"
#include "glfw3.h"
#include "internal.h"

#include <Availability.h>
#import <CoreServices/CoreServices.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#include <float.h>
#include <string.h>

#define debug(...) if (_glfw.hints.init.debugRendering) fprintf(stderr, __VA_ARGS__);

GLFWAPI int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int radius);

Expand Down Expand Up @@ -293,6 +295,7 @@
static NSUInteger getStyleMask(_GLFWwindow* window)
{
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->ns.titlebar_hidden) styleMask |= NSWindowStyleMaskFullSizeContentView;

if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
Expand Down Expand Up @@ -2922,29 +2925,6 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle)
return window->ns.object;
}

GLFWAPI void glfwHideCocoaTitlebar(GLFWwindow* handle, bool yes) {
@autoreleasepool {
_GLFWwindow* w = (_GLFWwindow*) handle;
NSWindow *window = w->ns.object;
w->ns.titlebar_hidden = yes;
NSButton *button;
button = [window standardWindowButton: NSWindowCloseButton];
if (button) button.hidden = yes;
button = [window standardWindowButton: NSWindowMiniaturizeButton];
if (button) button.hidden = yes;
button = [window standardWindowButton: NSWindowZoomButton];
[window setTitlebarAppearsTransparent:yes];
if (button) button.hidden = yes;
if (yes) {
[window setTitleVisibility:NSWindowTitleHidden];
[window setStyleMask: [window styleMask] | NSWindowStyleMaskFullSizeContentView];
} else {
[window setTitleVisibility:NSWindowTitleVisible];
[window setStyleMask: [window styleMask] & ~NSWindowStyleMaskFullSizeContentView];
}
} // autoreleasepool
}

GLFWAPI GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow *handle, GLFWcocoatextinputfilterfun callback) {
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFW_REQUIRE_INIT_OR_RETURN(nil);
Expand Down Expand Up @@ -2984,6 +2964,92 @@ GLFWAPI int glfwCocoaSetBackgroundBlur(GLFWwindow *w, int radius) {
return orig;
}

GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool use_system_color, unsigned int system_color, int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable) { @autoreleasepool {
_GLFWwindow* window = (_GLFWwindow*)w;
const bool is_transparent = ![window->ns.object isOpaque];
if (!is_transparent) { background_opacity = 1.0; background_blur = 0; }
NSColor *background = nil;
NSAppearance *appearance = nil;
bool titlebar_transparent = false;
NSWindowStyleMask current_style_mask = [window->ns.object styleMask];
bool in_fullscreen = ((current_style_mask & NSWindowStyleMaskFullScreen) != 0) || window->ns.in_traditional_fullscreen;
if (use_system_color || background_opacity < 1.0) {
if (is_transparent) {
// prevent blurring of shadows at window corners with desktop background by setting a low alpha background
background = background_blur > 0 ? [NSColor colorWithWhite: 0 alpha: 0.001f] : [NSColor clearColor];
} else background = [NSColor clearColor];
switch (system_color) {
case 1:
appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]; break;
case 2:
appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]; break;
}
} else {
// set a background color and make the title bar transparent so the background color is visible
double red = ((color >> 16) & 0xFF) / 255.0;
double green = ((color >> 8) & 0xFF) / 255.0;
double blue = (color & 0xFF) / 255.0;
double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
background = [NSColor colorWithSRGBRed:red green:green blue:blue alpha:1.f];
appearance = [NSAppearance appearanceNamed:(luma < 0.5 ? NSAppearanceNameVibrantDark : NSAppearanceNameVibrantLight)];
titlebar_transparent = true;
}
[window->ns.object setBackgroundColor:background];
[window->ns.object setAppearance:appearance];
glfwCocoaSetBackgroundBlur(w, background_blur);
bool has_shadow = false;
const char *decorations_desc = "full";
window->ns.titlebar_hidden = false;
switch (hide_window_decorations) {
case 1:
decorations_desc = "none";
window->decorated = false;
break;
case 2:
decorations_desc = "no-titlebar";
window->decorated = true;
has_shadow = true;
titlebar_transparent = true;
window->ns.titlebar_hidden = true;
show_text_in_titlebar = false;
break;
default:
window->decorated = true;
has_shadow = true;
break;
}
bool hide_titlebar_buttons = !in_fullscreen && window->ns.titlebar_hidden;
[window->ns.object setTitlebarAppearsTransparent:titlebar_transparent];
[window->ns.object setHasShadow:has_shadow];
[window->ns.object setTitleVisibility:(show_text_in_titlebar) ? NSWindowTitleVisible : NSWindowTitleHidden];
NSColorSpace *cs = nil;
switch (color_space) {
case SRGB_COLORSPACE: cs = [NSColorSpace sRGBColorSpace]; break;
case DISPLAY_P3_COLORSPACE: cs = [NSColorSpace displayP3ColorSpace]; break;
case DEFAULT_COLORSPACE: cs = [NSColorSpace deviceRGBColorSpace]; break;
}
window->resizable = resizable;
[window->ns.object setColorSpace:cs];
[[window->ns.object standardWindowButton: NSWindowCloseButton] setHidden:hide_titlebar_buttons];
[[window->ns.object standardWindowButton: NSWindowMiniaturizeButton] setHidden:hide_titlebar_buttons];
[[window->ns.object standardWindowButton: NSWindowZoomButton] setHidden:hide_titlebar_buttons];
debug(
"Window Chrome state:\n\tbackground: %s\n\tappearance: %s color_space: %s\n\t"
"blur: %d has_shadow: %d resizable: %d decorations: %s (%d)\n\t"
"titlebar: transparent: %d title_visibility: %d hidden: %d buttons_hidden: %d"
"\n",
background ? [background.description UTF8String] : "<nil>",
appearance ? [appearance.name UTF8String] : "<nil>",
cs ? (cs.localizedName ? [cs.localizedName UTF8String] : [cs.description UTF8String]) : "<nil>",
background_blur, has_shadow, resizable, decorations_desc, window->decorated, titlebar_transparent,
show_text_in_titlebar, window->ns.titlebar_hidden, hide_titlebar_buttons
);
window->ns.pre_full_screen_style_mask = getStyleMask(window);
[window->ns.object setStyleMask:window->ns.pre_full_screen_style_mask];
// HACK: Changing the style mask can cause the first responder to be cleared
[window->ns.object makeFirstResponder:window->ns.view];
}}

GLFWAPI int glfwGetCurrentSystemColorTheme(void) {
int theme_type = 0;
NSAppearance *changedAppearance = NSApp.effectiveAppearance;
Expand Down
3 changes: 2 additions & 1 deletion glfw/glfw.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ def generate_wrappers(glfw_header: str) -> None:
functions.append(Function(decl))
for line in '''\
void* glfwGetCocoaWindow(GLFWwindow* window)
void glfwHideCocoaTitlebar(GLFWwindow* window, bool yes)
void* glfwGetNSGLContext(GLFWwindow *window)
uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor)
GLFWcocoatextinputfilterfun glfwSetCocoaTextInputFilter(GLFWwindow* window, GLFWcocoatextinputfilterfun callback)
Expand All @@ -254,6 +253,8 @@ def generate_wrappers(glfw_header: str) -> None:
void* glfwGetX11Display(void)
int32_t glfwGetX11Window(GLFWwindow* window)
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
void glfwCocoaSetWindowChrome(GLFWwindow* window, unsigned int color, bool use_system_color, unsigned int system_color,\
int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable)
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
Expand Down
4 changes: 2 additions & 2 deletions glfw/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ typedef int (* _GLFWextensionsupportedfun)(const char*);
typedef GLFWglproc (* _GLFWgetprocaddressfun)(const char*);
typedef void (* _GLFWdestroycontextfun)(_GLFWwindow*);

#define GL_VERSION 0x1f02
#define GL_VERSION 0x1F02
#define GL_NONE 0
#define GL_COLOR_BUFFER_BIT 0x00004000
#define GL_UNSIGNED_BYTE 0x1401
#define GL_EXTENSIONS 0x1f03
#define GL_EXTENSIONS 0x1F03
#define GL_NUM_EXTENSIONS 0x821d
#define GL_CONTEXT_FLAGS 0x821e
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
Expand Down
3 changes: 3 additions & 0 deletions kitty/boss.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
set_options,
set_os_window_size,
set_os_window_title,
set_window_chrome,
thread_write,
toggle_fullscreen,
toggle_maximized,
Expand Down Expand Up @@ -1473,6 +1474,7 @@ def default_bg_changed_for(self, window_id: int) -> None:
t = tm.tab_for_id(w.tab_id)
if t is not None:
t.relayout_borders()
set_window_chrome(w.os_window_id)

def dispatch_action(
self,
Expand Down Expand Up @@ -2397,6 +2399,7 @@ def patch_colors(self, spec: Dict[str, Optional[int]], configured: bool = False)
t = tm.active_tab
if t is not None:
t.relayout_borders()
set_window_chrome(tm.os_window_id)
patch_global_colors(spec, configured)

def apply_new_options(self, opts: Options) -> None:
Expand Down
70 changes: 0 additions & 70 deletions kitty/cocoa_window.m
Original file line number Diff line number Diff line change
Expand Up @@ -699,25 +699,6 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
[m release];
} // }}}

bool
cocoa_make_window_resizable(void *w, bool resizable) {
NSWindow *window = (NSWindow*)w;

@try {
if (resizable) {
[window setStyleMask:
[window styleMask] | NSWindowStyleMaskResizable];
} else {
[window setStyleMask:
[window styleMask] & ~NSWindowStyleMaskResizable];
}
} @catch (NSException *e) {
log_error("Failed to set style mask: %s: %s", [[e name] UTF8String], [[e reason] UTF8String]);
return false;
}
return true;
}

#define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
#define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)

Expand Down Expand Up @@ -813,46 +794,6 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
[NSApp setActivationPolicy:(hide_from_tasks ? NSApplicationActivationPolicyAccessory : NSApplicationActivationPolicyRegular)];
}

void
cocoa_set_titlebar_appearance(void *w, unsigned int theme)
{
if (!theme) return;
@autoreleasepool {
NSWindow *window = (NSWindow*)w;
[window setAppearance:[NSAppearance appearanceNamed:((theme == 2) ? NSAppearanceNameVibrantDark : NSAppearanceNameVibrantLight)]];
} // autoreleasepool
}

void
cocoa_set_titlebar_color(void *w, color_type titlebar_color)
{
@autoreleasepool {

NSWindow *window = (NSWindow*)w;

double red = ((titlebar_color >> 16) & 0xFF) / 255.0;
double green = ((titlebar_color >> 8) & 0xFF) / 255.0;
double blue = (titlebar_color & 0xFF) / 255.0;

NSColor *background =
[NSColor colorWithSRGBRed:red
green:green
blue:blue
alpha:1.0];
[window setTitlebarAppearsTransparent:YES];
[window setBackgroundColor:background];

double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;

if (luma < 0.5) {
[window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
} else {
[window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
}

} // autoreleasepool
}

static PyObject*
cocoa_set_url_handler(PyObject UNUSED *self, PyObject *args) {
@autoreleasepool {
Expand Down Expand Up @@ -969,17 +910,6 @@ - (BOOL)openFileURLs:(NSPasteboard*)pasteboard
} // autoreleasepool
}

void
cocoa_hide_window_title(void *w)
{
@autoreleasepool {

NSWindow *window = (NSWindow*)w;
[window setTitleVisibility:NSWindowTitleHidden];

} // autoreleasepool
}

void
cocoa_system_beep(const char *path) {
if (!path) { NSBeep(); return; }
Expand Down
2 changes: 1 addition & 1 deletion kitty/fast_data_types.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ def init_cell_program() -> None:
pass


def set_titlebar_color(os_window_id: int, color: int, use_system_color: bool = False, system_color: int = 0) -> bool:
def set_window_chrome(os_window_id: int) -> bool:
pass


Expand Down
6 changes: 3 additions & 3 deletions kitty/glfw-wrapper.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions kitty/glfw-wrapper.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d3f14ff

Please sign in to comment.