summaryrefslogtreecommitdiff
path: root/app/include/zmk/display.h
diff options
context:
space:
mode:
Diffstat (limited to 'app/include/zmk/display.h')
-rw-r--r--app/include/zmk/display.h51
1 files changed, 50 insertions, 1 deletions
diff --git a/app/include/zmk/display.h b/app/include/zmk/display.h
index d3bd042..45a4bee 100644
--- a/app/include/zmk/display.h
+++ b/app/include/zmk/display.h
@@ -4,8 +4,57 @@
* SPDX-License-Identifier: MIT
*/
+/** @file display.h
+ * @brief Display functions and macros.
+ */
+
#pragma once
struct k_work_q *zmk_display_work_q();
-int zmk_display_init(); \ No newline at end of file
+bool zmk_display_is_initialized();
+int zmk_display_init();
+
+/**
+ * @brief Macro to define a ZMK event listener that handles the thread safety of fetching
+ * the necessary state from the system work queue context, invoking a work callback
+ * in the display queue context, and properly accessing that state safely when performing
+ * display/LVGL updates.
+ *
+ * @param listener THe ZMK Event manager listener name.
+ * @param state_type The struct/enum type used to store/transfer state.
+ * @param cb The callback to invoke in the dispaly queue context to update the UI. Should be `void
+ * func(state_type)` signature.
+ * @param state_func The callback function to invoke to fetch the updated state from ZMK core.
+ * Should be `state type func(const zmk_event_t *eh)` signature.
+ * @retval listner##_init Generates a function `listener##_init` that should be called by the widget
+ * once ready to be updated.
+ **/
+#define ZMK_DISPLAY_WIDGET_LISTENER(listener, state_type, cb, state_func) \
+ K_MUTEX_DEFINE(listener##_mutex); \
+ static state_type __##listener##_state; \
+ static state_type listener##_get_local_state() { \
+ k_mutex_lock(&listener##_mutex, K_FOREVER); \
+ state_type copy = __##listener##_state; \
+ k_mutex_unlock(&listener##_mutex); \
+ return copy; \
+ }; \
+ static void listener##_work_cb(struct k_work *work) { cb(listener##_get_local_state()); }; \
+ K_WORK_DEFINE(listener##_work, listener##_work_cb); \
+ static void listener##_refresh_state(const zmk_event_t *eh) { \
+ k_mutex_lock(&listener##_mutex, K_FOREVER); \
+ __##listener##_state = state_func(eh); \
+ k_mutex_unlock(&listener##_mutex); \
+ }; \
+ static void listener##_init() { \
+ listener##_refresh_state(NULL); \
+ listener##_work_cb(NULL); \
+ } \
+ static int listener##_cb(const zmk_event_t *eh) { \
+ if (zmk_display_is_initialized()) { \
+ listener##_refresh_state(eh); \
+ k_work_submit_to_queue(zmk_display_work_q(), &listener##_work); \
+ } \
+ return ZMK_EV_EVENT_BUBBLE; \
+ } \
+ ZMK_LISTENER(listener, listener##_cb);