aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/plugins/PluginAPI.hpp
blob: 36cdbe63cbf7b71022c4618201adb303cbfa6f26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#pragma once

/*

Hyprland Plugin API.

Most documentation will be made with comments in this code, but more info can be also found on the wiki.

!WARNING!
The Hyprland API passes C++ objects over, so no ABI compatibility is guaranteed.
Make sure to compile your plugins with the same compiler as Hyprland, and ideally,
on the same machine.

See examples/examplePlugin for an example plugin

 * NOTE:
Feel like the API is missing something you'd like to use in your plugin? Open an issue on github!

*/

#define HYPRLAND_API_VERSION "0.1"

#include "../helpers/Color.hpp"
#include "HookSystem.hpp"
#include "../SharedDefs.hpp"
#include "../version.h"

#include <any>
#include <functional>
#include <string>

typedef std::function<void(void*, SCallbackInfo&, std::any)> HOOK_CALLBACK_FN;
typedef struct {
    std::string name;
    std::string description;
    std::string author;
    std::string version;
} PLUGIN_DESCRIPTION_INFO;

struct SFunctionMatch {
    void*       address = nullptr;
    std::string signature;
    std::string demangled;
};

struct SVersionInfo {
    std::string hash;
    std::string tag;
    bool        dirty = false;
    std::string branch;
    std::string message;
};

#define APICALL extern "C"
#define EXPORT  __attribute__((visibility("default")))
#define REQUIRED
#define OPTIONAL
#define HANDLE void*

class IHyprLayout;
class CWindow;
class IHyprWindowDecoration;
struct SConfigValue;

/*
    These methods are for the plugin to implement
    Methods marked with REQUIRED are required.
*/

/* 
    called pre-plugin init.
    In case of a version mismatch, will eject the .so.

    This function should not be modified, see the example plugin.
*/
typedef REQUIRED std::string (*PPLUGIN_API_VERSION_FUNC)();
#define PLUGIN_API_VERSION          pluginAPIVersion
#define PLUGIN_API_VERSION_FUNC_STR "pluginAPIVersion"

/*
    called on plugin init. Passes a handle as the parameter, which the plugin should keep for identification later.
    The plugin should return a PLUGIN_DESCRIPTION_INFO struct with information about itself.

    Keep in mind this is executed synchronously, and as such any blocking calls to hyprland might hang. (e.g. system("hyprctl ..."))
*/
typedef REQUIRED PLUGIN_DESCRIPTION_INFO (*PPLUGIN_INIT_FUNC)(HANDLE);
#define PLUGIN_INIT          pluginInit
#define PLUGIN_INIT_FUNC_STR "pluginInit"

/*
    called on plugin unload, if that was a user action. If the plugin is being unloaded by an error,
    this will not be called.

    Hooks are unloaded after exit.
*/
typedef OPTIONAL void (*PPLUGIN_EXIT_FUNC)(void);
#define PLUGIN_EXIT          pluginExit
#define PLUGIN_EXIT_FUNC_STR "pluginExit"

/*
    End plugin methods
*/

namespace HyprlandAPI {

    /*
        Add a config value.
        All config values MUST be in the plugin: namespace
        This method may only be called in "pluginInit"

        After you have registered ALL of your config values, you may call `getConfigValue`

        returns: true on success, false on fail
    */
    APICALL bool addConfigValue(HANDLE handle, const std::string& name, const SConfigValue& value);

    /*
        Get a config value.

        returns: a pointer to the config value struct, which is guaranteed to be valid for the life of this plugin, unless another `addConfigValue` is called afterwards.
                nullptr on error.
    */
    APICALL SConfigValue* getConfigValue(HANDLE handle, const std::string& name);

    /*
        Register a static (pointer) callback to a selected event.
        Pointer must be kept valid until unregisterCallback() is called.

        returns: true on success, false on fail
    */
    APICALL bool registerCallbackStatic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN* fn);

    /*
        Register a dynamic (function) callback to a selected event.
        Pointer will be free'd by Hyprland on unregisterCallback().

        returns: a pointer to the newly allocated function. nullptr on fail.
    */
    APICALL HOOK_CALLBACK_FN* registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn);

    /*
        Unregisters a callback. If the callback was dynamic, frees the memory.

        returns: true on success, false on fail
    */
    APICALL bool unregisterCallback(HANDLE handle, HOOK_CALLBACK_FN* fn);

    /*
        Calls a hyprctl command.

        returns: the output (as in hyprctl)
    */
    APICALL std::string invokeHyprctlCommand(const std::string& call, const std::string& args, const std::string& format = "");

    /*
        Adds a layout to Hyprland.

        returns: true on success. False otherwise.
    */
    APICALL bool addLayout(HANDLE handle, const std::string& name, IHyprLayout* layout);

    /*
        Removes an added layout from Hyprland.

        returns: true on success. False otherwise.
    */
    APICALL bool removeLayout(HANDLE handle, IHyprLayout* layout);

    /*
        Queues a config reload. Does not take effect immediately.

        returns: true on success. False otherwise.
    */
    APICALL bool reloadConfig();

    /*
        Adds a notification.

        returns: true on success. False otherwise.
    */
    APICALL bool addNotification(HANDLE handle, const std::string& text, const CColor& color, const float timeMs);

    /*
        Creates a trampoline function hook to an internal hl func.

        returns: CFunctionHook*

        !WARNING! Hooks are *not* guaranteed any API stability. Internal methods may be removed, added, or renamed. Consider preferring the API whenever possible.
    */
    APICALL CFunctionHook* createFunctionHook(HANDLE handle, const void* source, const void* destination);

    /*
        Removes a trampoline function hook. Will unhook if still hooked.

        returns: true on success. False otherwise.

        !WARNING! Hooks are *not* guaranteed any API stability. Internal methods may be removed, added, or renamed. Consider preferring the API whenever possible.
    */
    APICALL bool removeFunctionHook(HANDLE handle, CFunctionHook* hook);

    /*
        Gets a function address from a signature.
        This is useful for hooking private functions.

        returns: function address, or nullptr on fail.

        Deprecated because of findFunctionsByName.
    */
    APICALL [[deprecated]] void* getFunctionAddressFromSignature(HANDLE handle, const std::string& sig);

    /*
        Adds a window decoration to a window

        returns: true on success. False otherwise.
    */
    APICALL bool addWindowDecoration(HANDLE handle, CWindow* pWindow, IHyprWindowDecoration* pDecoration);

    /*
        Removes a window decoration

        returns: true on success. False otherwise.
    */
    APICALL bool removeWindowDecoration(HANDLE handle, IHyprWindowDecoration* pDecoration);

    /*
        Adds a keybind dispatcher.

        returns: true on success. False otherwise.
    */
    APICALL bool addDispatcher(HANDLE handle, const std::string& name, std::function<void(std::string)> handler);

    /*
        Removes a keybind dispatcher.

        returns: true on success. False otherwise.
    */
    APICALL bool removeDispatcher(HANDLE handle, const std::string& name);

    /*
        Adds a notification.

        data has to contain:
         - text: std::string or const char*
         - time: uint64_t
         - color: CColor -> CColor(0) will apply the default color for the notification icon

        data may contain:
         - icon: eIcons

        returns: true on success. False otherwise.
    */
    APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map<std::string, std::any>& data);

    /*
        Returns a vector of found functions matching the provided name.

        These addresses will not change, and should be made static. Lookups are slow.

        Empty means either none found or handle was invalid
    */
    APICALL std::vector<SFunctionMatch> findFunctionsByName(HANDLE handle, const std::string& name);

    /*
        Returns the hyprland version data. It's highly advised to not run plugins compiled
        for a different hash.
    */
    APICALL SVersionInfo getHyprlandVersion(HANDLE handle);
};

/*
    Get the hash this plugin/server was compiled with.

    This function will end up in both hyprland and any/all plugins,
    and can be found by a simple dlsym()
*/
APICALL inline EXPORT const char* __hyprland_api_get_hash() {
    return GIT_COMMIT_HASH;
}