Skip to content

Instantly share code, notes, and snippets.

@sephid86
Last active January 2, 2026 09:13
Show Gist options
  • Select an option

  • Save sephid86/0969503dee1104030c0d63b0cd59c3f7 to your computer and use it in GitHub Desktop.

Select an option

Save sephid86/0969503dee1104030c0d63b0cd59c3f7 to your computer and use it in GitHub Desktop.
[fcitx5-status-lang] Ultra-lightweight D-Bus event-driven IME status listener #fcitx5 #waybar #lua #한글 #korean

Fulleaf Linux (based on Arch Linux) developer.
'풀잎 리눅스' 개발자입니다.

I also develop small utilities and occasionally contribute to other projects.
또한, 소소한 유틸리티들을 개발하며 드물게 가끔 다른 오픈소스 프로젝트에도 아주 작지만 기여를 하고 있습니다.

I'm working towards becoming Cup Noodles Profitable.
이 개발자는 오늘 굶었을지도 모릅니다.

 Buy me a Cup noodles  컵라면 하나만 사주세요

Fcitx5 의 트레이 아이콘이 너무 구석에 있다 보니 시야에 잘 들어오지 않아서
지금 언어 입력상태가 한글 입력 상태인지 영문 입력 상태인지
시야에 들어오기 좀 더 쉽고 편하게 해보고자 만들었습니다.
저는 이걸 윈도우 타이틀 옆에 표시되도록 설정해서 사용합니다.

CPU 점유율이나 부하가 없도록 그리고 리소스를 최소한만 사용하도록 하기 위해
많은 고민을 하고 AI 와 많은 토론과 많은 시행착오를 겪어가며 만들었습니다. AI 가 만들었습니다.

High-efficiency event-driven architecture using Lua LGI.
Zero idle CPU usage (0.0%). Single PID design with NixOS self-healing logic.
Perfect for Waybar or any custom bar modules. (Tested by sephid86)

설치 필요 - need packages

  • Arch Linux: sudo pacman -S lua-lgi fcitx5
  • Ubuntu/Debian: sudo apt install lua-lgi fcitx5
  • Fedora: sudo dnf install lua-lgi fcitx5
  • NixOS : fcitx5 lua

waybar 에서 사용법 - How to use with Waybar

Waybar 설정 파일(config)에 아래 내용을 추가하세요:
Add the following to your Waybar config:

"modules-center": ["YOUR_WM/window", "custom/fcitx5"],
"custom/fcitx5": {
    "exec": "/YOUR_PATH/fcitx5-status-lang.lua",
    //"return-type": "json",
    "format": "{}",
    "tooltip": false
}

!! 이 스크립트는 Fcitx5 의 트레이 아이콘이 표시 혹은 실행중일때만 동작가능합니다. Tested on waybar.
!! This script requires the Fcitx5 tray icon to be enabled, as it relies on D-Bus signals from the StatusNotifierItem.

!! print 부분은 필요에 따라 json 이나 다른 형식으로 변경하여 사용하시면 됩니다.
!! The output format in the print section can be customized to JSON or other structures to suit your specific bar configuration (e.g., Waybar's JSON mode).

🔗 왜 JSON 모드를 사용해야 하나요? / Why use JSON mode?

  • 클래스 주입: 스크립트에서 직접 class 필드(예: "class": "kor")를 Waybar로 전달할 수 있습니다.
  • Class Injection: You can pass a class field (e.g., "class": "kor") from the script directly to Waybar.
  • 동적 스타일링: 입력 언어가 바뀔 때마다 오렌지색 캡슐 스타일 같은 다양한 CSS 효과를 자동으로 적용할 수 있습니다.
  • Dynamic Styling: This allows you to apply different CSS styles (like your Orange Capsule) automatically when the language changes.
  • 풍부한 데이터 처리: 스크립트 출력 결과에 따라 툴팁(Tooltip)이나 커스텀 아이콘 변경 등 더 고급 기능을 활용할 수 있습니다.
  • Rich Data: It enables more advanced features like tooltips or custom icons based on the script's output.

JSON 모드 사용시 아래와 같이 waybar config 를 수정해야 합니다.

When using JSON mode, the waybar config should be modified as follows:

"modules-center": ["YOUR_WM/window", "custom/fcitx5"],
"custom/fcitx5": {
    "exec": "/YOUR_PATH/fcitx5-status-lang-json.lua",
    "return-type": "json",
    "format": "{}",
    "tooltip": false
}

새해 복 많이 받으세요. Happy New Year! - 2026-01-02 -
#!/usr/bin/env lua
--[[
fcitx5-status-lang.lua
Copyright (c) 2026 Google Gemini (Author)
Idea provided, tested, and debugged by sephid86 (Co-Author)
GitHub: github.com
Gist: gist.github.com
Email: sephid86@gmail.com
License: MIT
Description:
Extremely efficient Fcitx5 language status monitor for Waybar.
This version achieves 'Zero PID Increment' by utilizing direct
D-Bus communication via the LGI library, eliminating the need
for any external process calls.
]]
-- 1. NixOS 자가 치유 및 LGI 로드
-- Self-healing for NixOS and LGI library loading
local status, lgi = pcall(require, 'lgi')
if not status then
local f = io.open("/etc/os-release", "r")
if f then
local content = f:read("*all")
f:close()
-- NixOS 환경 감지 시 필요한 패키지를 포함하여 자동 재실행
-- Re-execute with nix-shell when NixOS environment is detected
if content:match("ID=nixos") and not os.getenv("IN_NIX_SHELL") then
local cmd = string.format("nix-shell -p 'pkgs.lua.withPackages (ps: [ps.lgi])' -p gobject-introspection -p glib --run 'lua %s'", arg[0])
os.execute(cmd)
os.exit()
end
end
error("LGI module not found. Please install 'lua-lgi'.")
end
local Gio = lgi.Gio
local GLib = lgi.GLib
-- 출력 버퍼 즉시 비우기 (실시간 반영 보장)
-- Flush output buffer immediately for real-time updates
io.stdout:setvbuf('line')
-- 2. D-Bus 프록시 설정 (Direct D-Bus Proxy Setup)
-- D-Bus와 직접 통신하여 외부 프로세스 생성 없이 정보를 가져옵니다.
-- Communicates directly with D-Bus without creating external processes.
local bus = Gio.bus_get_sync(Gio.BusType.SESSION)
local proxy = Gio.DBusProxy.new_sync(
bus,
Gio.DBusProxyFlags.NONE,
nil,
'org.fcitx.Fcitx5',
'/controller',
'org.fcitx.Fcitx.Controller1',
nil
)
-- 3. 상태 업데이트 및 출력 함수 (PID 증가 없음!)
-- JSON output function using direct D-Bus query.
local function update_status()
-- fcitx5-remote -n 명령어를 직접적인 D-Bus 쿼리로 대체
-- Replaces external command calls with a direct D-Bus method call.
local res = proxy:call_sync('CurrentInputMethod', nil, 0, -1, nil)
if res then
local ime = res:get_child_value(0):get_string()
-- 언어 판별 및 범용 출력 로직
-- Language detection and universal output logic
if ime == "" or ime:match("^keyboard%-us$") or ime:match("^us$") then
-- 영어(기본) 레이아웃
-- English (Default) layout
print('{"text": "ENG", "class": "eng"}')
elseif ime:match("hangul") then
-- 한국어 유저를 위한 명시적 표기
-- Explicit notation for Korean users
print('{"text": "한글", "class": "kor"}')
else
-- 일본어(mozc), 중국어(pinyin) 등 기타 모든 언어는 이름을 대문자로 출력
-- For all other languages (e.g., mozc, pinyin), print the name in uppercase
print('{"text": "' .. ime:upper() .. '", "class": "other"}')
end
end
end
-- 4. 초기 상태 출력 (Print initial status)
update_status()
-- 5. D-Bus 신호 구독 (이벤트 발생 시 즉시 반응 / Event Subscription)
-- 신뢰성 있는 신호들을 구독하여 입력기 상태 변화에 즉각 대응합니다.
-- Subscribes to reliable signals for immediate reaction to status changes.
if bus then
-- 입력 상태가 바뀔 때 발생하는 Fcitx5 고유 신호 구독
-- Subscribe to Fcitx5 native status change signal.
bus:signal_subscribe(
'org.fcitx.Fcitx5',
'org.fcitx.Fcitx.InputMethod1',
'StatusChanged',
'/org/fcitx/Fcitx5/InputMethod1',
nil,
Gio.DBusSignalFlags.NONE,
update_status
)
-- 범용성을 위해 기존의 신호들도 유지 (StatusNotifier 등)
-- Maintain auxiliary signals for universal compatibility.
bus:signal_subscribe(nil, "org.kde.StatusNotifierItem", "NewIcon", nil, nil, 0, update_status)
bus:signal_subscribe(nil, "com.canonical.dbusmenu", "LayoutUpdated", nil, nil, 0, update_status)
end
-- 6. 메인 루프 실행 (Start main event loop)
-- 이벤트 기반 방식으로 CPU 점유율이 0%에 수렴합니다.
-- Minimal CPU usage via event-driven architecture.
GLib.MainLoop():run()
#!/usr/bin/env lua
--[[
fcitx5-status-lang.lua
Copyright (c) 2026 Google Gemini (Author)
Idea provided, tested, and debugged by sephid86 (Co-Author)
GitHub: github.com
Gist: gist.github.com
Email: sephid86@gmail.com
License: MIT
Description:
Extremely efficient Fcitx5 language status monitor for Waybar.
This version achieves 'Zero PID Increment' by utilizing direct
D-Bus communication via the LGI library, eliminating the need
for any external process calls.
]]
-- 1. NixOS 자가 치유 및 LGI 로드
-- Self-healing for NixOS and LGI library loading
local status, lgi = pcall(require, 'lgi')
if not status then
local f = io.open("/etc/os-release", "r")
if f then
local content = f:read("*all")
f:close()
-- NixOS 환경 감지 시 필요한 패키지를 포함하여 자동 재실행
-- Re-execute with nix-shell when NixOS environment is detected
if content:match("ID=nixos") and not os.getenv("IN_NIX_SHELL") then
local cmd = string.format("nix-shell -p 'pkgs.lua.withPackages (ps: [ps.lgi])' -p gobject-introspection -p glib --run 'lua %s'", arg[0])
os.execute(cmd)
os.exit()
end
end
error("LGI module not found. Please install 'lua-lgi'.")
end
local Gio = lgi.Gio
local GLib = lgi.GLib
-- 출력 버퍼 즉시 비우기 (실시간 반영 보장)
-- Flush output buffer immediately for real-time updates
io.stdout:setvbuf('line')
-- 2. D-Bus 프록시 설정 (Direct D-Bus Proxy Setup)
-- D-Bus와 직접 통신하여 외부 프로세스 생성 없이 정보를 가져옵니다.
-- Communicates directly with D-Bus without creating external processes.
local bus = Gio.bus_get_sync(Gio.BusType.SESSION)
local proxy = Gio.DBusProxy.new_sync(
bus,
Gio.DBusProxyFlags.NONE,
nil,
'org.fcitx.Fcitx5',
'/controller',
'org.fcitx.Fcitx.Controller1',
nil
)
-- 3. 상태 업데이트 및 출력 함수 (PID 증가 없음!)
-- JSON output function using direct D-Bus query.
local function update_status()
-- fcitx5-remote -n 명령어를 직접적인 D-Bus 쿼리로 대체
-- Replaces external command calls with a direct D-Bus method call.
local res = proxy:call_sync('CurrentInputMethod', nil, 0, -1, nil)
if res then
local ime = res:get_child_value(0):get_string()
-- 언어 판별 및 범용 출력 로직
-- Language detection and universal output logic
if ime == "" or ime:match("^keyboard%-us$") or ime:match("^us$") then
-- 영어(기본) 레이아웃
-- English (Default) layout
print("ENG")
elseif ime:match("hangul") then
-- 한국어 유저를 위한 명시적 표기
-- Explicit notation for Korean users
print("한글")
else
-- 일본어(mozc), 중국어(pinyin) 등 기타 모든 언어는 이름을 대문자로 출력
-- For all other languages (e.g., mozc, pinyin), print the name in uppercase
print(ime:upper())
end
end
end
-- 4. 초기 상태 출력 (Print initial status)
update_status()
-- 5. D-Bus 신호 구독 (이벤트 발생 시 즉시 반응 / Event Subscription)
-- 신뢰성 있는 신호들을 구독하여 입력기 상태 변화에 즉각 대응합니다.
-- Subscribes to reliable signals for immediate reaction to status changes.
if bus then
-- 입력 상태가 바뀔 때 발생하는 Fcitx5 고유 신호 구독
-- Subscribe to Fcitx5 native status change signal.
bus:signal_subscribe(
'org.fcitx.Fcitx5',
'org.fcitx.Fcitx.InputMethod1',
'StatusChanged',
'/org/fcitx/Fcitx5/InputMethod1',
nil,
Gio.DBusSignalFlags.NONE,
update_status
)
-- 범용성을 위해 기존의 신호들도 유지 (StatusNotifier 등)
-- Maintain auxiliary signals for universal compatibility.
bus:signal_subscribe(nil, "org.kde.StatusNotifierItem", "NewIcon", nil, nil, 0, update_status)
bus:signal_subscribe(nil, "com.canonical.dbusmenu", "LayoutUpdated", nil, nil, 0, update_status)
end
-- 6. 메인 루프 실행 (Start main event loop)
-- 이벤트 기반 방식으로 CPU 점유율이 0%에 수렴합니다.
-- Minimal CPU usage via event-driven architecture.
GLib.MainLoop():run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment