Compare commits

...

7 Commits

Author SHA1 Message Date
Kovid Goyal
13e59df1f8 version 0.22.2 2021-08-02 08:20:33 +05:30
Kovid Goyal
c797944923 Also set first underviced render frame request 2021-08-01 12:59:22 +05:30
Kovid Goyal
ade4e67b51 Possible fix for #3890
Try to ensure we have a functioning displaylink always.
GLFW skips over sleeping monitors during a poll and also
had a bug where the display link was not re-created for a monitor
that already had a glfw monitor entry.

Also add a bunch more debug reporting
2021-08-01 12:53:35 +05:30
Kovid Goyal
656f49f2ff ... 2021-08-01 07:56:55 +05:30
Kovid Goyal
0045244295 All option instances must not share the same color table 2021-07-31 18:44:39 +05:30
Kovid Goyal
6bfb704f6f When going from csd->no csd increase window height to compensate for titlebar.
Sway will send the next configure event (for example when focus changes)
with titlebar height added, so to avoid a sudden resize at that time,
bump the height by the titlebar.
2021-07-31 14:56:45 +05:30
Kovid Goyal
80cebdefcd Better fix for CSD toggling on Wayland
Draw CSD if the compositor wants us to. See #3888
2021-07-31 14:15:38 +05:30
10 changed files with 94 additions and 37 deletions

View File

@@ -22,7 +22,7 @@ If applicable, add screenshots to help explain your problem.
**Environment details**
```
Press Ctrl+Shift+F6 (cmd+option+, on macOS) in kitty, to copy debug output about kitty and its
Press Ctrl+Shift+F6 (cmd+option+comma on macOS) in kitty, to copy debug output about kitty and its
configuration to the clipboard and paste it here.
On older versions of kitty, run kitty --debug-config instead

View File

@@ -4,6 +4,17 @@ Changelog
|kitty| is a feature-rich, cross-platform, *fast*, GPU based terminal.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.22.2 [2021-08-02]
----------------------
- macOS: Fix a long standing bug that could cause kitty windows to stop
updating, that got worse in the previous release (:iss:`3890` and
:iss:`2016`)
- Wayland: A better fix for compositors like sway that can toggle client side
decorations on and off (:iss:`3888`)
0.22.1 [2021-07-31]
----------------------

View File

@@ -41,7 +41,8 @@
// Get the name of the specified display, or NULL
//
static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
static char*
getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
{
// IOKit doesn't work on Apple Silicon anymore
// Luckily, 10.15 introduced -[NSScreen localizedName].
@@ -51,8 +52,9 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
if ([screen respondsToSelector:@selector(localizedName)])
{
NSString* name = [screen valueForKey:@"localizedName"];
if (name)
if (name) {
return _glfw_strdup([name UTF8String]);
}
}
}
io_iterator_t it;
@@ -64,7 +66,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
&it) != 0)
{
// This may happen if a desktop Mac is running headless
return _glfw_strdup("Display");
return NULL;
}
while ((service = IOIteratorNext(it)) != 0)
@@ -102,7 +104,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find service port for display");
return _glfw_strdup("Display");
return NULL;
}
CFDictionaryRef names =
@@ -115,7 +117,7 @@ static char* getDisplayName(CGDirectDisplayID displayID, NSScreen* screen)
{
// This may happen if a desktop Mac is running headless
CFRelease(info);
return _glfw_strdup("Display");
return NULL;
}
const CFIndex size =
@@ -326,11 +328,9 @@ void _glfwClearDisplayLinks() {
if (_glfw.ns.displayLinks.entries[i].displayLink) {
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
_glfw.ns.displayLinks.entries[i].displayLink = nil;
_glfw.ns.displayLinks.entries[i].lastRenderFrameRequestedAt = 0;
_glfw.ns.displayLinks.entries[i].first_unserviced_render_frame_request_at = 0;
}
}
memset(_glfw.ns.displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * _glfw.ns.displayLinks.count);
_glfw.ns.displayLinks.count = 0;
}
@@ -352,16 +352,21 @@ _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
}
static void
createDisplayLink(CGDirectDisplayID displayID) {
if (_glfw.ns.displayLinks.count >= sizeof(_glfw.ns.displayLinks.entries)/sizeof(_glfw.ns.displayLinks.entries[0]) - 1) return;
_GLFWDisplayLinkNS*
_glfw_create_display_link(CGDirectDisplayID displayID) {
if (_glfw.ns.displayLinks.count >= arraysz(_glfw.ns.displayLinks.entries) - 1) {
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
return NULL;
}
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return;
// already created in this run
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return _glfw.ns.displayLinks.entries + i;
}
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
entry->displayID = displayID;
_glfw_create_cv_display_link(entry);
return entry;
}
// Poll for changes in the set of connected monitors
@@ -369,11 +374,13 @@ createDisplayLink(CGDirectDisplayID displayID) {
void _glfwPollMonitorsNS(void)
{
uint32_t displayCount;
CGGetOnlineDisplayList(0, NULL, &displayCount);
CGDirectDisplayID* displays = calloc(displayCount, sizeof(CGDirectDisplayID));
CGGetOnlineDisplayList(displayCount, displays, &displayCount);
_glfwClearDisplayLinks();
if (_glfw.hints.init.debugRendering) {
fprintf(stderr, "Polling for monitors: %u found\n", displayCount);
}
for (int i = 0; i < _glfw.monitorCount; i++)
_glfw.monitors[i]->ns.screen = nil;
@@ -390,8 +397,10 @@ void _glfwPollMonitorsNS(void)
for (uint32_t i = 0; i < displayCount; i++)
{
if (CGDisplayIsAsleep(displays[i]))
if (CGDisplayIsAsleep(displays[i])) {
if (_glfw.hints.init.debugRendering) fprintf(stderr, "Ignoring sleeping display: %u", displays[i]);
continue;
}
const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
NSScreen* screen = nil;
@@ -415,7 +424,9 @@ void _glfwPollMonitorsNS(void)
{
if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
{
disconnected[j]->ns.displayID = displays[i];
disconnected[j]->ns.screen = screen;
_glfw_create_display_link(displays[i]);
disconnected[j] = NULL;
break;
}
@@ -426,14 +437,17 @@ void _glfwPollMonitorsNS(void)
const CGSize size = CGDisplayScreenSize(displays[i]);
char* name = getDisplayName(displays[i], screen);
if (!name)
continue;
if (!name) {
_glfwInputError(GLFW_PLATFORM_ERROR,
"Failed to get name for display, using generic name");
name = _glfw_strdup("Display with no name");
}
_GLFWmonitor* monitor = _glfwAllocMonitor(name, (int)size.width, (int)size.height);
monitor->ns.displayID = displays[i];
monitor->ns.unitNumber = unitNumber;
monitor->ns.screen = screen;
createDisplayLink(monitor->ns.displayID);
_glfw_create_display_link(monitor->ns.displayID);
free(name);

View File

@@ -250,3 +250,4 @@ void _glfwDispatchRenderFrame(CGDirectDisplayID);
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
void _glfwCocoaPostEmptyEvent(void);
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
_GLFWDisplayLinkNS* _glfw_create_display_link(CGDirectDisplayID);

View File

@@ -337,9 +337,12 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
}
monotonic_t now = glfwGetTime();
bool found_display_link = false;
_GLFWDisplayLinkNS *dl = NULL;
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
_GLFWDisplayLinkNS *dl = &_glfw.ns.displayLinks.entries[i];
dl = &_glfw.ns.displayLinks.entries[i];
if (dl->displayID == displayID) {
found_display_link = true;
dl->lastRenderFrameRequestedAt = now;
if (!dl->first_unserviced_render_frame_request_at) dl->first_unserviced_render_frame_request_at = now;
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
@@ -359,6 +362,14 @@ requestRenderFrame(_GLFWwindow *w, GLFWcocoarenderframefun callback) {
dl->first_unserviced_render_frame_request_at = 0;
}
}
if (!found_display_link) {
dl = _glfw_create_display_link(displayID);
if (dl) {
dl->lastRenderFrameRequestedAt = now;
dl->first_unserviced_render_frame_request_at = now;
if (!CVDisplayLinkIsRunning(dl->displayLink)) CVDisplayLinkStart(dl->displayLink);
}
}
}
void

37
glfw/wl_window.c vendored
View File

@@ -254,6 +254,14 @@ dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height
_glfwInputWindowDamage(window);
}
static void
inform_compositor_of_window_geometry(_GLFWwindow *window, const char *event) {
#define geometry window->wl.decorations.geometry
debug("Setting window geometry in %s event: x=%d y=%d %dx%d\n", event, geometry.x, geometry.y, geometry.width, geometry.height);
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x, geometry.y, geometry.width, geometry.height);
#undef geometry
}
static void
xdgDecorationHandleConfigure(void* data,
@@ -263,15 +271,22 @@ xdgDecorationHandleConfigure(void* data,
_GLFWwindow* window = data;
bool has_server_side_decorations = (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
debug("XDG decoration configure event received: Has server side decorations: %d\n", has_server_side_decorations);
if (!has_server_side_decorations && window->wl.decorations.serverSide) {
// this can happen for example on sway where it has a "border toggle" function
// that turns on/off the server side decorations. In such a case, we dont turn
// on client side decorations, as that causes things to break.
return;
}
debug("XDG decoration configure event received: has_server_side_decorations: %d\n", has_server_side_decorations);
if (has_server_side_decorations == window->wl.decorations.serverSide) return;
window->wl.decorations.serverSide = has_server_side_decorations;
int width = window->wl.width, height = window->wl.height;
if (window->wl.decorations.serverSide) {
free_csd_surfaces(window);
height += window->wl.decorations.metrics.visible_titlebar_height;
} else {
ensure_csd_resources(window);
}
set_csd_window_geometry(window, &width, &height);
dispatchChangesAfterConfigure(window, width, height);
ensure_csd_resources(window);
wl_surface_commit(window->wl.surface);
debug("final window content size: %dx%d\n", window->wl.width, window->wl.height);
inform_compositor_of_window_geometry(window, "configure-decorations");
}
static const struct zxdg_toplevel_decoration_v1_listener xdgDecorationListener = {
@@ -405,14 +420,6 @@ _glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
return !already_fullscreen;
}
static void
inform_compositor_of_window_geometry(_GLFWwindow *window, const char *event) {
#define geometry window->wl.decorations.geometry
debug("Setting window geometry in %s event: x=%d y=%d %dx%d\n", event, geometry.x, geometry.y, geometry.width, geometry.height);
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x, geometry.y, geometry.width, geometry.height);
#undef geometry
}
static void
xdgToplevelHandleConfigure(void* data,
struct xdg_toplevel* toplevel UNUSED,

View File

@@ -182,6 +182,8 @@ def generate_class(defn: Definition, loc: str) -> Tuple[str, str]:
a(' config_overrides: typing.Tuple[str, ...] = ()')
a('')
a(' def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:')
if defn.has_color_table:
a(' self.color_table = array(self.color_table.typecode, self.color_table)')
a(' if options_dict is not None:')
a(' for key in option_names:')
a(' setattr(self, key, options_dict[key])')

View File

@@ -23,7 +23,7 @@ class Version(NamedTuple):
appname: str = 'kitty'
kitty_face = '🐱'
version: Version = Version(0, 22, 1)
version: Version = Version(0, 22, 2)
str_version: str = '.'.join(map(str, version))
_plat = sys.platform.lower()
is_macos: bool = 'darwin' in _plat

View File

@@ -7,12 +7,14 @@ from functools import partial
from pprint import pformat
from typing import Callable, Dict, Generator, Iterable, Set, Tuple
from kittens.tui.operations import colored, styled
from .cli import version
from .conf.utils import KeyAction
from .constants import is_macos, is_wayland
from kittens.tui.operations import colored
from .options.types import Options as KittyOpts, defaults
from .options.utils import MouseMap
from .rgb import Color, color_as_sharp
from .types import MouseEvent, SingleKey
from .typing import SequenceMap
@@ -113,6 +115,7 @@ def compare_opts(opts: KittyOpts, print: Callable) -> None:
]
field_len = max(map(len, changed_opts)) if changed_opts else 20
fmt = '{{:{:d}s}}'.format(field_len)
colors = []
for f in changed_opts:
val = getattr(opts, f)
if isinstance(val, dict):
@@ -123,7 +126,11 @@ def compare_opts(opts: KittyOpts, print: Callable) -> None:
else:
print(pformat(val))
else:
print(title(fmt.format(f)), str(getattr(opts, f)))
val = getattr(opts, f)
if isinstance(val, Color):
colors.append(fmt.format(f) + ' ' + color_as_sharp(val) + ' ' + styled(' ', bg=val))
else:
print(fmt.format(f), str(getattr(opts, f)))
compare_mousemaps(opts.mousemap, default_opts.mousemap, print)
final_, initial_ = opts.keymap, default_opts.keymap
@@ -133,6 +140,9 @@ def compare_opts(opts: KittyOpts, print: Callable) -> None:
final.update(final_s)
initial.update(initial_s)
compare_keymaps(final, initial, print)
if colors:
print(f'{title("Colors")}:', end='\n\t')
print('\n\t'.join(sorted(colors)))
def debug_config(opts: KittyOpts) -> str:

View File

@@ -606,6 +606,7 @@ class Options:
config_overrides: typing.Tuple[str, ...] = ()
def __init__(self, options_dict: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:
self.color_table = array(self.color_table.typecode, self.color_table)
if options_dict is not None:
for key in option_names:
setattr(self, key, options_dict[key])