Skip to content

Commit 1d4b909

Browse files
authored
adapt app-specific accent color (#255)
1 parent 0d373d6 commit 1d4b909

File tree

14 files changed

+110
-20
lines changed

14 files changed

+110
-20
lines changed

macosfrontend/macosfrontend-public.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ std::string process_key(ICUUID uuid, uint32_t unicode, uint32_t osxModifiers,
1111
uint16_t osxKeycode, bool isRelease,
1212
bool isPassword) noexcept;
1313

14-
ICUUID create_input_context(const char *appId, id client) noexcept;
14+
ICUUID create_input_context(const char *appId, id client,
15+
const char *accentColor) noexcept;
1516
void destroy_input_context(ICUUID uuid) noexcept;
1617
void focus_in(ICUUID uuid) noexcept;
1718
std::string focus_out(ICUUID uuid) noexcept;

macosfrontend/macosfrontend.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,10 @@ MacosInputContext *MacosFrontend::findIC(ICUUID uuid) {
122122
instance_->inputContextManager().findByUUID(uuid));
123123
}
124124

125-
ICUUID MacosFrontend::createInputContext(const std::string &appId, id client) {
125+
ICUUID MacosFrontend::createInputContext(const std::string &appId, id client,
126+
const std::string &accentColor) {
126127
auto ic = new MacosInputContext(this, instance_->inputContextManager(),
127-
appId, client);
128+
appId, client, accentColor);
128129
ic->setFocusGroup(&focusGroup_);
129130
FCITX_INFO() << "Create IC for " << appId;
130131
return ic->uuid();
@@ -174,6 +175,7 @@ void MacosFrontend::focusIn(ICUUID uuid) {
174175
auto *ic = findIC(uuid);
175176
if (!ic)
176177
return;
178+
webpanel_->applyAppAccentColor(ic->getAccentColor()); // app-specific
177179
ic->focusIn();
178180
auto program = ic->program();
179181
FCITX_INFO() << "Focus in " << program;
@@ -209,9 +211,10 @@ std::string MacosFrontend::focusOut(ICUUID uuid) {
209211

210212
MacosInputContext::MacosInputContext(MacosFrontend *frontend,
211213
InputContextManager &inputContextManager,
212-
const std::string &program, id client)
214+
const std::string &program, id client,
215+
const std::string &accentColor)
213216
: InputContext(inputContextManager, program), frontend_(frontend),
214-
client_(client) {
217+
client_(client), accentColor_(accentColor) {
215218
CFRetain(client_);
216219
CapabilityFlags flags = CapabilityFlag::Preedit;
217220
setCapabilityFlags(flags);
@@ -286,9 +289,10 @@ std::string process_key(ICUUID uuid, uint32_t unicode, uint32_t osxModifiers,
286289
});
287290
}
288291

289-
ICUUID create_input_context(const char *appId, id client) noexcept {
292+
ICUUID create_input_context(const char *appId, id client,
293+
const char *accentColor) noexcept {
290294
return with_fcitx([=](Fcitx &fcitx) {
291-
return fcitx.frontend()->createInputContext(appId, client);
295+
return fcitx.frontend()->createInputContext(appId, client, accentColor);
292296
});
293297
}
294298

macosfrontend/macosfrontend.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ class MacosFrontend : public AddonInstance {
7171
updateConfig();
7272
}
7373

74-
ICUUID createInputContext(const std::string &appId, id client);
74+
ICUUID createInputContext(const std::string &appId, id client,
75+
const std::string &accentColor);
7576
void destroyInputContext(ICUUID);
7677
std::string keyEvent(ICUUID, const Key &key, bool isRelease,
7778
bool isPassword);
@@ -108,7 +109,8 @@ class MacosInputContext : public InputContext {
108109
public:
109110
MacosInputContext(MacosFrontend *frontend,
110111
InputContextManager &inputContextManager,
111-
const std::string &program, id client);
112+
const std::string &program, id client,
113+
const std::string &accentColor);
112114
~MacosInputContext();
113115

114116
const char *frontend() const override { return "macos"; }
@@ -119,6 +121,7 @@ class MacosInputContext : public InputContext {
119121

120122
std::pair<double, double> getCursorCoordinates(bool followCursor);
121123
id client() { return client_; }
124+
std::string getAccentColor() { return accentColor_; }
122125

123126
void resetState() {
124127
state_.commit.clear();
@@ -139,6 +142,7 @@ class MacosInputContext : public InputContext {
139142
MacosFrontend *frontend_;
140143
id client_;
141144
InputContextState state_;
145+
std::string accentColor_;
142146
};
143147

144148
class MacosFrontendFactory : public AddonFactory {

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ add_executable(Fcitx5
4040
server.swift
4141
locale.swift
4242
controller.swift
43+
color.swift
4344
${CONFIG_UI_FILES}
4445
)
4546

src/color.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import AppKit
2+
3+
public func nsColorToString(_ color: NSColor) -> String? {
4+
guard let rgbColor = color.usingColorSpace(.sRGB) else {
5+
return nil
6+
}
7+
let red = UInt8(round(rgbColor.redComponent * 255.0))
8+
let green = UInt8(round(rgbColor.greenComponent * 255.0))
9+
let blue = UInt8(round(rgbColor.blueComponent * 255.0))
10+
let alpha = UInt8(round(rgbColor.alphaComponent * 255.0))
11+
return String(format: "#%02X%02X%02X%02X", red, green, blue, alpha)
12+
}
13+
14+
private var colorMap = [String: String]()
15+
16+
func getAccentColor(_ id: String) -> String {
17+
if let cachedColor = colorMap[id] {
18+
return cachedColor
19+
}
20+
if let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: id),
21+
let bundle = Bundle(url: url),
22+
let info = bundle.infoDictionary,
23+
let name = info["NSAccentColorName"] as? String,
24+
let color = NSColor(named: NSColor.Name(name), bundle: bundle),
25+
let string = nsColorToString(color)
26+
{
27+
colorMap[id] = string
28+
return string
29+
} else {
30+
colorMap[id] = ""
31+
return ""
32+
}
33+
}

src/config/optionmodels.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,8 @@ private func stringToColor(_ hex: String) -> Color {
202202

203203
private func colorToString(_ color: Color) -> String {
204204
let resolved = NSColor(color)
205-
if let rgbColor = resolved.usingColorSpace(.sRGB) {
206-
let red = UInt8(round(rgbColor.redComponent * 255.0))
207-
let green = UInt8(round(rgbColor.greenComponent * 255.0))
208-
let blue = UInt8(round(rgbColor.blueComponent * 255.0))
209-
let alpha = UInt8(round(rgbColor.alphaComponent * 255.0))
210-
return String(format: "#%02X%02X%02X%02X", red, green, blue, alpha)
205+
if let string = nsColorToString(resolved) {
206+
return string
211207
} else {
212208
FCITX_ERROR("Can't convert color \(color) to RGB")
213209
return "#000000FF"

src/controller.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class FcitxInputController: IMKInputController {
1919
var lastModifiers = NSEvent.ModifierFlags(rawValue: 0)
2020
var ignoreRelease: Bool = false
2121
let client: Any!
22+
var accentColor = ""
2223

2324
// A registry of live FcitxInputController objects.
2425
// Use NSHashTable to store weak references.
@@ -31,11 +32,12 @@ class FcitxInputController: IMKInputController {
3132
override init(server: IMKServer!, delegate: Any!, client: Any!) {
3233
if let client = client as? IMKTextInput {
3334
appId = client.bundleIdentifier() ?? ""
35+
accentColor = getAccentColor(appId)
3436
} else {
3537
appId = ""
3638
}
3739
self.client = client
38-
uuid = create_input_context(appId, client)
40+
uuid = create_input_context(appId, client, accentColor)
3941
super.init(server: server, delegate: delegate, client: client)
4042
FcitxInputController.registry.add(self)
4143
}
@@ -47,9 +49,9 @@ class FcitxInputController: IMKInputController {
4749

4850
func reconnectToFcitx() {
4951
// The old fcitx input context was automatically destroyed when
50-
// restarting fcitx. So just start a new one here.
52+
// restarting fcitx thread. So just start a new one here.
5153
FCITX_DEBUG("Reconnecting to \(appId), client = \(String(describing: client))")
52-
uuid = create_input_context(appId, client)
54+
uuid = create_input_context(appId, client, accentColor)
5355
}
5456

5557
func processRes(_ client: IMKTextInput, _ res: String, focusOut: Bool = false) -> Bool {

src/fcitx.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ namespace fs = std::filesystem;
2525

2626
FCITX_DEFINE_STATIC_ADDON_REGISTRY(getStaticAddon)
2727

28+
fcitx::WebPanel *webpanel_;
29+
2830
static std::string join_paths(const std::vector<fs::path> &paths,
2931
char sep = ':');
3032

@@ -89,13 +91,15 @@ void Fcitx::setup() {
8991
setupInstance();
9092
frontend_ =
9193
dynamic_cast<fcitx::MacosFrontend *>(addonMgr().addon("macosfrontend"));
94+
webpanel_ = dynamic_cast<fcitx::WebPanel *>(addonMgr().addon("webpanel"));
9295
auto beast_ = dynamic_cast<fcitx::Beast *>(addonMgr().addon("beast"));
9396
beast_->setConfigGetter(getConfig);
9497
beast_->setConfigSetter(setConfig);
9598
}
9699

97100
void Fcitx::teardown() {
98101
frontend_ = nullptr;
102+
webpanel_ = nullptr;
99103
instance_.reset();
100104
}
101105

src/fcitx.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
#include "fcitx-public.h"
99
#include "../macosfrontend/macosfrontend.h"
10+
#include "../webpanel/webpanel.h"
11+
12+
extern fcitx::WebPanel *webpanel_;
1013

1114
/// 'Fcitx' manages the lifecycle of the global Fcitx instance.
1215
class Fcitx final {

0 commit comments

Comments
 (0)