diff --git a/src/uterm.h b/src/uterm.h index cbeea7d..4e743f7 100644 --- a/src/uterm.h +++ b/src/uterm.h @@ -127,6 +127,14 @@ struct uterm_video_hotplug { int action; }; +enum uterm_display_action { + UTERM_PAGE_FLIP, +}; + +struct uterm_display_event { + int action; +}; + enum uterm_video_format { UTERM_FORMAT_GREY, UTERM_FORMAT_XRGB32, @@ -155,6 +163,9 @@ struct uterm_video_blend_req { typedef void (*uterm_video_cb) (struct uterm_video *video, struct uterm_video_hotplug *arg, void *data); +typedef void (*uterm_display_cb) (struct uterm_display *disp, + struct uterm_display_event *arg, + void *data); /* misc */ @@ -203,6 +214,11 @@ void uterm_display_ref(struct uterm_display *disp); void uterm_display_unref(struct uterm_display *disp); struct uterm_display *uterm_display_next(struct uterm_display *disp); +int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb, + void *data); +void uterm_display_unregister_cb(struct uterm_display *disp, + uterm_display_cb cb, void *data); + struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp); struct uterm_mode *uterm_display_get_current(struct uterm_display *disp); struct uterm_mode *uterm_display_get_default(struct uterm_display *disp); diff --git a/src/uterm_video.c b/src/uterm_video.c index 1d34bff..32f6eca 100644 --- a/src/uterm_video.c +++ b/src/uterm_video.c @@ -270,14 +270,20 @@ int display_new(struct uterm_display **out, const struct display_ops *ops) disp->ref = 1; disp->ops = ops; - ret = VIDEO_CALL(disp->ops->init, 0, disp); + ret = shl_hook_new(&disp->hook); if (ret) goto err_free; + ret = VIDEO_CALL(disp->ops->init, 0, disp); + if (ret) + goto err_hook; + log_info("new display %p", disp); *out = disp; return 0; +err_hook: + shl_hook_free(disp->hook); err_free: free(disp); return ret; @@ -307,6 +313,7 @@ void uterm_display_unref(struct uterm_display *disp) mode->next = NULL; uterm_mode_unref(mode); } + shl_hook_free(disp->hook); free(disp); } @@ -318,6 +325,24 @@ struct uterm_display *uterm_display_next(struct uterm_display *disp) return disp->next; } +int uterm_display_register_cb(struct uterm_display *disp, uterm_display_cb cb, + void *data) +{ + if (!disp) + return -EINVAL; + + return shl_hook_add_cast(disp->hook, cb, data); +} + +void uterm_display_unregister_cb(struct uterm_display *disp, + uterm_display_cb cb, void *data) +{ + if (!disp) + return; + + shl_hook_rm_cast(disp->hook, cb, data); +} + struct uterm_mode *uterm_display_get_modes(struct uterm_display *disp) { if (!disp) diff --git a/src/uterm_video.h b/src/uterm_video.h index 8803592..3bbdaef 100644 --- a/src/uterm_video.h +++ b/src/uterm_video.h @@ -337,6 +337,7 @@ struct uterm_display { struct uterm_display *next; struct uterm_video *video; + struct shl_hook *hook; struct uterm_mode *modes; struct uterm_mode *default_mode; struct uterm_mode *current_mode; @@ -352,6 +353,11 @@ struct uterm_display { int display_new(struct uterm_display **out, const struct display_ops *ops); +#define DISPLAY_CB(disp, act) shl_hook_call((disp)->hook, (disp), \ + &(struct uterm_display_event){ \ + .action = (act), \ + }) + static inline bool display_is_conn(const struct uterm_display *disp) { return disp->video; diff --git a/src/uterm_video_drm.c b/src/uterm_video_drm.c index 6803ca7..9ca0d51 100644 --- a/src/uterm_video_drm.c +++ b/src/uterm_video_drm.c @@ -979,8 +979,11 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, { struct uterm_display *disp = data; - disp->flags &= ~DISPLAY_VSYNC; uterm_display_unref(disp); + if (disp->flags & DISPLAY_VSYNC) { + disp->flags &= ~DISPLAY_VSYNC; + DISPLAY_CB(disp, UTERM_PAGE_FLIP); + } } static void event(struct ev_fd *fd, int mask, void *data) diff --git a/src/uterm_video_dumb.c b/src/uterm_video_dumb.c index b054ff2..3633a4a 100644 --- a/src/uterm_video_dumb.c +++ b/src/uterm_video_dumb.c @@ -742,8 +742,11 @@ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, { struct uterm_display *disp = data; - disp->flags &= ~DISPLAY_VSYNC; uterm_display_unref(disp); + if (disp->flags & DISPLAY_VSYNC) { + disp->flags &= ~DISPLAY_VSYNC; + DISPLAY_CB(disp, UTERM_PAGE_FLIP); + } } static void event(struct ev_fd *fd, int mask, void *data) diff --git a/src/uterm_video_fbdev.c b/src/uterm_video_fbdev.c index 28228ac..c9c733e 100644 --- a/src/uterm_video_fbdev.c +++ b/src/uterm_video_fbdev.c @@ -343,8 +343,10 @@ static int display_swap(struct uterm_display *disp) if (!(disp->flags & DISPLAY_ONLINE)) return -EINVAL; - if (!(disp->flags & DISPLAY_DBUF)) + if (!(disp->flags & DISPLAY_DBUF)) { + DISPLAY_CB(disp, UTERM_PAGE_FLIP); return 0; + } vinfo = &disp->fbdev.vinfo; vinfo->activate = FB_ACTIVATE_VBL; @@ -362,6 +364,7 @@ static int display_swap(struct uterm_display *disp) } disp->fbdev.bufid ^= 1; + DISPLAY_CB(disp, UTERM_PAGE_FLIP); return 0; }