Skip to content

Commit 536de36

Browse files
authored
status bar: hide and menu (#266)
1 parent 96c4b19 commit 536de36

File tree

7 files changed

+112
-44
lines changed

7 files changed

+112
-44
lines changed

assets/po/zh_CN.po

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,23 @@ msgstr ""
1515
"Content-Type: text/plain; charset=UTF-8\n"
1616
"Content-Transfer-Encoding: 8bit\n"
1717

18-
#: macosfrontend/macosfrontend.h:47
18+
#: macosfrontend/macosfrontend.h:27
19+
msgid "Hidden"
20+
msgstr "隐藏"
21+
22+
#: macosfrontend/macosfrontend.h:28
23+
msgid "Toggle input method"
24+
msgstr "切换输入法"
25+
26+
#: macosfrontend/macosfrontend.h:28
27+
msgid "Menu"
28+
msgstr "菜单"
29+
30+
#: macosfrontend/macosfrontend.h:44
31+
msgid "Status bar"
32+
msgstr "状态栏"
33+
34+
#: macosfrontend/macosfrontend.h:48
1935
msgid "App default IM"
2036
msgstr "应用默认输入法"
2137

256 Bytes
Binary file not shown.

macosfrontend/macosfrontend.cpp

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,41 @@ namespace fcitx {
2626
MacosFrontend::MacosFrontend(Instance *instance)
2727
: instance_(instance),
2828
focusGroup_("macos", instance->inputContextManager()) {
29-
eventHandler_ = instance_->watchEvent(
29+
// For update when switching internal input method of rime.
30+
eventHandlers_.emplace_back(instance_->watchEvent(
3031
EventType::InputContextUpdateUI, EventWatcherPhase::Default,
31-
[=, this](Event &event) {
32-
if (auto ic = instance->mostRecentInputContext()) {
33-
auto engine = instance->inputMethodEngine(ic);
34-
auto entry = instance->inputMethodEntry(ic);
35-
std::string display;
36-
if (engine) {
37-
auto subModeLabel = engine->subModeLabel(*entry, *ic);
38-
auto name =
39-
entry->label().empty() ? entry->name() : entry->label();
40-
if (subModeLabel.empty()) {
41-
display = std::move(name);
42-
} else {
43-
display = std::move(subModeLabel);
44-
}
45-
} else {
46-
display = "🐧";
47-
}
48-
if (statusItemText != display) {
49-
statusItemText = std::move(display);
50-
SwiftFrontend::setStatusItemText(statusItemText);
51-
}
52-
}
53-
});
32+
[this](Event &event) { updateStatusItemText(); }));
33+
// For switching from VSCode to Terminal, otherwise the first key press
34+
// triggers text update.
35+
eventHandlers_.emplace_back(instance_->watchEvent(
36+
EventType::InputContextInputMethodActivated, EventWatcherPhase::Default,
37+
[this](Event &event) { updateStatusItemText(); }));
5438
reloadConfig();
5539
}
5640

41+
void MacosFrontend::updateStatusItemText() {
42+
if (auto ic = instance_->mostRecentInputContext()) {
43+
auto engine = instance_->inputMethodEngine(ic);
44+
auto entry = instance_->inputMethodEntry(ic);
45+
std::string display;
46+
if (engine) {
47+
auto subModeLabel = engine->subModeLabel(*entry, *ic);
48+
auto name = entry->label().empty() ? entry->name() : entry->label();
49+
if (subModeLabel.empty()) {
50+
display = std::move(name);
51+
} else {
52+
display = std::move(subModeLabel);
53+
}
54+
} else {
55+
display = "🐧";
56+
}
57+
if (statusItemText != display) {
58+
statusItemText = std::move(display);
59+
SwiftFrontend::setStatusItemText(statusItemText);
60+
}
61+
}
62+
}
63+
5764
// Runs on the fcitx thread.
5865
void MacosFrontend::pollPasteboard() {
5966
monitorPasteboardEvent_ = instance_->eventLoop().addTimeEvent(
@@ -86,6 +93,7 @@ void MacosFrontend::pollPasteboard() {
8693
}
8794

8895
void MacosFrontend::updateConfig() {
96+
SwiftFrontend::setStatusItemMode(int(*config_.statusBar));
8997
simulateKeyRelease_ = config_.simulateKeyRelease.value();
9098
simulateKeyReleaseDelay_ =
9199
static_cast<long>(config_.simulateKeyReleaseDelay.value()) * 1000L;

macosfrontend/macosfrontend.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
#define TERMINAL_USE_EN \
2424
R"JSON({"appPath": "/System/Applications/Utilities/Terminal.app", "appId": "com.apple.Terminal", "imName": "keyboard-us"})JSON"
2525

26+
enum class StatusBar { Hidden, ToggleInputMethod, Menu };
27+
FCITX_CONFIG_ENUM_NAME_WITH_I18N(StatusBar, N_("Hidden"),
28+
N_("Toggle input method"), N_("Menu"))
29+
2630
namespace fcitx {
2731

2832
class MacosInputContext;
@@ -37,6 +41,8 @@ struct AppIMAnnotation {
3741

3842
FCITX_CONFIGURATION(
3943
MacosFrontendConfig,
44+
OptionWithAnnotation<StatusBar, StatusBarI18NAnnotation> statusBar{
45+
this, "StatusBar", _("Status bar"), StatusBar::Menu};
4046
OptionWithAnnotation<std::vector<std::string>, AppIMAnnotation>
4147
appDefaultIM{
4248
this, "AppDefaultIM", _("App default IM"), {TERMINAL_USE_EN}};
@@ -91,8 +97,10 @@ class MacosFrontend : public AddonInstance {
9197
static const inline std::string ConfPath = "conf/macosfrontend.conf";
9298

9399
FocusGroup focusGroup_; // ensure there is at most one active ic
94-
std::unique_ptr<HandlerTableEntry<EventHandler>> eventHandler_;
100+
std::vector<std::unique_ptr<HandlerTableEntry<EventHandler>>>
101+
eventHandlers_;
95102
std::string statusItemText;
103+
void updateStatusItemText();
96104

97105
inline MacosInputContext *findIC(ICUUID);
98106
void useAppDefaultIM(const std::string &appId);

macosfrontend/macosfrontend.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ public func setController(_ ctrl: Any) {
1414
controller = ctrl as? IMKInputController
1515
}
1616

17-
private var statusItemCallback: ((String) -> Void)? = nil
17+
private var statusItemCallback: ((Int32?, String?) -> Void)? = nil
1818

19-
public func setStatusItemCallback(_ callback: @escaping (String) -> Void) {
19+
public func setStatusItemCallback(_ callback: @escaping (Int32?, String?) -> Void) {
2020
statusItemCallback = callback
2121
}
2222

2323
public func setStatusItemText(_ text: String) {
24-
statusItemCallback?(text)
24+
statusItemCallback?(nil, text)
25+
}
26+
27+
public func setStatusItemMode(_ mode: Int32) {
28+
statusItemCallback?(mode, nil)
2529
}
2630

2731
private func commitString(_ client: IMKTextInput, _ string: String) {

src/controller.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ class FcitxInputController: IMKInputController {
4343
// Do not clear in deinit, otherwise it will crash with
4444
// "Simultaneous accesses to 0x100e05650, but modification requires exclusive access."
4545
setController(self)
46-
setStatusItemCallback { text in
47-
// No concrete evidence that this needs to be on main thread but just to be safe.
48-
DispatchQueue.main.async {
49-
if let button = AppDelegate.statusItem?.button {
50-
button.title = text
51-
}
52-
}
53-
}
5446
}
5547

5648
deinit {

src/server.swift

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Cocoa
22
import Fcitx
33
import InputMethodKit
4+
import SwiftFrontend
45
import SwiftNotify
56

67
class NSManualApplication: NSApplication {
@@ -40,18 +41,53 @@ class AppDelegate: NSObject, NSApplicationDelegate {
4041
static var server = IMKServer()
4142
static var notificationDelegate = NotificationDelegate()
4243
static var statusItem: NSStatusItem?
44+
static var statusItemText: String = "🐧"
4345

4446
func applicationDidFinishLaunching(_ notification: Notification) {
4547
redirectStderr()
4648

4749
signal(SIGTERM, signalHandler)
4850

49-
// NSStatusItem.variableLength causes layout shift of icons on the left when switching between en and 拼.
50-
AppDelegate.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
51-
52-
if let button = AppDelegate.statusItem?.button {
53-
button.action = #selector(handleStatusItemClick)
54-
button.target = self
51+
setStatusItemCallback { mode, text in
52+
// Main thread could call fcitx thread which then calls this, so must be async.
53+
DispatchQueue.main.async { [self] in
54+
if let mode = mode {
55+
if mode == 0 { // Hidden
56+
AppDelegate.statusItem = nil
57+
} else {
58+
// NSStatusItem.variableLength causes layout shift of icons on the left when switching between en and 拼.
59+
let statusItem: NSStatusItem = NSStatusBar.system.statusItem(
60+
withLength: NSStatusItem.variableLength)
61+
AppDelegate.statusItem = statusItem
62+
if let button = statusItem.button {
63+
button.title = AppDelegate.statusItemText
64+
button.target = self
65+
if mode == 1 { // Toggle input method
66+
button.action = #selector(toggle)
67+
} else // Menu
68+
{
69+
let menu = NSMenu()
70+
menu.addItem(
71+
NSMenuItem(
72+
title: NSLocalizedString("Toggle input method", comment: ""),
73+
action: #selector(toggle), keyEquivalent: ""))
74+
menu.addItem(NSMenuItem.separator())
75+
menu.addItem(
76+
NSMenuItem(
77+
title: NSLocalizedString("Hide", comment: ""),
78+
action: #selector(hide), keyEquivalent: ""))
79+
statusItem.menu = menu
80+
}
81+
}
82+
}
83+
}
84+
if let text = text {
85+
AppDelegate.statusItemText = text
86+
if let button = AppDelegate.statusItem?.button {
87+
button.title = text
88+
}
89+
}
90+
}
5591
}
5692

5793
AppDelegate.server = IMKServer(
@@ -69,7 +105,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
69105
stop_fcitx_thread()
70106
}
71107

72-
@objc func handleStatusItemClick() {
108+
@objc func toggle() {
73109
toggleInputMethod()
74110
}
111+
112+
@objc func hide() {
113+
Fcitx.setConfig("fcitx://config/addon/macosfrontend", "{\"StatusBar\": \"Hidden\"}")
114+
}
75115
}

0 commit comments

Comments
 (0)