mirror of
https://codeberg.org/tmayoff/.dotfiles.git
synced 2025-12-06 08:48:34 -05:00
added sketchybar config
This commit is contained in:
parent
87bb07f015
commit
95ebd7af03
38 changed files with 2329 additions and 0 deletions
313
dot_config/sketchybar/helpers/app_icons.lua
Normal file
313
dot_config/sketchybar/helpers/app_icons.lua
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
return {
|
||||
["Live"] = ":ableton:",
|
||||
["Adobe Bridge"] = ":adobe_bridge:",
|
||||
["Affinity Designer"] = ":affinity_designer:",
|
||||
["Affinity Designer 2"] = ":affinity_designer_2:",
|
||||
["Affinity Photo"] = ":affinity_photo:",
|
||||
["Affinity Photo 2"] = ":affinity_photo_2:",
|
||||
["Affinity Publisher"] = ":affinity_publisher:",
|
||||
["Affinity Publisher 2"] = ":affinity_publisher_2:",
|
||||
["Airmail"] = ":airmail:",
|
||||
["Alacritty"] = ":alacritty:",
|
||||
["Alfred"] = ":alfred:",
|
||||
["Android Messages"] = ":android_messages:",
|
||||
["Android Studio"] = ":android_studio:",
|
||||
["Anki"] = ":anki:",
|
||||
["Anytype"] = ":anytype:",
|
||||
["App Eraser"] = ":app_eraser:",
|
||||
["App Store"] = ":app_store:",
|
||||
["Arc"] = ":arc:",
|
||||
["Arduino"] = ":arduino:",
|
||||
["Arduino IDE"] = ":arduino:",
|
||||
["Atom"] = ":atom:",
|
||||
["Audacity"] = ":audacity:",
|
||||
["Bambu Studio"] = ":bambu_studio:",
|
||||
["MoneyMoney"] = ":bank:",
|
||||
["Battle.net"] = ":battle_net:",
|
||||
["Bear"] = ":bear:",
|
||||
["BetterTouchTool"] = ":bettertouchtool:",
|
||||
["Bilibili"] = ":bilibili:",
|
||||
["哔哩哔哩"] = ":bilibili:",
|
||||
["Bitwarden"] = ":bit_warden:",
|
||||
["Blender"] = ":blender:",
|
||||
["BluOS Controller"] = ":bluos_controller:",
|
||||
["Calibre"] = ":book:",
|
||||
["Brave Browser"] = ":brave_browser:",
|
||||
["BusyCal"] = ":busycal:",
|
||||
["Calculator"] = ":calculator:",
|
||||
["Calculette"] = ":calculator:",
|
||||
["Calendar"] = ":calendar:",
|
||||
["日历"] = ":calendar:",
|
||||
["Fantastical"] = ":calendar:",
|
||||
["Cron"] = ":calendar:",
|
||||
["Amie"] = ":calendar:",
|
||||
["Calendrier"] = ":calendar:",
|
||||
["Notion Calendar"] = ":calendar:",
|
||||
["Caprine"] = ":caprine:",
|
||||
["Amazon Chime"] = ":chime:",
|
||||
["Citrix Workspace"] = ":citrix:",
|
||||
["Citrix Viewer"] = ":citrix:",
|
||||
["Claude"] = ":claude:",
|
||||
["ClickUp"] = ":click_up:",
|
||||
["Code"] = ":code:",
|
||||
["Code - Insiders"] = ":code:",
|
||||
["Cold Turkey Blocker"] = ":cold_turkey_blocker:",
|
||||
["Color Picker"] = ":color_picker:",
|
||||
["数码测色计"] = ":color_picker:",
|
||||
["Copilot"] = ":copilot:",
|
||||
["CotEditor"] = ":coteditor:",
|
||||
["Creative Cloud"] = ":creative_cloud:",
|
||||
["Cursor"] = ":cursor:",
|
||||
["Cypress"] = ":cypress:",
|
||||
["DataGrip"] = ":datagrip:",
|
||||
["DataSpell"] = ":dataspell:",
|
||||
["DaVinci Resolve"] = ":davinciresolve:",
|
||||
["Deezer"] = ":deezer:",
|
||||
["Default"] = ":default:",
|
||||
["CleanMyMac X"] = ":desktop:",
|
||||
["DEVONthink 3"] = ":devonthink3:",
|
||||
["DingTalk"] = ":dingtalk:",
|
||||
["钉钉"] = ":dingtalk:",
|
||||
["阿里钉"] = ":dingtalk:",
|
||||
["Discord"] = ":discord:",
|
||||
["Discord Canary"] = ":discord:",
|
||||
["Discord PTB"] = ":discord:",
|
||||
["Docker"] = ":docker:",
|
||||
["Docker Desktop"] = ":docker:",
|
||||
["GrandTotal"] = ":dollar:",
|
||||
["Receipts"] = ":dollar:",
|
||||
["Double Commander"] = ":doublecmd:",
|
||||
["Drafts"] = ":drafts:",
|
||||
["draw.io"] = ":draw_io:",
|
||||
["Dropbox"] = ":dropbox:",
|
||||
["Element"] = ":element:",
|
||||
["Emacs"] = ":emacs:",
|
||||
["Evernote Legacy"] = ":evernote_legacy:",
|
||||
["FaceTime"] = ":face_time:",
|
||||
["FaceTime 通话"] = ":face_time:",
|
||||
["Figma"] = ":figma:",
|
||||
["Final Cut Pro"] = ":final_cut_pro:",
|
||||
["Finder"] = ":finder:",
|
||||
["访达"] = ":finder:",
|
||||
["Firefox"] = ":firefox:",
|
||||
["Firefox Developer Edition"] = ":firefox_developer_edition:",
|
||||
["Firefox Nightly"] = ":firefox_developer_edition:",
|
||||
["Folx"] = ":folx:",
|
||||
["Fork"] = ":fork:",
|
||||
["FreeTube"] = ":freetube:",
|
||||
["Fusion"] = ":fusion:",
|
||||
["System Preferences"] = ":gear:",
|
||||
["System Settings"] = ":gear:",
|
||||
["系统设置"] = ":gear:",
|
||||
["Réglages Système"] = ":gear:",
|
||||
["GitHub Desktop"] = ":git_hub:",
|
||||
["Godot"] = ":godot:",
|
||||
["GoLand"] = ":goland:",
|
||||
["Chromium"] = ":google_chrome:",
|
||||
["Google Chrome"] = ":google_chrome:",
|
||||
["Google Chrome Canary"] = ":google_chrome:",
|
||||
["Grammarly Editor"] = ":grammarly:",
|
||||
["Home Assistant"] = ":home_assistant:",
|
||||
["Hyper"] = ":hyper:",
|
||||
["IntelliJ IDEA"] = ":idea:",
|
||||
["IINA"] = ":iina:",
|
||||
["Adobe Illustrator"] = ":illustrator:",
|
||||
["Illustrator"] = ":illustrator:",
|
||||
["Adobe InDesign"] = ":indesign:",
|
||||
["InDesign"] = ":indesign:",
|
||||
["Inkdrop"] = ":inkdrop:",
|
||||
["Inkscape"] = ":inkscape:",
|
||||
["Insomnia"] = ":insomnia:",
|
||||
["Iris"] = ":iris:",
|
||||
["iTerm"] = ":iterm:",
|
||||
["iTerm2"] = ":iterm:",
|
||||
["Jellyfin Media Player"] = ":jellyfin:",
|
||||
["Joplin"] = ":joplin:",
|
||||
["카카오톡"] = ":kakaotalk:",
|
||||
["KakaoTalk"] = ":kakaotalk:",
|
||||
["Kakoune"] = ":kakoune:",
|
||||
["KeePassXC"] = ":kee_pass_x_c:",
|
||||
["Keyboard Maestro"] = ":keyboard_maestro:",
|
||||
["Keynote"] = ":keynote:",
|
||||
["Keynote 讲演"] = ":keynote:",
|
||||
["kitty"] = ":kitty:",
|
||||
["League of Legends"] = ":league_of_legends:",
|
||||
["LibreWolf"] = ":libre_wolf:",
|
||||
["Adobe Lightroom"] = ":lightroom:",
|
||||
["Lightroom Classic"] = ":lightroomclassic:",
|
||||
["LINE"] = ":line:",
|
||||
["Linear"] = ":linear:",
|
||||
["LM Studio"] = ":lm_studio:",
|
||||
["LocalSend"] = ":localsend:",
|
||||
["Logic Pro"] = ":logicpro:",
|
||||
["Logseq"] = ":logseq:",
|
||||
["Canary Mail"] = ":mail:",
|
||||
["HEY"] = ":mail:",
|
||||
["Mail"] = ":mail:",
|
||||
["Mailspring"] = ":mail:",
|
||||
["MailMate"] = ":mail:",
|
||||
["Superhuman"] = ":mail:",
|
||||
["Spark"] = ":mail:",
|
||||
["邮件"] = ":mail:",
|
||||
["MAMP"] = ":mamp:",
|
||||
["MAMP PRO"] = ":mamp:",
|
||||
["Maps"] = ":maps:",
|
||||
["Google Maps"] = ":maps:",
|
||||
["Marta"] = ":marta:",
|
||||
["Matlab"] = ":matlab:",
|
||||
["Mattermost"] = ":mattermost:",
|
||||
["Messages"] = ":messages:",
|
||||
["信息"] = ":messages:",
|
||||
["Nachrichten"] = ":messages:",
|
||||
["Messenger"] = ":messenger:",
|
||||
["Microsoft Edge"] = ":microsoft_edge:",
|
||||
["Microsoft Excel"] = ":microsoft_excel:",
|
||||
["Microsoft Outlook"] = ":microsoft_outlook:",
|
||||
["Microsoft PowerPoint"] = ":microsoft_power_point:",
|
||||
["Microsoft Remote Desktop"] = ":microsoft_remote_desktop:",
|
||||
["Microsoft Teams"] = ":microsoft_teams:",
|
||||
["Microsoft Teams (work or school)"] = ":microsoft_teams:",
|
||||
["Microsoft Word"] = ":microsoft_word:",
|
||||
["Min"] = ":min_browser:",
|
||||
["Miro"] = ":miro:",
|
||||
["MongoDB Compass"] = ":mongodb:",
|
||||
["mpv"] = ":mpv:",
|
||||
["Mullvad Browser"] = ":mullvad_browser:",
|
||||
["Music"] = ":music:",
|
||||
["音乐"] = ":music:",
|
||||
["Musique"] = ":music:",
|
||||
["Neovide"] = ":neovide:",
|
||||
["neovide"] = ":neovide:",
|
||||
["Neovim"] = ":neovim:",
|
||||
["neovim"] = ":neovim:",
|
||||
["nvim"] = ":neovim:",
|
||||
["网易云音乐"] = ":netease_music:",
|
||||
["Noodl"] = ":noodl:",
|
||||
["Noodl Editor"] = ":noodl:",
|
||||
["NordVPN"] = ":nord_vpn:",
|
||||
["Notability"] = ":notability:",
|
||||
["Notes"] = ":notes:",
|
||||
["备忘录"] = ":notes:",
|
||||
["Notion"] = ":notion:",
|
||||
["Nova"] = ":nova:",
|
||||
["Numbers"] = ":numbers:",
|
||||
["Numbers 表格"] = ":numbers:",
|
||||
["Obsidian"] = ":obsidian:",
|
||||
["OBS"] = ":obsstudio:",
|
||||
["OmniFocus"] = ":omni_focus:",
|
||||
["1Password"] = ":one_password:",
|
||||
["Open Video Downloader"] = ":open_video_downloader:",
|
||||
["ChatGPT"] = ":openai:",
|
||||
["OpenVPN Connect"] = ":openvpn_connect:",
|
||||
["Opera"] = ":opera:",
|
||||
["OrbStack"] = ":orbstack:",
|
||||
["OrcaSlicer"] = ":orcaslicer:",
|
||||
["Orion"] = ":orion:",
|
||||
["Orion RC"] = ":orion:",
|
||||
["Pages"] = ":pages:",
|
||||
["Pages 文稿"] = ":pages:",
|
||||
["Parallels Desktop"] = ":parallels:",
|
||||
["Parsec"] = ":parsec:",
|
||||
["Preview"] = ":pdf:",
|
||||
["预览"] = ":pdf:",
|
||||
["Skim"] = ":pdf:",
|
||||
["zathura"] = ":pdf:",
|
||||
["Aperçu"] = ":pdf:",
|
||||
["PDF Expert"] = ":pdf_expert:",
|
||||
["Pearcleaner"] = ":pearcleaner:",
|
||||
["Phoenix Slides"] = ":phoenix_slides:",
|
||||
["Adobe Photoshop"] = ":photoshop:",
|
||||
["PhpStorm"] = ":php_storm:",
|
||||
["Pi-hole Remote"] = ":pihole:",
|
||||
["Pine"] = ":pine:",
|
||||
["Plex"] = ":plex:",
|
||||
["Plexamp"] = ":plexamp:",
|
||||
["Podcasts"] = ":podcasts:",
|
||||
["播客"] = ":podcasts:",
|
||||
["PomoDone App"] = ":pomodone:",
|
||||
["Postman"] = ":postman:",
|
||||
["Proton Mail"] = ":proton_mail:",
|
||||
["Proton Mail Bridge"] = ":proton_mail:",
|
||||
["PrusaSlicer"] = ":prusaslicer:",
|
||||
["SuperSlicer"] = ":prusaslicer:",
|
||||
["PyCharm"] = ":pycharm:",
|
||||
["QQ"] = ":qq:",
|
||||
["QQ音乐"] = ":qqmusic:",
|
||||
["QQMusic"] = ":qqmusic:",
|
||||
["Quantumult X"] = ":quantumult_x:",
|
||||
["qutebrowser"] = ":qute_browser:",
|
||||
["Raindrop.io"] = ":raindrop_io:",
|
||||
["Reeder"] = ":reeder5:",
|
||||
["Reminders"] = ":reminders:",
|
||||
["提醒事项"] = ":reminders:",
|
||||
["Rappels"] = ":reminders:",
|
||||
["Replit"] = ":replit:",
|
||||
["Rider"] = ":rider:",
|
||||
["JetBrains Rider"] = ":rider:",
|
||||
["Rio"] = ":rio:",
|
||||
["Royal TSX"] = ":royaltsx:",
|
||||
["Safari"] = ":safari:",
|
||||
["Safari浏览器"] = ":safari:",
|
||||
["Safari Technology Preview"] = ":safari:",
|
||||
["Sequel Ace"] = ":sequel_ace:",
|
||||
["Sequel Pro"] = ":sequel_pro:",
|
||||
["Setapp"] = ":setapp:",
|
||||
["SF Symbols"] = ":sf_symbols:",
|
||||
["Signal"] = ":signal:",
|
||||
["sioyek"] = ":sioyek:",
|
||||
["Sketch"] = ":sketch:",
|
||||
["Skype"] = ":skype:",
|
||||
["Slack"] = ":slack:",
|
||||
["Spark Desktop"] = ":spark:",
|
||||
["Spotify"] = ":spotify:",
|
||||
["Spotlight"] = ":spotlight:",
|
||||
["Sublime Text"] = ":sublime_text:",
|
||||
["superProductivity"] = ":superproductivity:",
|
||||
["Tana"] = ":tana:",
|
||||
["TeamSpeak 3"] = ":team_speak:",
|
||||
["Telegram"] = ":telegram:",
|
||||
["Terminal"] = ":terminal:",
|
||||
["终端"] = ":terminal:",
|
||||
["Typora"] = ":text:",
|
||||
["Microsoft To Do"] = ":things:",
|
||||
["Things"] = ":things:",
|
||||
["Thunderbird"] = ":thunderbird:",
|
||||
["TickTick"] = ":tick_tick:",
|
||||
["TIDAL"] = ":tidal:",
|
||||
["Tiny RDM"] = ":tinyrdm:",
|
||||
["Todoist"] = ":todoist:",
|
||||
["Toggl Track"] = ":toggl_track:",
|
||||
["Tor Browser"] = ":tor_browser:",
|
||||
["Tower"] = ":tower:",
|
||||
["Transmit"] = ":transmit:",
|
||||
["Trello"] = ":trello:",
|
||||
["Tweetbot"] = ":twitter:",
|
||||
["Twitter"] = ":twitter:",
|
||||
["UTM"] = ":utm:",
|
||||
["MacVim"] = ":vim:",
|
||||
["Vim"] = ":vim:",
|
||||
["VimR"] = ":vim:",
|
||||
["Vivaldi"] = ":vivaldi:",
|
||||
["VLC"] = ":vlc:",
|
||||
["VMware Fusion"] = ":vmware_fusion:",
|
||||
["VSCodium"] = ":vscodium:",
|
||||
["Warp"] = ":warp:",
|
||||
["WebStorm"] = ":web_storm:",
|
||||
["微信"] = ":wechat:",
|
||||
["WeChat"] = ":wechat:",
|
||||
["企业微信"] = ":wecom:",
|
||||
["WeCom"] = ":wecom:",
|
||||
["WezTerm"] = ":wezterm:",
|
||||
["WhatsApp"] = ":whats_app:",
|
||||
["WhatsApp"] = ":whats_app:",
|
||||
["Xcode"] = ":xcode:",
|
||||
["Yandex Music"] = ":yandex_music:",
|
||||
["Yuque"] = ":yuque:",
|
||||
["语雀"] = ":yuque:",
|
||||
["Zed"] = ":zed:",
|
||||
["Zen Browser"] = ":zen_browser:",
|
||||
["Zeplin"] = ":zeplin:",
|
||||
["zoom.us"] = ":zoom:",
|
||||
["Zotero"] = ":zotero:",
|
||||
["Zulip"] = ":zulip:",
|
||||
}
|
||||
13
dot_config/sketchybar/helpers/default_font.lua
Normal file
13
dot_config/sketchybar/helpers/default_font.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
return {
|
||||
text = "SF Pro", -- Used for text
|
||||
numbers = "SF Mono", -- Used for numbers
|
||||
|
||||
-- Unified font style map
|
||||
style_map = {
|
||||
["Regular"] = "Regular",
|
||||
["Semibold"] = "Semibold",
|
||||
["Bold"] = "Bold",
|
||||
["Heavy"] = "Heavy",
|
||||
["Black"] = "Black",
|
||||
}
|
||||
}
|
||||
1
dot_config/sketchybar/helpers/dot_gitignore
Normal file
1
dot_config/sketchybar/helpers/dot_gitignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
bin
|
||||
58
dot_config/sketchybar/helpers/event_providers/cpu_load/cpu.h
Normal file
58
dot_config/sketchybar/helpers/event_providers/cpu_load/cpu.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include <mach/mach.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct cpu {
|
||||
host_t host;
|
||||
mach_msg_type_number_t count;
|
||||
host_cpu_load_info_data_t load;
|
||||
host_cpu_load_info_data_t prev_load;
|
||||
bool has_prev_load;
|
||||
|
||||
int user_load;
|
||||
int sys_load;
|
||||
int total_load;
|
||||
};
|
||||
|
||||
static inline void cpu_init(struct cpu* cpu) {
|
||||
cpu->host = mach_host_self();
|
||||
cpu->count = HOST_CPU_LOAD_INFO_COUNT;
|
||||
cpu->has_prev_load = false;
|
||||
}
|
||||
|
||||
static inline void cpu_update(struct cpu* cpu) {
|
||||
kern_return_t error = host_statistics(cpu->host,
|
||||
HOST_CPU_LOAD_INFO,
|
||||
(host_info_t)&cpu->load,
|
||||
&cpu->count );
|
||||
|
||||
if (error != KERN_SUCCESS) {
|
||||
printf("Error: Could not read cpu host statistics.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpu->has_prev_load) {
|
||||
uint32_t delta_user = cpu->load.cpu_ticks[CPU_STATE_USER]
|
||||
- cpu->prev_load.cpu_ticks[CPU_STATE_USER];
|
||||
|
||||
uint32_t delta_system = cpu->load.cpu_ticks[CPU_STATE_SYSTEM]
|
||||
- cpu->prev_load.cpu_ticks[CPU_STATE_SYSTEM];
|
||||
|
||||
uint32_t delta_idle = cpu->load.cpu_ticks[CPU_STATE_IDLE]
|
||||
- cpu->prev_load.cpu_ticks[CPU_STATE_IDLE];
|
||||
|
||||
cpu->user_load = (double)delta_user / (double)(delta_system
|
||||
+ delta_user
|
||||
+ delta_idle) * 100.0;
|
||||
|
||||
cpu->sys_load = (double)delta_system / (double)(delta_system
|
||||
+ delta_user
|
||||
+ delta_idle) * 100.0;
|
||||
|
||||
cpu->total_load = cpu->user_load + cpu->sys_load;
|
||||
}
|
||||
|
||||
cpu->prev_load = cpu->load;
|
||||
cpu->has_prev_load = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#include "cpu.h"
|
||||
#include "../sketchybar.h"
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
float update_freq;
|
||||
if (argc < 3 || (sscanf(argv[2], "%f", &update_freq) != 1)) {
|
||||
printf("Usage: %s \"<event-name>\" \"<event_freq>\"\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
alarm(0);
|
||||
struct cpu cpu;
|
||||
cpu_init(&cpu);
|
||||
|
||||
// Setup the event in sketchybar
|
||||
char event_message[512];
|
||||
snprintf(event_message, 512, "--add event '%s'", argv[1]);
|
||||
sketchybar(event_message);
|
||||
|
||||
char trigger_message[512];
|
||||
for (;;) {
|
||||
// Acquire new info
|
||||
cpu_update(&cpu);
|
||||
|
||||
// Prepare the event message
|
||||
snprintf(trigger_message,
|
||||
512,
|
||||
"--trigger '%s' user_load='%d' sys_load='%02d' total_load='%02d'",
|
||||
argv[1],
|
||||
cpu.user_load,
|
||||
cpu.sys_load,
|
||||
cpu.total_load );
|
||||
|
||||
// Trigger the event
|
||||
sketchybar(trigger_message);
|
||||
|
||||
// Wait
|
||||
usleep(update_freq * 1000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
bin/cpu_load: cpu_load.c cpu.h ../sketchybar.h | bin
|
||||
clang -std=c99 -O3 $< -o $@
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
3
dot_config/sketchybar/helpers/event_providers/makefile
Normal file
3
dot_config/sketchybar/helpers/event_providers/makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
all:
|
||||
(cd cpu_load && $(MAKE))
|
||||
(cd network_load && $(MAKE))
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
bin/network_load: network_load.c network.h ../sketchybar.h | bin
|
||||
clang -std=c99 -O3 $< -o $@
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_mib.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static char unit_str[3][6] = { { " Bps" }, { "KBps" }, { "MBps" }, };
|
||||
|
||||
enum unit {
|
||||
UNIT_BPS,
|
||||
UNIT_KBPS,
|
||||
UNIT_MBPS
|
||||
};
|
||||
struct network {
|
||||
uint32_t row;
|
||||
struct ifmibdata data;
|
||||
struct timeval tv_nm1, tv_n, tv_delta;
|
||||
|
||||
int up;
|
||||
int down;
|
||||
enum unit up_unit, down_unit;
|
||||
};
|
||||
|
||||
static inline void ifdata(uint32_t net_row, struct ifmibdata* data) {
|
||||
static size_t size = sizeof(struct ifmibdata);
|
||||
static int32_t data_option[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, 0, IFDATA_GENERAL };
|
||||
data_option[4] = net_row;
|
||||
sysctl(data_option, 6, data, &size, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void network_init(struct network* net, char* ifname) {
|
||||
memset(net, 0, sizeof(struct network));
|
||||
|
||||
static int count_option[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_SYSTEM, IFMIB_IFCOUNT };
|
||||
uint32_t interface_count = 0;
|
||||
size_t size = sizeof(uint32_t);
|
||||
sysctl(count_option, 5, &interface_count, &size, NULL, 0);
|
||||
|
||||
for (int i = 0; i < interface_count; i++) {
|
||||
ifdata(i, &net->data);
|
||||
if (strcmp(net->data.ifmd_name, ifname) == 0) {
|
||||
net->row = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void network_update(struct network* net) {
|
||||
gettimeofday(&net->tv_n, NULL);
|
||||
timersub(&net->tv_n, &net->tv_nm1, &net->tv_delta);
|
||||
net->tv_nm1 = net->tv_n;
|
||||
|
||||
uint64_t ibytes_nm1 = net->data.ifmd_data.ifi_ibytes;
|
||||
uint64_t obytes_nm1 = net->data.ifmd_data.ifi_obytes;
|
||||
ifdata(net->row, &net->data);
|
||||
|
||||
double time_scale = (net->tv_delta.tv_sec + 1e-6*net->tv_delta.tv_usec);
|
||||
if (time_scale < 1e-6 || time_scale > 1e2) return;
|
||||
double delta_ibytes = (double)(net->data.ifmd_data.ifi_ibytes - ibytes_nm1)
|
||||
/ time_scale;
|
||||
double delta_obytes = (double)(net->data.ifmd_data.ifi_obytes - obytes_nm1)
|
||||
/ time_scale;
|
||||
|
||||
double exponent_ibytes = log10(delta_ibytes);
|
||||
double exponent_obytes = log10(delta_obytes);
|
||||
|
||||
if (exponent_ibytes < 3) {
|
||||
net->down_unit = UNIT_BPS;
|
||||
net->down = delta_ibytes;
|
||||
} else if (exponent_ibytes < 6) {
|
||||
net->down_unit = UNIT_KBPS;
|
||||
net->down = delta_ibytes / 1000.0;
|
||||
} else if (exponent_ibytes < 9) {
|
||||
net->down_unit = UNIT_MBPS;
|
||||
net->down = delta_ibytes / 1000000.0;
|
||||
}
|
||||
|
||||
if (exponent_obytes < 3) {
|
||||
net->up_unit = UNIT_BPS;
|
||||
net->up = delta_obytes;
|
||||
} else if (exponent_obytes < 6) {
|
||||
net->up_unit = UNIT_KBPS;
|
||||
net->up = delta_obytes / 1000.0;
|
||||
} else if (exponent_obytes < 9) {
|
||||
net->up_unit = UNIT_MBPS;
|
||||
net->up = delta_obytes / 1000000.0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#include <unistd.h>
|
||||
#include "network.h"
|
||||
#include "../sketchybar.h"
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
float update_freq;
|
||||
if (argc < 4 || (sscanf(argv[3], "%f", &update_freq) != 1)) {
|
||||
printf("Usage: %s \"<interface>\" \"<event-name>\" \"<event_freq>\"\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
alarm(0);
|
||||
// Setup the event in sketchybar
|
||||
char event_message[512];
|
||||
snprintf(event_message, 512, "--add event '%s'", argv[2]);
|
||||
sketchybar(event_message);
|
||||
|
||||
struct network network;
|
||||
network_init(&network, argv[1]);
|
||||
char trigger_message[512];
|
||||
for (;;) {
|
||||
// Acquire new info
|
||||
network_update(&network);
|
||||
|
||||
// Prepare the event message
|
||||
snprintf(trigger_message,
|
||||
512,
|
||||
"--trigger '%s' upload='%03d%s' download='%03d%s'",
|
||||
argv[2],
|
||||
network.up,
|
||||
unit_str[network.up_unit],
|
||||
network.down,
|
||||
unit_str[network.down_unit]);
|
||||
|
||||
// Trigger the event
|
||||
sketchybar(trigger_message);
|
||||
|
||||
// Wait
|
||||
usleep(update_freq * 1000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
122
dot_config/sketchybar/helpers/event_providers/sketchybar.h
Normal file
122
dot_config/sketchybar/helpers/event_providers/sketchybar.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#pragma once
|
||||
|
||||
#include <mach/arm/kern_return.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/message.h>
|
||||
#include <bootstrap.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef char* env;
|
||||
|
||||
#define MACH_HANDLER(name) void name(env env)
|
||||
typedef MACH_HANDLER(mach_handler);
|
||||
|
||||
struct mach_message {
|
||||
mach_msg_header_t header;
|
||||
mach_msg_size_t msgh_descriptor_count;
|
||||
mach_msg_ool_descriptor_t descriptor;
|
||||
};
|
||||
|
||||
struct mach_buffer {
|
||||
struct mach_message message;
|
||||
mach_msg_trailer_t trailer;
|
||||
};
|
||||
|
||||
static mach_port_t g_mach_port = 0;
|
||||
|
||||
static inline mach_port_t mach_get_bs_port() {
|
||||
mach_port_name_t task = mach_task_self();
|
||||
|
||||
mach_port_t bs_port;
|
||||
if (task_get_special_port(task,
|
||||
TASK_BOOTSTRAP_PORT,
|
||||
&bs_port ) != KERN_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* name = getenv("BAR_NAME");
|
||||
if (!name) name = "sketchybar";
|
||||
uint32_t lookup_len = 16 + strlen(name);
|
||||
|
||||
char buffer[lookup_len];
|
||||
snprintf(buffer, lookup_len, "git.felix.%s", name);
|
||||
|
||||
mach_port_t port;
|
||||
if (bootstrap_look_up(bs_port, buffer, &port) != KERN_SUCCESS) return 0;
|
||||
return port;
|
||||
}
|
||||
|
||||
static inline bool mach_send_message(mach_port_t port, char* message, uint32_t len) {
|
||||
if (!message || !port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct mach_message msg = { 0 };
|
||||
msg.header.msgh_remote_port = port;
|
||||
msg.header.msgh_local_port = 0;
|
||||
msg.header.msgh_id = 0;
|
||||
msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
|
||||
MACH_MSG_TYPE_MAKE_SEND,
|
||||
0,
|
||||
MACH_MSGH_BITS_COMPLEX );
|
||||
|
||||
msg.header.msgh_size = sizeof(struct mach_message);
|
||||
msg.msgh_descriptor_count = 1;
|
||||
msg.descriptor.address = message;
|
||||
msg.descriptor.size = len * sizeof(char);
|
||||
msg.descriptor.copy = MACH_MSG_VIRTUAL_COPY;
|
||||
msg.descriptor.deallocate = false;
|
||||
msg.descriptor.type = MACH_MSG_OOL_DESCRIPTOR;
|
||||
|
||||
kern_return_t err = mach_msg(&msg.header,
|
||||
MACH_SEND_MSG,
|
||||
sizeof(struct mach_message),
|
||||
0,
|
||||
MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE,
|
||||
MACH_PORT_NULL );
|
||||
|
||||
return err == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
static inline uint32_t format_message(char* message, char* formatted_message) {
|
||||
// This is not actually robust, switch to stack based messaging.
|
||||
char outer_quote = 0;
|
||||
uint32_t caret = 0;
|
||||
uint32_t message_length = strlen(message) + 1;
|
||||
for (int i = 0; i < message_length; ++i) {
|
||||
if (message[i] == '"' || message[i] == '\'') {
|
||||
if (outer_quote && outer_quote == message[i]) outer_quote = 0;
|
||||
else if (!outer_quote) outer_quote = message[i];
|
||||
continue;
|
||||
}
|
||||
formatted_message[caret] = message[i];
|
||||
if (message[i] == ' ' && !outer_quote) formatted_message[caret] = '\0';
|
||||
caret++;
|
||||
}
|
||||
|
||||
if (caret > 0 && formatted_message[caret] == '\0'
|
||||
&& formatted_message[caret - 1] == '\0') {
|
||||
caret--;
|
||||
}
|
||||
formatted_message[caret] = '\0';
|
||||
return caret + 1;
|
||||
}
|
||||
|
||||
static inline void sketchybar(char* message) {
|
||||
char formatted_message[strlen(message) + 2];
|
||||
uint32_t length = format_message(message, formatted_message);
|
||||
if (!length) return;
|
||||
|
||||
if (!g_mach_port) g_mach_port = mach_get_bs_port();
|
||||
if (!mach_send_message(g_mach_port, formatted_message, length)) {
|
||||
g_mach_port = mach_get_bs_port();
|
||||
if (!mach_send_message(g_mach_port, formatted_message, length)) {
|
||||
// No sketchybar instance running, exit.
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
4
dot_config/sketchybar/helpers/init.lua
Normal file
4
dot_config/sketchybar/helpers/init.lua
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-- Add the sketchybar module to the package cpath
|
||||
package.cpath = package.cpath .. ";/Users/" .. os.getenv("USER") .. "/.local/share/sketchybar_lua/?.so"
|
||||
|
||||
os.execute("(cd helpers && make)")
|
||||
3
dot_config/sketchybar/helpers/makefile
Normal file
3
dot_config/sketchybar/helpers/makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
all:
|
||||
(cd event_providers && $(MAKE)) >/dev/null
|
||||
(cd menus && $(MAKE)) >/dev/null
|
||||
5
dot_config/sketchybar/helpers/menus/makefile
Normal file
5
dot_config/sketchybar/helpers/menus/makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
bin/menus: menus.c | bin
|
||||
clang -std=c99 -O3 -F/System/Library/PrivateFrameworks/ -framework Carbon -framework SkyLight $< -o $@
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
248
dot_config/sketchybar/helpers/menus/menus.c
Normal file
248
dot_config/sketchybar/helpers/menus/menus.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
#include <Carbon/Carbon.h>
|
||||
|
||||
void ax_init() {
|
||||
const void *keys[] = { kAXTrustedCheckOptionPrompt };
|
||||
const void *values[] = { kCFBooleanTrue };
|
||||
|
||||
CFDictionaryRef options;
|
||||
options = CFDictionaryCreate(kCFAllocatorDefault,
|
||||
keys,
|
||||
values,
|
||||
sizeof(keys) / sizeof(*keys),
|
||||
&kCFCopyStringDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks );
|
||||
|
||||
bool trusted = AXIsProcessTrustedWithOptions(options);
|
||||
CFRelease(options);
|
||||
if (!trusted) exit(1);
|
||||
}
|
||||
|
||||
void ax_perform_click(AXUIElementRef element) {
|
||||
if (!element) return;
|
||||
AXUIElementPerformAction(element, kAXCancelAction);
|
||||
usleep(150000);
|
||||
AXUIElementPerformAction(element, kAXPressAction);
|
||||
}
|
||||
|
||||
CFStringRef ax_get_title(AXUIElementRef element) {
|
||||
CFTypeRef title = NULL;
|
||||
AXError error = AXUIElementCopyAttributeValue(element,
|
||||
kAXTitleAttribute,
|
||||
&title );
|
||||
|
||||
if (error != kAXErrorSuccess) return NULL;
|
||||
return title;
|
||||
}
|
||||
|
||||
void ax_select_menu_option(AXUIElementRef app, int id) {
|
||||
AXUIElementRef menubars_ref = NULL;
|
||||
CFArrayRef children_ref = NULL;
|
||||
|
||||
AXError error = AXUIElementCopyAttributeValue(app,
|
||||
kAXMenuBarAttribute,
|
||||
(CFTypeRef*)&menubars_ref);
|
||||
if (error == kAXErrorSuccess) {
|
||||
error = AXUIElementCopyAttributeValue(menubars_ref,
|
||||
kAXVisibleChildrenAttribute,
|
||||
(CFTypeRef*)&children_ref );
|
||||
|
||||
if (error == kAXErrorSuccess) {
|
||||
uint32_t count = CFArrayGetCount(children_ref);
|
||||
if (id < count) {
|
||||
AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, id);
|
||||
ax_perform_click(item);
|
||||
}
|
||||
if (children_ref) CFRelease(children_ref);
|
||||
}
|
||||
if (menubars_ref) CFRelease(menubars_ref);
|
||||
}
|
||||
}
|
||||
|
||||
void ax_print_menu_options(AXUIElementRef app) {
|
||||
AXUIElementRef menubars_ref = NULL;
|
||||
CFTypeRef menubar = NULL;
|
||||
CFArrayRef children_ref = NULL;
|
||||
|
||||
AXError error = AXUIElementCopyAttributeValue(app,
|
||||
kAXMenuBarAttribute,
|
||||
(CFTypeRef*)&menubars_ref);
|
||||
if (error == kAXErrorSuccess) {
|
||||
error = AXUIElementCopyAttributeValue(menubars_ref,
|
||||
kAXVisibleChildrenAttribute,
|
||||
(CFTypeRef*)&children_ref );
|
||||
|
||||
if (error == kAXErrorSuccess) {
|
||||
uint32_t count = CFArrayGetCount(children_ref);
|
||||
|
||||
for (int i = 1; i < count; i++) {
|
||||
AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, i);
|
||||
CFTypeRef title = ax_get_title(item);
|
||||
|
||||
if (title) {
|
||||
uint32_t buffer_len = 2*CFStringGetLength(title);
|
||||
char buffer[2*CFStringGetLength(title)];
|
||||
CFStringGetCString(title, buffer, buffer_len, kCFStringEncodingUTF8);
|
||||
printf("%s\n", buffer);
|
||||
CFRelease(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (menubars_ref) CFRelease(menubars_ref);
|
||||
if (children_ref) CFRelease(children_ref);
|
||||
}
|
||||
}
|
||||
|
||||
AXUIElementRef ax_get_extra_menu_item(char* alias) {
|
||||
pid_t pid = 0;
|
||||
CGRect bounds = CGRectNull;
|
||||
CFArrayRef window_list = CGWindowListCopyWindowInfo(kCGWindowListOptionAll,
|
||||
kCGNullWindowID );
|
||||
char owner_buffer[256];
|
||||
char name_buffer[256];
|
||||
char buffer[512];
|
||||
int window_count = CFArrayGetCount(window_list);
|
||||
for (int i = 0; i < window_count; ++i) {
|
||||
CFDictionaryRef dictionary = CFArrayGetValueAtIndex(window_list, i);
|
||||
if (!dictionary) continue;
|
||||
|
||||
CFStringRef owner_ref = CFDictionaryGetValue(dictionary,
|
||||
kCGWindowOwnerName);
|
||||
|
||||
CFNumberRef owner_pid_ref = CFDictionaryGetValue(dictionary,
|
||||
kCGWindowOwnerPID);
|
||||
|
||||
CFStringRef name_ref = CFDictionaryGetValue(dictionary, kCGWindowName);
|
||||
CFNumberRef layer_ref = CFDictionaryGetValue(dictionary, kCGWindowLayer);
|
||||
CFDictionaryRef bounds_ref = CFDictionaryGetValue(dictionary,
|
||||
kCGWindowBounds);
|
||||
|
||||
if (!name_ref || !owner_ref || !owner_pid_ref || !layer_ref || !bounds_ref)
|
||||
continue;
|
||||
|
||||
long long int layer = 0;
|
||||
CFNumberGetValue(layer_ref, CFNumberGetType(layer_ref), &layer);
|
||||
uint64_t owner_pid = 0;
|
||||
CFNumberGetValue(owner_pid_ref,
|
||||
CFNumberGetType(owner_pid_ref),
|
||||
&owner_pid );
|
||||
|
||||
if (layer != 0x19) continue;
|
||||
bounds = CGRectNull;
|
||||
if (!CGRectMakeWithDictionaryRepresentation(bounds_ref, &bounds)) continue;
|
||||
CFStringGetCString(owner_ref,
|
||||
owner_buffer,
|
||||
sizeof(owner_buffer),
|
||||
kCFStringEncodingUTF8);
|
||||
|
||||
CFStringGetCString(name_ref,
|
||||
name_buffer,
|
||||
sizeof(name_buffer),
|
||||
kCFStringEncodingUTF8);
|
||||
snprintf(buffer, sizeof(buffer), "%s,%s", owner_buffer, name_buffer);
|
||||
|
||||
if (strcmp(buffer, alias) == 0) {
|
||||
pid = owner_pid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CFRelease(window_list);
|
||||
if (!pid) return NULL;
|
||||
|
||||
AXUIElementRef app = AXUIElementCreateApplication(pid);
|
||||
if (!app) return NULL;
|
||||
AXUIElementRef result = NULL;
|
||||
CFTypeRef extras = NULL;
|
||||
CFArrayRef children_ref = NULL;
|
||||
AXError error = AXUIElementCopyAttributeValue(app,
|
||||
kAXExtrasMenuBarAttribute,
|
||||
&extras );
|
||||
if (error == kAXErrorSuccess) {
|
||||
error = AXUIElementCopyAttributeValue(extras,
|
||||
kAXVisibleChildrenAttribute,
|
||||
(CFTypeRef*)&children_ref );
|
||||
|
||||
if (error == kAXErrorSuccess) {
|
||||
uint32_t count = CFArrayGetCount(children_ref);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
AXUIElementRef item = CFArrayGetValueAtIndex(children_ref, i);
|
||||
CFTypeRef position_ref = NULL;
|
||||
CFTypeRef size_ref = NULL;
|
||||
AXUIElementCopyAttributeValue(item, kAXPositionAttribute,
|
||||
&position_ref );
|
||||
AXUIElementCopyAttributeValue(item, kAXSizeAttribute,
|
||||
&size_ref );
|
||||
if (!position_ref || !size_ref) continue;
|
||||
|
||||
CGPoint position = CGPointZero;
|
||||
AXValueGetValue(position_ref, kAXValueCGPointType, &position);
|
||||
CGSize size = CGSizeZero;
|
||||
AXValueGetValue(size_ref, kAXValueCGSizeType, &size);
|
||||
CFRelease(position_ref);
|
||||
CFRelease(size_ref);
|
||||
// The offset is exactly 8 on macOS Sonoma...
|
||||
// printf("%f %f\n", position.x, bounds.origin.x);
|
||||
if (error == kAXErrorSuccess
|
||||
&& fabs(position.x - bounds.origin.x) <= 10) {
|
||||
result = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(app);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern int SLSMainConnectionID();
|
||||
extern void SLSSetMenuBarVisibilityOverrideOnDisplay(int cid, int did, bool enabled);
|
||||
extern void SLSSetMenuBarVisibilityOverrideOnDisplay(int cid, int did, bool enabled);
|
||||
extern void SLSSetMenuBarInsetAndAlpha(int cid, double u1, double u2, float alpha);
|
||||
void ax_select_menu_extra(char* alias) {
|
||||
AXUIElementRef item = ax_get_extra_menu_item(alias);
|
||||
if (!item) return;
|
||||
SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 0.0);
|
||||
SLSSetMenuBarVisibilityOverrideOnDisplay(SLSMainConnectionID(), 0, true);
|
||||
SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 0.0);
|
||||
ax_perform_click(item);
|
||||
SLSSetMenuBarVisibilityOverrideOnDisplay(SLSMainConnectionID(), 0, false);
|
||||
SLSSetMenuBarInsetAndAlpha(SLSMainConnectionID(), 0, 1, 1.0);
|
||||
CFRelease(item);
|
||||
}
|
||||
|
||||
extern void _SLPSGetFrontProcess(ProcessSerialNumber* psn);
|
||||
extern void SLSGetConnectionIDForPSN(int cid, ProcessSerialNumber* psn, int* cid_out);
|
||||
extern void SLSConnectionGetPID(int cid, pid_t* pid_out);
|
||||
AXUIElementRef ax_get_front_app() {
|
||||
ProcessSerialNumber psn;
|
||||
_SLPSGetFrontProcess(&psn);
|
||||
int target_cid;
|
||||
SLSGetConnectionIDForPSN(SLSMainConnectionID(), &psn, &target_cid);
|
||||
|
||||
pid_t pid;
|
||||
SLSConnectionGetPID(target_cid, &pid);
|
||||
return AXUIElementCreateApplication(pid);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
printf("Usage: %s [-l | -s id/alias ]\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
ax_init();
|
||||
if (strcmp(argv[1], "-l") == 0) {
|
||||
AXUIElementRef app = ax_get_front_app();
|
||||
if (!app) return 1;
|
||||
ax_print_menu_options(app);
|
||||
CFRelease(app);
|
||||
} else if (argc == 3 && strcmp(argv[1], "-s") == 0) {
|
||||
int id = 0;
|
||||
if (sscanf(argv[2], "%d", &id) == 1) {
|
||||
AXUIElementRef app = ax_get_front_app();
|
||||
if (!app) return 1;
|
||||
ax_select_menu_option(app, id);
|
||||
CFRelease(app);
|
||||
} else ax_select_menu_extra(argv[2]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue