mirror of
https://github.com/FelixKratz/SketchyBar
synced 2024-11-10 05:44:16 +00:00
add space_windows_change event (#435)
This commit is contained in:
parent
4ba2290ac3
commit
f3eafac1a3
15 changed files with 334 additions and 18 deletions
2
makefile
2
makefile
|
@ -18,7 +18,7 @@ _OBJ = alias.o background.o bar_item.o custom_events.o event.o graph.o \
|
|||
image.o mouse.o shadow.o font.o text.o message.o mouse.o bar.o color.o \
|
||||
window.o bar_manager.o display.o group.o mach.o popup.o \
|
||||
animation.o workspace.om volume.o slider.o power.o wifi.om media.om \
|
||||
hotload.o
|
||||
hotload.o app_windows.o
|
||||
|
||||
OBJ = $(patsubst %, $(ODIR)/%, $(_OBJ))
|
||||
|
||||
|
|
246
src/app_windows.c
Normal file
246
src/app_windows.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
#include "app_windows.h"
|
||||
#include "workspace.h"
|
||||
#include "misc/helpers.h"
|
||||
#include "event.h"
|
||||
|
||||
extern pid_t g_pid;
|
||||
struct app_windows g_windows = { 0 };
|
||||
bool g_space_window_events = false;
|
||||
|
||||
static bool iterator_window_suitable(CFTypeRef iterator) {
|
||||
uint64_t tags = SLSWindowIteratorGetTags(iterator);
|
||||
uint64_t attributes = SLSWindowIteratorGetAttributes(iterator);
|
||||
uint32_t parent_wid = SLSWindowIteratorGetParentID(iterator);
|
||||
if (((parent_wid == 0)
|
||||
&& ((attributes & 0x2)
|
||||
|| (tags & 0x400000000000000))
|
||||
&& (((tags & 0x1))
|
||||
|| ((tags & 0x2)
|
||||
&& (tags & 0x80000000))))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void app_window_clear(struct app_window* window) {
|
||||
memset(window, 0, sizeof(struct app_window));
|
||||
}
|
||||
|
||||
void app_windows_add(struct app_windows* windows, struct app_window* window) {
|
||||
for (int i = 0; i < windows->num_windows; i++) {
|
||||
if (!windows->windows[i].wid) {
|
||||
windows->windows[i] = *window;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
windows->windows = realloc(windows->windows,
|
||||
sizeof(struct app_window)
|
||||
* ++windows->num_windows);
|
||||
|
||||
windows->windows[windows->num_windows - 1] = *window;
|
||||
}
|
||||
|
||||
void app_windows_clear_space(struct app_windows* windows, uint64_t sid) {
|
||||
for (int i = 0; i < windows->num_windows; i++) {
|
||||
if (windows->windows[i].sid == sid)
|
||||
app_window_clear(windows->windows + i);
|
||||
}
|
||||
}
|
||||
|
||||
bool app_windows_find(struct app_windows* windows, struct app_window* window) {
|
||||
for (int i = 0; i < windows->num_windows; i++) {
|
||||
if (windows->windows[i].wid == window->wid
|
||||
&& windows->windows[i].sid == window->sid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool app_window_suitable(struct app_window* window) {
|
||||
CFArrayRef target_ref = cfarray_of_cfnumbers(&window->wid,
|
||||
sizeof(uint32_t),
|
||||
1,
|
||||
kCFNumberSInt32Type);
|
||||
|
||||
if (!target_ref) return false;
|
||||
|
||||
bool suitable = false;
|
||||
CFTypeRef query = SLSWindowQueryWindows(g_connection, target_ref, 0x0);
|
||||
if (query) {
|
||||
CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);
|
||||
if (iterator && SLSWindowIteratorGetCount(iterator) > 0) {
|
||||
if (SLSWindowIteratorAdvance(iterator)) {
|
||||
if (iterator_window_suitable(iterator)) {
|
||||
suitable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (iterator) CFRelease(iterator);
|
||||
CFRelease(query);
|
||||
}
|
||||
CFRelease(target_ref);
|
||||
return suitable;
|
||||
}
|
||||
|
||||
static void app_windows_post_event_for_space(struct app_windows* windows, uint64_t sid) {
|
||||
int index = mission_control_index(sid);
|
||||
pid_t pid_list[windows->num_windows];
|
||||
uint32_t pid_count[windows->num_windows];
|
||||
char* pid_name[windows->num_windows];
|
||||
|
||||
memset(&pid_list, 0, sizeof(pid_t)*windows->num_windows);
|
||||
memset(&pid_count, 0, sizeof(uint32_t)*windows->num_windows);
|
||||
memset(&pid_name, 0, sizeof(char*)*windows->num_windows);
|
||||
|
||||
uint32_t length = 64;
|
||||
for (int i = 0; i < windows->num_windows; i++) {
|
||||
for (int j = 0; j < windows->num_windows; j++) {
|
||||
if ((!pid_list[j] || pid_list[j] == windows->windows[i].pid)
|
||||
&& windows->windows[i].sid == sid) {
|
||||
pid_list[j] = windows->windows[i].pid;
|
||||
pid_count[j]++;
|
||||
if (!pid_name[j]) {
|
||||
pid_name[j] = workspace_copy_app_name_for_pid(pid_list[j]);
|
||||
length += pid_name[j] ? strlen(pid_name[j]) + 16 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char payload[length];
|
||||
memset(payload, 0, length);
|
||||
snprintf(payload, length, "{\n"
|
||||
"\t\"space\": %d,\n"
|
||||
"\t\"apps\": {\n",
|
||||
index );
|
||||
|
||||
char* cursor = payload + strlen(payload);
|
||||
bool first = true;
|
||||
for (int i = 0; i < windows->num_windows; i++) {
|
||||
if (!pid_list[i]) break;
|
||||
if (!pid_name[i]) continue;
|
||||
if (!first) {
|
||||
snprintf(cursor, length - (cursor - payload), ",\n");
|
||||
cursor = payload + strlen(payload);
|
||||
} else first = false;
|
||||
snprintf(cursor,
|
||||
length - (cursor - payload),
|
||||
"\t\t\"%s\": %d",
|
||||
pid_name[i],
|
||||
pid_count[i] );
|
||||
|
||||
free(pid_name[i]);
|
||||
cursor = payload + strlen(payload);
|
||||
}
|
||||
|
||||
|
||||
snprintf(cursor, length - (cursor - payload), "\n\t}\n}\n");
|
||||
struct event event = { payload, SPACE_WINDOWS_CHANGED };
|
||||
event_post(&event);
|
||||
}
|
||||
|
||||
static void app_windows_update_space(struct app_windows* windows, uint64_t sid, bool silent) {
|
||||
app_windows_clear_space(windows, sid);
|
||||
CFArrayRef space_list_ref = cfarray_of_cfnumbers(&sid,
|
||||
sizeof(uint64_t),
|
||||
1,
|
||||
kCFNumberSInt64Type);
|
||||
|
||||
uint64_t set_tags = 1;
|
||||
uint64_t clear_tags = 0;
|
||||
CFArrayRef window_list = SLSCopyWindowsWithOptionsAndTags(g_connection,
|
||||
0,
|
||||
space_list_ref,
|
||||
0x2,
|
||||
&set_tags,
|
||||
&clear_tags );
|
||||
|
||||
if (window_list) {
|
||||
uint32_t window_count = CFArrayGetCount(window_list);
|
||||
if (window_count > 0) {
|
||||
CFTypeRef query = SLSWindowQueryWindows(g_connection, window_list, 0x0);
|
||||
if (query) {
|
||||
CFTypeRef iterator = SLSWindowQueryResultCopyWindows(query);
|
||||
if (iterator) {
|
||||
while(SLSWindowIteratorAdvance(iterator)) {
|
||||
if (iterator_window_suitable(iterator)) {
|
||||
uint32_t wid = SLSWindowIteratorGetWindowID(iterator);
|
||||
int wid_cid = 0;
|
||||
SLSGetWindowOwner(g_connection, wid, &wid_cid);
|
||||
|
||||
pid_t pid = 0;
|
||||
SLSConnectionGetPID(wid_cid, &pid);
|
||||
struct app_window window = { .wid = wid,
|
||||
.sid = sid,
|
||||
.pid = pid };
|
||||
app_windows_add(windows, &window);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(query);
|
||||
}
|
||||
}
|
||||
CFRelease(window_list);
|
||||
}
|
||||
|
||||
CFRelease(space_list_ref);
|
||||
if (!silent) app_windows_post_event_for_space(windows, sid);
|
||||
}
|
||||
|
||||
struct window_spawn_data {
|
||||
uint64_t sid;
|
||||
uint32_t wid;
|
||||
};
|
||||
|
||||
static void window_spawn_handler(uint32_t event, struct window_spawn_data* data, size_t _, int cid) {
|
||||
uint32_t wid = data->wid;
|
||||
uint64_t sid = data->sid;
|
||||
|
||||
if (!wid || !sid) return;
|
||||
|
||||
struct app_window window = { .wid = wid, .sid = sid, .pid = 0 };
|
||||
|
||||
if (event == 1325 && app_window_suitable(&window)) {
|
||||
app_windows_update_space(&g_windows, sid, false);
|
||||
} else if (event == 1326) {
|
||||
bool found = app_windows_find(&g_windows, &window);
|
||||
if (found) {
|
||||
app_windows_update_space(&g_windows, sid, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_all_spaces(struct app_windows* windows, bool silent) {
|
||||
uint32_t display_count = 0;
|
||||
uint32_t* displays = display_active_display_list(&display_count);
|
||||
for (int i = 0; i < display_count; i++) {
|
||||
int space_count = 0;
|
||||
uint64_t* spaces = display_space_list(displays[i], &space_count);
|
||||
for (int j = 0; j < space_count; j++) {
|
||||
app_windows_update_space(windows, spaces[j], silent);
|
||||
}
|
||||
if (spaces) free(spaces);
|
||||
}
|
||||
if (displays) free(displays);
|
||||
}
|
||||
|
||||
void forced_space_windows_event() {
|
||||
if (g_space_window_events) update_all_spaces(&g_windows, false);
|
||||
}
|
||||
|
||||
void begin_receiving_space_window_events() {
|
||||
if (!g_space_window_events) {
|
||||
SLSRegisterNotifyProc(window_spawn_handler,
|
||||
1325,
|
||||
(void*)(intptr_t)g_connection);
|
||||
|
||||
SLSRegisterNotifyProc(window_spawn_handler,
|
||||
1326,
|
||||
(void*)(intptr_t)g_connection);
|
||||
g_space_window_events = true;
|
||||
update_all_spaces(&g_windows, true);
|
||||
}
|
||||
}
|
30
src/app_windows.h
Normal file
30
src/app_windows.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include "event.h"
|
||||
|
||||
extern CGError SLSGetWindowOwner(int cid, uint32_t wid, int* out_cid);
|
||||
extern CGError SLSConnectionGetPID(int cid, pid_t *pid);
|
||||
extern CFArrayRef SLSCopyWindowsWithOptionsAndTags(int cid, uint32_t owner, CFArrayRef spaces, uint32_t options, uint64_t *set_tags, uint64_t *clear_tags);
|
||||
extern CFTypeRef SLSWindowQueryWindows(int cid, CFArrayRef windows, uint32_t options);
|
||||
extern CFTypeRef SLSWindowQueryResultCopyWindows(CFTypeRef window_query);
|
||||
extern int SLSWindowIteratorGetCount(CFTypeRef iterator);
|
||||
extern bool SLSWindowIteratorAdvance(CFTypeRef iterator);
|
||||
extern uint32_t SLSWindowIteratorGetParentID(CFTypeRef iterator);
|
||||
extern uint32_t SLSWindowIteratorGetWindowID(CFTypeRef iterator);
|
||||
extern uint64_t SLSWindowIteratorGetTags(CFTypeRef iterator);
|
||||
extern uint64_t SLSWindowIteratorGetAttributes(CFTypeRef iterator);
|
||||
extern CGError SLSRegisterNotifyProc(void* callback, uint32_t event, void* context);
|
||||
|
||||
struct app_window {
|
||||
uint32_t wid;
|
||||
uint64_t sid;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct app_windows {
|
||||
struct app_window* windows;
|
||||
uint32_t num_windows;
|
||||
};
|
||||
|
||||
|
||||
void begin_receiving_space_window_events();
|
||||
void forced_space_windows_event();
|
|
@ -4,6 +4,7 @@
|
|||
#include "volume.h"
|
||||
#include "power.h"
|
||||
#include "media.h"
|
||||
#include "app_windows.h"
|
||||
|
||||
struct bar_item* bar_item_create() {
|
||||
struct bar_item* bar_item = malloc(sizeof(struct bar_item));
|
||||
|
@ -1234,6 +1235,10 @@ void bar_item_parse_subscribe_message(struct bar_item* bar_item, char* message,
|
|||
begin_receiving_media_events();
|
||||
}
|
||||
|
||||
if (event_flag & UPDATE_SPACE_WINDOWS_CHANGE) {
|
||||
begin_receiving_space_window_events();
|
||||
}
|
||||
|
||||
bar_item->update_mask |= event_flag;
|
||||
|
||||
if (!event_flag) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "power.h"
|
||||
#include "mouse.h"
|
||||
#include "media.h"
|
||||
#include "app_windows.h"
|
||||
|
||||
extern void forced_front_app_event();
|
||||
|
||||
|
@ -524,6 +525,7 @@ void bar_manager_update(struct bar_manager* bar_manager, bool forced) {
|
|||
forced_power_event();
|
||||
forced_front_app_event();
|
||||
forced_media_change_event();
|
||||
forced_space_windows_event();
|
||||
}
|
||||
|
||||
bool needs_refresh = false;
|
||||
|
@ -906,6 +908,16 @@ void bar_manager_handle_front_app_switch(struct bar_manager* bar_manager, char*
|
|||
env_vars_destroy(&env_vars);
|
||||
}
|
||||
|
||||
void bar_manager_handle_space_windows_change(struct bar_manager* bar_manager, char* info) {
|
||||
struct env_vars env_vars;
|
||||
env_vars_init(&env_vars);
|
||||
if (info) env_vars_set(&env_vars, string_copy("INFO"), string_copy(info));
|
||||
bar_manager_custom_events_trigger(bar_manager,
|
||||
COMMAND_SUBSCRIBE_SPACE_WINDOWS_CHANGE,
|
||||
&env_vars );
|
||||
env_vars_destroy(&env_vars);
|
||||
}
|
||||
|
||||
void bar_manager_handle_space_change(struct bar_manager* bar_manager, bool forced) {
|
||||
struct env_vars env_vars;
|
||||
env_vars_init(&env_vars);
|
||||
|
|
|
@ -119,6 +119,7 @@ void bar_manager_handle_brightness_change(struct bar_manager* bar_manager, float
|
|||
void bar_manager_handle_power_source_change(struct bar_manager* bar_manager, char* state);
|
||||
void bar_manager_handle_media_change(struct bar_manager* bar_manager, char* info);
|
||||
void bar_manager_handle_media_cover_change(struct bar_manager* bar_manager, CGImageRef image);
|
||||
void bar_manager_handle_space_windows_change(struct bar_manager* bar_manager, char* info);
|
||||
void bar_manager_custom_events_trigger(struct bar_manager* bar_manager, char* name, struct env_vars* env_vars);
|
||||
|
||||
void bar_manager_destroy(struct bar_manager* bar_manager);
|
||||
|
|
|
@ -37,6 +37,7 @@ void custom_events_init(struct custom_events* custom_events) {
|
|||
custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_POWER_SOURCE_CHANGE), NULL);
|
||||
custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_WIFI_CHANGE), NULL);
|
||||
custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_MEDIA_CHANGE), NULL);
|
||||
custom_events_append(custom_events, string_copy(COMMAND_SUBSCRIBE_SPACE_WINDOWS_CHANGE), NULL);
|
||||
}
|
||||
|
||||
void custom_events_append(struct custom_events* custom_events, char* name, char* notification) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define UPDATE_POWER_SOURCE_CHANGE 1ULL << 14
|
||||
#define UPDATE_WIFI_CHANGE 1ULL << 15
|
||||
#define UPDATE_MEDIA_CHANGE 1ULL << 16
|
||||
#define UPDATE_SPACE_WINDOWS_CHANGE 1ULL << 17
|
||||
|
||||
extern void* g_workspace_context;
|
||||
extern void workspace_create_custom_observer(void** context, char* name);
|
||||
|
|
|
@ -34,6 +34,7 @@ uint32_t display_arrangement_display_id(int arrangement);
|
|||
bool display_menu_bar_visible(void);
|
||||
CGRect display_menu_bar_rect(uint32_t did);
|
||||
uint32_t display_active_display_count(void);
|
||||
uint32_t *display_active_display_list(uint32_t *count);
|
||||
bool display_begin(void);
|
||||
bool display_end(void);
|
||||
|
||||
|
|
|
@ -329,6 +329,10 @@ static void event_cover_changed(void* context) {
|
|||
bar_manager_handle_media_cover_change(&g_bar_manager, (CGImageRef)context);
|
||||
}
|
||||
|
||||
static void event_space_windows_changed(void* context) {
|
||||
bar_manager_handle_space_windows_change(&g_bar_manager, (char*)context);
|
||||
}
|
||||
|
||||
static void event_hotload(void* context) {
|
||||
bar_manager_destroy(&g_bar_manager);
|
||||
bar_manager_init(&g_bar_manager);
|
||||
|
@ -364,6 +368,7 @@ static callback_type* event_handler[] = {
|
|||
[ANIMATOR_REFRESH] = event_animator_refresh,
|
||||
[MACH_MESSAGE] = event_mach_message,
|
||||
[HOTLOAD] = event_hotload,
|
||||
[SPACE_WINDOWS_CHANGED] = event_space_windows_changed,
|
||||
};
|
||||
|
||||
extern pthread_mutex_t g_event_mutex;
|
||||
|
|
|
@ -28,6 +28,7 @@ enum event_type {
|
|||
POWER_SOURCE_CHANGED,
|
||||
MEDIA_CHANGED,
|
||||
COVER_CHANGED,
|
||||
SPACE_WINDOWS_CHANGED,
|
||||
DISTRIBUTED_NOTIFICATION,
|
||||
HOTLOAD,
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
#define COMMAND_SUBSCRIBE_MOUSE_ENTERED_GLOBAL "mouse.entered.global"
|
||||
#define COMMAND_SUBSCRIBE_MOUSE_EXITED_GLOBAL "mouse.exited.global"
|
||||
#define COMMAND_SUBSCRIBE_MOUSE_SCROLLED_GLOBAL "mouse.scrolled.global"
|
||||
#define COMMAND_SUBSCRIBE_SPACE_WINDOWS_CHANGE "space_windows_change"
|
||||
|
||||
#define DOMAIN_QUERY "--query"
|
||||
#define COMMAND_QUERY_DEFAULT_ITEMS "default_menu_items"
|
||||
|
|
|
@ -50,6 +50,7 @@ char g_lock_file[MAXLEN];
|
|||
bool g_volume_events;
|
||||
bool g_brightness_events;
|
||||
int64_t g_disable_capture = 0;
|
||||
pid_t g_pid = 0;
|
||||
|
||||
static int client_send_message(int argc, char **argv) {
|
||||
if (argc <= 1) {
|
||||
|
@ -187,6 +188,7 @@ int main(int argc, char **argv) {
|
|||
if (is_root())
|
||||
error("%s: running as root is not allowed! abort..\n", g_name);
|
||||
|
||||
pid_for_task(mach_task_self(), &g_pid);
|
||||
init_misc_settings();
|
||||
acquire_lockfile();
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ int workspace_display_notch_height(uint32_t did);
|
|||
float workspace_get_scale();
|
||||
|
||||
CGImageRef workspace_icon_for_app(char* app);
|
||||
char* workspace_copy_app_name_for_pid(pid_t pid);
|
||||
|
|
|
@ -74,6 +74,15 @@ void forced_front_app_event() {
|
|||
}
|
||||
}
|
||||
|
||||
char* workspace_copy_app_name_for_pid(pid_t pid) {
|
||||
const char* result = NULL;
|
||||
@autoreleasepool {
|
||||
NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
|
||||
result = [[app localizedName] UTF8String];
|
||||
}
|
||||
return result ? string_copy((char*)result) : NULL;
|
||||
}
|
||||
|
||||
CGImageRef workspace_icon_for_app(char* app) {
|
||||
@autoreleasepool {
|
||||
NSString* ns_app = [NSString stringWithUTF8String:app];
|
||||
|
|
Loading…
Reference in a new issue