-
-
Notifications
You must be signed in to change notification settings - Fork 659
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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: