Skip to content

Commit 7dfa74f

Browse files
committed
feat: add mango modules: workspace,language,keymode,window,layout
1 parent 0594574 commit 7dfa74f

21 files changed

Lines changed: 1514 additions & 0 deletions

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- River (Mapping mode, Tags, Focused window name)
1010
- Hyprland (Window Icons, Workspaces, Focused window name)
1111
- Niri (Workspaces, Focused window name, Language)
12+
- Mango (Workspaces, Focused window name, Language, Keymode)
1213
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc)
1314
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
1415
- Local time

include/modules/mango/backend.hpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// include/modules/mango/backend.hpp
2+
#pragma once
3+
4+
#include <list>
5+
#include <mutex>
6+
#include <string>
7+
#include <thread>
8+
#include <unordered_map>
9+
#include <vector>
10+
11+
#include "util/json.hpp"
12+
13+
namespace waybar::modules::mango {
14+
15+
class EventHandler {
16+
public:
17+
virtual void onEvent(const Json::Value& ev) = 0;
18+
virtual ~EventHandler() = default;
19+
};
20+
21+
class IPC {
22+
public:
23+
IPC();
24+
~IPC();
25+
26+
IPC(const IPC&) = delete;
27+
IPC& operator=(const IPC&) = delete;
28+
29+
void registerForIPC(const std::string& ev, EventHandler* handler);
30+
void unregisterForIPC(EventHandler* handler);
31+
32+
static Json::Value send(const Json::Value& request);
33+
static void sendAsync(const Json::Value& request);
34+
35+
std::unique_lock<std::mutex> lockData() { return std::unique_lock<std::mutex>(data_mutex_); }
36+
37+
std::unordered_map<std::string, Json::Value> getMonitors() const;
38+
Json::Value getMonitor(const std::string& name);
39+
Json::Value getActiveClientForMonitor(const std::string& name) const;
40+
std::string getKeyboardLayout() const;
41+
std::string getKeymode() const;
42+
std::string getLayoutSymbolForMonitor(const std::string& name) const;
43+
44+
private:
45+
void startIPC();
46+
static int connectToSocket();
47+
void parseIPC(const std::string& line);
48+
49+
void handleMonitorUpdate(const Json::Value& mon);
50+
void updateFocusingClient(const Json::Value& client);
51+
void updateKeyboardLayout(const std::string& layout);
52+
53+
static Json::Value sendCommand(const std::string& cmd);
54+
55+
int sockfd_ = -1;
56+
std::thread ipc_thread_;
57+
mutable std::mutex data_mutex_;
58+
std::unordered_map<std::string, Json::Value> monitors_;
59+
std::unordered_map<uint64_t, Json::Value> clients_;
60+
uint64_t focusing_client_id_ = 0;
61+
std::string keyboard_layout_;
62+
std::string keymode_;
63+
Json::Value active_client_;
64+
std::mutex callback_mutex_;
65+
std::list<std::pair<std::string, EventHandler*>> callbacks_;
66+
};
67+
68+
inline std::unique_ptr<IPC> gIPC;
69+
70+
} // namespace waybar::modules::mango

include/modules/mango/keymode.hpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#include <mutex>
4+
#include <string>
5+
6+
#include "ALabel.hpp"
7+
#include "bar.hpp"
8+
#include "modules/mango/backend.hpp"
9+
10+
namespace waybar::modules::mango {
11+
12+
class Keymode : public ALabel, public EventHandler {
13+
public:
14+
Keymode(const std::string&, const Bar&, const Json::Value&);
15+
~Keymode() override;
16+
void update() override;
17+
18+
private:
19+
void onEvent(const Json::Value& ev) override;
20+
void doUpdate();
21+
22+
std::mutex mutex_;
23+
const Bar& bar_;
24+
std::string last_keymode_;
25+
};
26+
27+
} // namespace waybar::modules::mango

include/modules/mango/language.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include <string>
4+
5+
#include "ALabel.hpp"
6+
#include "bar.hpp"
7+
#include "modules/mango/backend.hpp"
8+
9+
namespace waybar::modules::mango {
10+
11+
class Language : public ALabel, public EventHandler {
12+
public:
13+
Language(const std::string&, const Bar&, const Json::Value&);
14+
~Language() override;
15+
void update() override;
16+
17+
private:
18+
void updateFromIPC();
19+
void onEvent(const Json::Value& ev) override;
20+
void doUpdate();
21+
22+
struct Layout {
23+
std::string full_name;
24+
std::string short_name;
25+
std::string variant;
26+
std::string short_description;
27+
};
28+
29+
static Layout getLayout(const std::string& fullName);
30+
31+
std::mutex mutex_;
32+
const Bar& bar_;
33+
34+
std::vector<Layout> layouts_;
35+
unsigned current_idx_;
36+
std::string last_short_name_;
37+
};
38+
39+
} // namespace waybar::modules::mango

include/modules/mango/layout.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#include <mutex>
4+
#include <string>
5+
6+
#include "ALabel.hpp"
7+
#include "bar.hpp"
8+
#include "modules/mango/backend.hpp"
9+
10+
namespace waybar::modules::mango {
11+
12+
class Layout : public ALabel, public EventHandler {
13+
public:
14+
Layout(const std::string&, const Bar&, const Json::Value&);
15+
~Layout() override;
16+
void update() override;
17+
18+
private:
19+
void onEvent(const Json::Value& ev) override;
20+
void doUpdate();
21+
22+
std::mutex mutex_;
23+
const Bar& bar_;
24+
};
25+
26+
} // namespace waybar::modules::mango

include/modules/mango/window.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include <gtkmm/button.h>
4+
#include <json/value.h>
5+
6+
#include <mutex>
7+
8+
#include "AAppIconLabel.hpp"
9+
#include "bar.hpp"
10+
#include "modules/mango/backend.hpp"
11+
12+
namespace waybar::modules::mango {
13+
14+
class Window : public AAppIconLabel, public EventHandler {
15+
public:
16+
Window(const std::string&, const Bar&, const Json::Value&);
17+
~Window() override;
18+
void update() override;
19+
20+
private:
21+
void onEvent(const Json::Value& ev) override;
22+
void doUpdate();
23+
void setClass(const std::string& className, bool enable);
24+
25+
const Bar& bar_;
26+
std::string oldAppId_;
27+
std::mutex mutex_;
28+
};
29+
30+
} // namespace waybar::modules::mango
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
3+
#include <gtkmm/button.h>
4+
#include <json/value.h>
5+
6+
#include <unordered_map>
7+
8+
#include "AModule.hpp"
9+
#include "bar.hpp"
10+
#include "modules/mango/backend.hpp"
11+
12+
namespace waybar::modules::mango {
13+
14+
class Workspaces : public AModule, public EventHandler {
15+
public:
16+
Workspaces(const std::string&, const Bar&, const Json::Value&);
17+
~Workspaces() override;
18+
void update() override;
19+
20+
private:
21+
void onEvent(const Json::Value& ev) override;
22+
void doUpdate();
23+
24+
Gtk::Button& addButton(uint64_t idx);
25+
void updateButtonState(Gtk::Button& button, const Json::Value& tag, const Json::Value& monitor);
26+
std::string getIcon(const std::string& value, const Json::Value& tag);
27+
bool handleButtonClick(GdkEventButton* event, uint64_t idx, bool isOverview);
28+
29+
const Bar& bar_;
30+
Gtk::Box box_;
31+
32+
std::unordered_map<uint64_t, Gtk::Button> buttons_;
33+
Gtk::Button* overview_button_ = nullptr;
34+
35+
std::string on_click_left_;
36+
std::string on_click_middle_;
37+
std::string on_click_right_;
38+
};
39+
40+
} // namespace waybar::modules::mango

man/waybar-mango-keymode.5.scd

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
waybar-mango-keymode(5)
2+
3+
# NAME
4+
5+
waybar - mango keymode module
6+
7+
# DESCRIPTION
8+
9+
The *keymode* module displays the current keyboard mode (e.g. "resize", "default") in the Mango compositor. It is hidden when no mode is active.
10+
11+
# CONFIGURATION
12+
13+
Addressed by *mango/keymode*
14+
15+
*format*: ++
16+
typeof: string ++
17+
default: {} ++
18+
The format, how the mode should be displayed. *{mode}* is replaced by the current mode name.
19+
20+
*format-<mode>*: ++
21+
typeof: string ++
22+
Provide a custom format for a specific keymode. *<mode>* is the mode name as reported by Mango (e.g. "resize"). The value can contain *{mode}* as a placeholder.
23+
If this option is set, it overrides the main *format* for that mode.
24+
25+
*menu*: ++
26+
typeof: string ++
27+
Action that pops up a menu.
28+
29+
*menu-file*: ++
30+
typeof: string ++
31+
Location of the menu descriptor file.
32+
33+
*menu-actions*: ++
34+
typeof: array ++
35+
Actions for the menu buttons.
36+
37+
*expand*: ++
38+
typeof: bool ++
39+
default: false ++
40+
Enables the module to consume all leftover space.
41+
42+
# FORMAT REPLACEMENTS
43+
44+
*{mode}*: The name of the current keymode.
45+
46+
# EXAMPLES
47+
48+
```
49+
"mango/keymode": {
50+
"format": "[{mode}]",
51+
"format-resize": " Resizing"
52+
}
53+
```
54+
55+
# STYLE
56+
57+
- *#keymode*
58+
59+
A CSS class with the current mode name (e.g. *.resize*) is added to the widget, allowing per‑mode styling:
60+
61+
```
62+
#keymode.resize { background: #ff0000; }
63+
```

man/waybar-mango-language.5.scd

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
waybar-mango-language(5)
2+
3+
# NAME
4+
5+
waybar - mango language module
6+
7+
# DESCRIPTION
8+
9+
The *language* module displays the currently active keyboard layout in the Mango compositor.
10+
11+
# CONFIGURATION
12+
13+
Addressed by *mango/language*
14+
15+
*format*: ++
16+
typeof: string ++
17+
default: {} ++
18+
The format, how the layout should be displayed. See *FORMAT REPLACEMENTS*.
19+
20+
*format-<lang>*: ++
21+
typeof: string ++
22+
Provide an alternative format string for a given language.
23+
<lang> is the short description of the layout (e.g. "us", "de").
24+
The value is used as the replacement for *{}* in the main *format*.
25+
This option can be repeated for multiple languages.
26+
27+
*menu*: ++
28+
typeof: string ++
29+
Action that pops up a menu.
30+
31+
*menu-file*: ++
32+
typeof: string ++
33+
Location of the menu descriptor file. It must contain an element of type GtkMenu with id *menu*.
34+
35+
*menu-actions*: ++
36+
typeof: array ++
37+
Actions corresponding to the buttons of the menu.
38+
39+
*expand*: ++
40+
typeof: bool ++
41+
default: false ++
42+
Enables this module to consume all leftover space dynamically.
43+
44+
# FORMAT REPLACEMENTS
45+
46+
*{short}*: Short name of the layout (e.g. "us"). This is also the default when no format is specified.
47+
48+
*{shortDescription}*: Short description of the layout (same as *{short}* in most cases).
49+
50+
*{long}*: Full name of the layout as reported by Mango (e.g. "English (US)").
51+
52+
*{variant}*: Variant of the layout, if any.
53+
54+
# EXAMPLES
55+
56+
```
57+
"mango/language": {
58+
"format": " {long} ",
59+
"format-us": "US",
60+
"format-de": "DE"
61+
}
62+
```
63+
64+
# STYLE
65+
66+
- *#language*
67+
68+
A CSS class matching the current layout's short name is added to the widget.
69+
This allows per‑layout styling:
70+
71+
```
72+
#language.us { color: #00ff00; }
73+
#language.de { color: #ff0000; }
74+
```

0 commit comments

Comments
 (0)