aboutsummaryrefslogtreecommitdiff
path: root/src/er_xdg_pipe_menu_cache.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/er_xdg_pipe_menu_cache.erl')
-rw-r--r--src/er_xdg_pipe_menu_cache.erl56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/er_xdg_pipe_menu_cache.erl b/src/er_xdg_pipe_menu_cache.erl
new file mode 100644
index 0000000..a71526e
--- /dev/null
+++ b/src/er_xdg_pipe_menu_cache.erl
@@ -0,0 +1,56 @@
+%%%-------------------------------------------------------------------
+%% @doc Caches the rendered Openbox pipe menu in memory.
+%%
+%% Holds the last-rendered menu binary so socket clients get an
+%% instant response. `invalidate/0' synchronously rescans the XDG
+%% application directories, reparses every `.desktop' file and
+%% re-renders the menu, replacing the cached binary.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(er_xdg_pipe_menu_cache).
+
+-behaviour(gen_server).
+
+-export([start_link/0, get_menu/0, invalidate/0, build/1]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
+
+-spec start_link() -> {ok, pid()}.
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+-spec get_menu() -> binary().
+get_menu() ->
+ gen_server:call(?MODULE, get_menu).
+
+-spec invalidate() -> ok.
+invalidate() ->
+ gen_server:cast(?MODULE, invalidate).
+
+%% Pure pipeline: explicit dirs in, rendered menu binary out. Kept
+%% side-effect-free (besides reading the filesystem) and exported so
+%% it can be unit tested directly and reused by the CLI client's
+%% no-daemon fallback, without going through the gen_server at all.
+-spec build([file:filename_all()]) -> binary().
+build(Dirs) ->
+ Files = er_xdg_pipe_menu_scanner:find_desktop_files(Dirs),
+ Entries = lists:filtermap(fun parse/1, Files),
+ er_xdg_pipe_menu_renderer:render(Entries).
+
+parse(File) ->
+ case er_xdg_pipe_menu_desktop_entry:parse_file(File) of
+ {ok, Entry} -> {true, Entry};
+ {error, _} -> false
+ end.
+
+init([]) ->
+ {ok, build(er_xdg_pipe_menu_scanner:data_dirs())}.
+
+handle_call(get_menu, _From, Menu) ->
+ {reply, Menu, Menu}.
+
+handle_cast(invalidate, _Menu) ->
+ {noreply, build(er_xdg_pipe_menu_scanner:data_dirs())}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.