-
-
Notifications
You must be signed in to change notification settings - Fork 643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Window animations still flicker at random #2129
Comments
Added commit that eliminates flicker, but it also breaks JankyBorders inregration. Hopefully I can work out a solution together with Felix that makes both of these compatible in the end. The flicker is very noticable and distracting, so I will prioritize this over the border integration if I can only have one. |
I put together some debug code; you can apply this patch to yabai when you want to investigate further. diff --git a/src/yabai.c b/src/yabai.c
index 0afe9ed..83baab0 100644
--- a/src/yabai.c
+++ b/src/yabai.c
@@ -24,6 +24,7 @@
#define MINOR 0
#define PATCH 15
+static id (* SLSWMBridgeDelegate)(void);
struct signal *g_signal_event[SIGNAL_TYPE_COUNT];
struct process_manager g_process_manager;
struct display_manager g_display_manager;
@@ -51,6 +52,50 @@ int g_connection;
bool g_verbose;
pid_t g_pid;
+static void dump_class_info(Class c)
+{
+ const char *name = class_getName(c);
+ NSLog(@"DUMP::%s\n", name);
+
+ unsigned int count = 0;
+
+ Ivar *ivar_list = class_copyIvarList(c, &count);
+ for (int i = 0; i < count; i++) {
+ Ivar ivar = ivar_list[i];
+ const char *ivar_name = ivar_getName(ivar);
+ NSLog(@"%s ivar: %s", name, ivar_name);
+ }
+ if (ivar_list) free(ivar_list);
+
+ objc_property_t *property_list = class_copyPropertyList(c, &count);
+ for (int i = 0; i < count; i++) {
+ objc_property_t property = property_list[i];
+ const char *prop_name = property_getName(property);
+ NSLog(@"%s property: %s", name, prop_name);
+ }
+ if (property_list) free(property_list);
+
+ Method *method_list = class_copyMethodList(c, &count);
+ for (int i = 0; i < count; i++) {
+ Method method = method_list[i];
+ const char *method_name = sel_getName(method_getName(method));
+ NSLog(@"%s method: %s", name, method_name);
+ }
+ if (method_list) free(method_list);
+}
+
+static inline id get_ivar_value(id instance, const char *name)
+{
+ id result = nil;
+ object_getInstanceVariable(instance, name, (void **) &result);
+ return result;
+}
+
+static inline void set_ivar_value(id instance, const char *name, id value)
+{
+ object_setInstanceVariable(instance, name, value);
+}
+
static int client_send_message(int argc, char **argv)
{
if (argc <= 1) {
@@ -167,6 +212,84 @@ static void exec_config_file(void)
}
}
+struct BlockDescriptor {
+ unsigned long reserved;
+ unsigned long size;
+ void *rest[1];
+};
+
+struct Block {
+ void *isa;
+ int flags;
+ int reserved;
+ void *invoke;
+ struct BlockDescriptor *descriptor;
+};
+
+static const char *BlockSig(id blockObj)
+{
+ struct Block *block = (void *)blockObj;
+ struct BlockDescriptor *descriptor = block->descriptor;
+
+ int copyDisposeFlag = 1 << 25;
+ int signatureFlag = 1 << 30;
+
+ assert(block->flags & signatureFlag);
+
+ int index = 0;
+ if(block->flags & copyDisposeFlag)
+ index += 2;
+
+ return descriptor->rest[index];
+}
+
+static void *BlockHandler(id blockObj)
+{
+ struct Block *block = (void *)blockObj;
+ return block->invoke;
+}
+
+@implementation NSObject(swizzle)
+- (void)fake_performAsynchronousBridgedWindowManagementOperation:(id)instance
+{
+ printf("%s\n", __FUNCTION__);
+ return;
+}
+- (void)fake_performSynchronousBridgedWindowManagementOperation:(id)instance
+{
+ printf("%s\n", __FUNCTION__);
+ return;
+}
+- (void)fake_performWindowManagementBridgeTransactionUsingBlock:(id)arg1
+{
+ uint64_t address = (uint64_t)arg1;
+ printf("\n");
+ printf("FUNC: %s\n", __FUNCTION__);
+ printf("ARG1: %p\n", arg1);
+ printf("ARG1 class: %s\n", [NSStringFromClass([arg1 class]) UTF8String]);
+ printf("ARG1 description: %s\n", [[arg1 description] UTF8String]);
+ printf("ARG1 signature: %s\n", BlockSig(arg1));
+ printf("ARG1 handler: %p\n", BlockHandler(arg1));
+ printf("\n");
+
+ void *addr[40];
+ int frame_count = backtrace(addr, sizeof(addr)/sizeof(*addr));
+ if (frame_count > 1) {
+ char **syms = backtrace_symbols(addr, frame_count);
+ for (int f = 0; f < frame_count; ++f) {
+ printf("%s\n", syms[f]);
+ }
+ printf("\n");
+ free(syms);
+ } else {
+ printf("*** Failed to generate backtrace.");
+ }
+
+ [self fake_performWindowManagementBridgeTransactionUsingBlock:arg1];
+ return;
+}
+@end
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
static inline bool configure_settings_and_acquire_lock(void)
@@ -180,6 +303,12 @@ static inline bool configure_settings_and_acquire_lock(void)
snprintf(g_socket_file, sizeof(g_socket_file), SOCKET_PATH_FMT, user);
snprintf(g_lock_file, sizeof(g_lock_file), LCFILE_PATH_FMT, user);
+ CGSGetConnectionPortById = macho_find_symbol("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", "_CGSGetConnectionPortById");
+ SLSWMBridgeDelegate = macho_find_symbol("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", "__ZL19SLSWMBridgeDelegatev");
+ SLSWindowManagementBridgeSetDelegate = macho_find_symbol("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", "_SLSWindowManagementBridgeSetDelegate");
+ // if (SLSWindowManagementBridgeSetDelegate) SLSWindowManagementBridgeSetDelegate(NULL);
+ id delegate = SLSWMBridgeDelegate ? SLSWMBridgeDelegate() : NULL;
+
NSApplicationLoad();
g_pid = getpid();
g_event_bytes = malloc(0xf8);
@@ -189,10 +318,6 @@ static inline bool configure_settings_and_acquire_lock(void)
g_layer_below_window_level = CGWindowLevelForKey(LAYER_BELOW);
g_layer_above_window_level = CGWindowLevelForKey(LAYER_ABOVE);
- CGSGetConnectionPortById = macho_find_symbol("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", "_CGSGetConnectionPortById");
- SLSWindowManagementBridgeSetDelegate = macho_find_symbol("/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", "_SLSWindowManagementBridgeSetDelegate");
- if (SLSWindowManagementBridgeSetDelegate) SLSWindowManagementBridgeSetDelegate(NULL);
-
signal(SIGCHLD, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
CGSetLocalEventsSuppressionInterval(0.0f);
@@ -200,6 +325,60 @@ static inline bool configure_settings_and_acquire_lock(void)
mouse_state_init(&g_mouse_state);
task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &g_bs_port);
+ if (delegate) {
+ dump_class_info([delegate class]);
+
+ id manager = get_ivar_value(delegate, "_manager");
+ dump_class_info([manager class]);
+
+ // set_ivar_value(delegate, "_manager", NULL);
+ // set_ivar_value(manager, "_delegate", NULL);
+ // [manager setDelegate: NULL];
+
+ Class class = [delegate class];
+
+ {
+ SEL originalSelector = @selector(performWindowManagementBridgeTransactionUsingBlock:);
+ SEL swizzledSelector = @selector(fake_performWindowManagementBridgeTransactionUsingBlock:);
+
+ Method originalMethod = class_getInstanceMethod(class, originalSelector);
+ Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
+
+ IMP originalImp = method_getImplementation(originalMethod);
+ IMP swizzledImp = method_getImplementation(swizzledMethod);
+
+ class_replaceMethod(class, swizzledSelector, originalImp, method_getTypeEncoding(originalMethod));
+ class_replaceMethod(class, originalSelector, swizzledImp, method_getTypeEncoding(swizzledMethod));
+ }
+ {
+ SEL originalSelector = @selector(performAsynchronousBridgedWindowManagementOperation:);
+ SEL swizzledSelector = @selector(fake_performAsynchronousBridgedWindowManagementOperation:);
+
+ Method originalMethod = class_getInstanceMethod(class, originalSelector);
+ Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
+
+ IMP originalImp = method_getImplementation(originalMethod);
+ IMP swizzledImp = method_getImplementation(swizzledMethod);
+
+ class_replaceMethod(class, swizzledSelector, originalImp, method_getTypeEncoding(originalMethod));
+ class_replaceMethod(class, originalSelector, swizzledImp, method_getTypeEncoding(swizzledMethod));
+ }
+ {
+ SEL originalSelector = @selector(performSynchronousBridgedWindowManagementOperation:);
+ SEL swizzledSelector = @selector(fake_performSynchronousBridgedWindowManagementOperation:);
+
+ Method originalMethod = class_getInstanceMethod(class, originalSelector);
+ Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
+
+ IMP originalImp = method_getImplementation(originalMethod);
+ IMP swizzledImp = method_getImplementation(swizzledMethod);
+
+ class_replaceMethod(class, swizzledSelector, originalImp, method_getTypeEncoding(originalMethod));
+ class_replaceMethod(class, originalSelector, swizzledImp, method_getTypeEncoding(swizzledMethod));
+ }
+ }
+
+
#if 0
hook_nsobject_autorelease();
hook_autoreleasepool_drain(); |
So there are actually multiple things going on. When the program launches. Getting the WMBridge instance and dumping it results in :
After calling NSApplicationLoad, getting the WMBridge instance and dumping it results in:
Calling This flag is then checked internally by the windowserver before it attempts to perform some operation, deciding whether it should use a bridged operation or the "old" way. |
I noticed that there is code inside
This can be used instead of disabling the entire WMBridge, however, the window still won't respond to order-operations from JankyBorders. Edit: There is also a different code path inside |
Fixed in v7.0.0. |
Where do you find the code for those functions? I'm guessing you're looking at the disassembly, but I wonder how you knew where to look. |
I have a solution for this, but it breaks integration with JankyBorders FelixKratz/JankyBorders#62 (comment)
The text was updated successfully, but these errors were encountered: