diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 13:13:52 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-14 13:13:52 +0300 |
| commit | 1ab3e5a123109704789c2768e11a4f9af515821d (patch) | |
| tree | 31ee03e58093a58100c6eb58681d5d29648a5ddd /src/common/surface.c | |
| parent | d86fa6215d40caa7852dbbd6a8cf4aa8e89dd879 (diff) | |
Redefine public and rendering APIs with explicit contracts
Diffstat (limited to 'src/common/surface.c')
| -rw-r--r-- | src/common/surface.c | 1429 |
1 files changed, 1035 insertions, 394 deletions
diff --git a/src/common/surface.c b/src/common/surface.c index b47fea7..de9e7b3 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -11,514 +11,1155 @@ #include <string.h> static struct yasl_private_display *display; -static enum yasl_backend requested_backend; -static char *application_id; static pthread_t owner; static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; static bool pumping; static unsigned refresh_depth; static char *delivered_text; /* Strings of the last returned event; freed by the next poll/wait. */ -static _Thread_local enum yasl_error last_error; -static _Thread_local int native_error; - -void yasl_public_set_error(enum yasl_error error, int native) -{ last_error=error; native_error=native; } bool yasl_public_fail(int error) { - if (!error) error=EIO; - enum yasl_error code=YASL_ERROR_IO; - if (error==EINVAL || error==EOVERFLOW || error==EILSEQ) code=YASL_ERROR_INVALID; - else if (error==ENOTSUP || error==ENOSYS) code=YASL_ERROR_UNSUPPORTED; - else if (error==ENOMEM) code=YASL_ERROR_NO_MEMORY; - else if (error==EBUSY) code=YASL_ERROR_BUSY; - else if (error==EPERM) code=YASL_ERROR_WRONG_THREAD; - else if (error==ENOTCONN) code=YASL_ERROR_DISCONNECTED; - yasl_public_set_error(code,error); errno=error; return false; -} -enum yasl_error yasl_get_error(const char **description) -{ - static const char *const messages[]={"No error","Invalid argument","Unsupported operation", - "Out of memory","Library not initialized","Operation is busy","Wrong thread", - "Input context expired","Native operation failed","Display disconnected"}; - if(description) *description=messages[last_error]; - return last_error; -} -int yasl_get_native_error(void) { return native_error; } -struct yasl_private_display *yasl_public_display(void) { return display; } + errno = error > 0 ? error : EIO; + return false; +} +int yasl_public_error(int error) +{ + yasl_public_fail(error); + return -errno; +} +int yasl_public_status(bool success) +{ + return success ? 0 : yasl_public_error(errno); +} +struct yasl_private_display *yasl_public_display(void) +{ + return display; +} bool yasl_public_owner(void) { - if(!display) { yasl_public_set_error(YASL_ERROR_NOT_INITIALIZED,0); return false; } - if(!pthread_equal(owner,pthread_self())) return yasl_public_fail(EPERM); + if (!display) + return yasl_public_fail(ENODEV); + if (!pthread_equal(owner, pthread_self())) + return yasl_public_fail(EPERM); return true; } -bool yasl_public_surface(yasl_surface *s,bool mutation) +bool yasl_public_surface(yasl_surface *s, bool mutation) { - if(!yasl_public_owner()) return false; - if(!s || s->display!=display) return yasl_public_fail(EINVAL); - if(mutation && refresh_depth) return yasl_public_fail(EBUSY); + if (!yasl_public_owner()) + return false; + if (!s || s->display != display) + return yasl_public_fail(EINVAL); + if (mutation && refresh_depth) + return yasl_public_fail(EBUSY); return true; } -static bool initialize(void) +int yasl_init(const struct yasl_options *options) { - if(display) return yasl_public_owner(); - struct yasl_private_display_spec spec={.app_id=application_id,.backend=(enum yasl_private_backend)requested_backend}; - struct yasl_private_display *d=yasl_private_display_open(NULL,&spec); - if(!d) return yasl_public_fail(errno); + if (display) { + if (!yasl_public_owner()) + return -errno; + return yasl_public_error(EALREADY); + } + struct yasl_options defaults = {0}; + if (!options) + options = &defaults; + if ((unsigned)options->backend > YASL_BACKEND_COCOA) + return yasl_public_error(EINVAL); + struct yasl_private_display_spec spec = { + .app_id = options->app_id, + .backend = (enum yasl_private_backend)options->backend, + }; + errno = 0; + struct yasl_private_display *d = yasl_private_display_open(NULL, &spec); + if (!d) + return yasl_public_error(errno); pthread_mutex_lock(&lifecycle_mutex); - owner=pthread_self(); display=d; + owner = pthread_self(); + display = d; pthread_mutex_unlock(&lifecycle_mutex); - return true; -} -bool yasl_set_app_id(const char *id) -{ - if(display) return yasl_public_fail(EBUSY); - char *copy=id ? strdup(id) : NULL; - if(id&&!copy) return yasl_public_fail(ENOMEM); - free(application_id); application_id=copy; return true; + return 0; } -bool yasl_set_backend(enum yasl_backend backend) +static bool initialize(void) { - if(display) return yasl_public_fail(EBUSY); - if(backend<YASL_BACKEND_AUTO || backend>YASL_BACKEND_COCOA) return yasl_public_fail(EINVAL); - requested_backend=backend; return true; + return display ? yasl_public_owner() : yasl_init(NULL) == 0; } -static bool creation_valid(int width,int height,unsigned flags) +static bool creation_valid(int width, int height, unsigned flags) { - if(width<=0 || height<=0 || width>32767 || height>32767 || - (unsigned long long)width*(unsigned)height>INT32_MAX/4 || (flags & ~15u)) + if (width <= 0 || height <= 0 || width > 32767 || height > 32767 || + (unsigned long long)width * (unsigned)height > INT32_MAX / 4 || (flags & ~15u)) return yasl_public_fail(EINVAL); - if(pumping || refresh_depth) return yasl_public_fail(EBUSY); + if (pumping || refresh_depth) + return yasl_public_fail(EBUSY); return true; } -static void draw_committed(yasl_surface *s,struct yasl_private_frame *frame,void *ud) +static void draw_committed(yasl_surface *s, struct yasl_private_frame *frame, void *ud) { (void)ud; - if(s->refresh_callback && pumping && !refresh_depth) { - ++refresh_depth; s->refresh_callback(s,s->refresh_userdata); --refresh_depth; - } - if(s->presenter!=YASL_PRIVATE_PRESENTER_CPU || !frame->target.pixels) return; - int w=frame->target.size.x,h=frame->target.size.y; - if(w==s->committed_width && h==s->committed_height && s->committed_pixels) - memcpy(frame->target.pixels,s->committed_pixels,(size_t)w*h*4); - else memset(frame->target.pixels,0,(size_t)w*h*4); - struct yasl_private_damage_list damage={.n=-1}; - yasl_private_surface_present(s,&frame->target,&damage); -} -void yasl_public_register_surface(yasl_surface *s,unsigned flags,yasl_surface *parent) -{ - s->creation_flags=flags; s->parent=parent; - if(flags&YASL_SURFACE_CPU) s->presenter=YASL_PRIVATE_PRESENTER_CPU; - struct yasl_private_window_cbs cb={.draw=draw_committed}; - yasl_private_surface_set_callbacks(s,&cb,NULL); - s->reported_state=s->state; - struct yasl_private_geometry geometry=yasl_private_surface_geometry(s); - yasl_private_surface_notify_configure(s,geometry); -} -yasl_surface *yasl_surface_create(const char *title,int width,int height,unsigned flags) -{ - if(!creation_valid(width,height,flags)) return NULL; - bool fresh=!display; - if(!initialize()) return NULL; - struct yasl_private_window_spec spec={.title=title,.size={width,height}, - .flags=flags,.external_gpu=!(flags&YASL_SURFACE_CPU)}; - yasl_surface *s=yasl_private_surface_create_toplevel(display,&spec); - if(!s) { - int error=errno; - if(fresh) { pthread_mutex_lock(&lifecycle_mutex); struct yasl_private_display *d=display; display=NULL; - pthread_mutex_unlock(&lifecycle_mutex); yasl_private_display_close(d); } - yasl_public_fail(error); return NULL; - } - yasl_public_register_surface(s,flags,NULL); return s; -} -void yasl_surface_destroy(yasl_surface *s) -{ - if(!s) return; - if(!yasl_public_surface(s,true)) return; - for(;;) { - yasl_surface *child=NULL; - for(yasl_surface *p=display->surfaces;p;p=p->event_next) if(p->parent==s) { child=p; break; } - if(!child) break; + if (s->refresh_callback && pumping && !refresh_depth) { + ++refresh_depth; + s->refresh_callback(s, s->refresh_userdata); + --refresh_depth; + } + if (s->presenter != YASL_PRIVATE_PRESENTER_CPU || !frame->target.pixels) + return; + int w = frame->target.size.x, h = frame->target.size.y; + if (w == s->committed_width && h == s->committed_height && s->committed_pixels) + memcpy(frame->target.pixels, s->committed_pixels, (size_t)w * h * 4); + else + memset(frame->target.pixels, 0, (size_t)w * h * 4); + struct yasl_private_damage_list damage = {.n = -1}; + yasl_private_surface_present(s, &frame->target, &damage); +} +void yasl_public_register_surface(yasl_surface *s, unsigned flags, yasl_surface *parent) +{ + s->creation_flags = flags; + s->parent = parent; + if (flags & YASL_PRIVATE_SURFACE_CPU) + s->presenter = YASL_PRIVATE_PRESENTER_CPU; + struct yasl_private_window_cbs cb = {.draw = draw_committed}; + yasl_private_surface_set_callbacks(s, &cb, NULL); + s->reported_state = s->state; + struct yasl_private_geometry geometry = yasl_private_surface_geometry(s); + yasl_private_surface_notify_configure(s, geometry); +} +yasl_surface *yasl_surface_create(const struct yasl_surface_options *options) +{ + if (!options || (unsigned)options->type > YASL_SURFACE_CPU || (options->flags & ~14u)) { + yasl_public_fail(EINVAL); + return NULL; + } + const char *title = options->title; + int width = options->width, height = options->height; + unsigned flags = + options->flags | (options->type == YASL_SURFACE_CPU ? YASL_PRIVATE_SURFACE_CPU : 0u); + if (!creation_valid(width, height, flags)) + return NULL; + bool fresh = !display; + if (!initialize()) + return NULL; + struct yasl_private_window_spec spec = {.title = title, + .size = {width, height}, + .flags = flags, + .external_gpu = !(flags & YASL_PRIVATE_SURFACE_CPU)}; + yasl_surface *s = yasl_private_surface_create_toplevel(display, &spec); + if (!s) { + int error = errno; + if (fresh) { + pthread_mutex_lock(&lifecycle_mutex); + struct yasl_private_display *d = display; + display = NULL; + pthread_mutex_unlock(&lifecycle_mutex); + yasl_private_display_close(d); + } + yasl_public_fail(error); + return NULL; + } + yasl_public_register_surface(s, flags, NULL); + s->userdata = options->userdata; + return s; +} +int yasl_surface_destroy(yasl_surface *s) +{ + if (!s) + return 0; + if (!yasl_public_surface(s, true)) + return -errno; + for (yasl_surface *p = display->surfaces; p; p = p->event_next) { + for (yasl_surface *ancestor = p; ancestor; ancestor = ancestor->parent) + if (ancestor == s && p->vulkan) + return yasl_public_error(EBUSY); + } + for (;;) { + yasl_surface *child = NULL; + for (yasl_surface *p = display->surfaces; p; p = p->event_next) + if (p->parent == s) { + child = p; + break; + } + if (!child) + break; yasl_surface_destroy(child); } - free(s->committed_pixels); s->committed_pixels=NULL; - free(s->text_surrounding); s->text_surrounding=NULL; + free(s->cpu_pixels); + s->cpu_pixels = NULL; + free(s->committed_pixels); + s->committed_pixels = NULL; + free(s->text_surrounding); + s->text_surrounding = NULL; yasl_private_surface_destroy(s); + return 0; } -void yasl_shutdown(void) +int yasl_shutdown(void) { - if(display && !yasl_public_owner()) return; - if(pumping || refresh_depth) { yasl_public_fail(EBUSY); return; } - if(display) { - while(display->surfaces) yasl_surface_destroy(display->surfaces); - pthread_mutex_lock(&lifecycle_mutex); struct yasl_private_display *d=display; display=NULL; - pthread_mutex_unlock(&lifecycle_mutex); yasl_private_display_close(d); + if (display && !yasl_public_owner()) + return -errno; + if (pumping || refresh_depth) { + yasl_public_fail(EBUSY); + return -errno; + } + if (display) { + for (yasl_surface *s = display->surfaces; s; s = s->event_next) + if (s->vulkan) + return yasl_public_error(EBUSY); + while (display->surfaces) + yasl_surface_destroy(display->surfaces); + pthread_mutex_lock(&lifecycle_mutex); + struct yasl_private_display *d = display; + display = NULL; + pthread_mutex_unlock(&lifecycle_mutex); + yasl_private_display_close(d); } - free(delivered_text); delivered_text=NULL; - free(application_id); application_id=NULL; requested_backend=YASL_BACKEND_AUTO; + free(delivered_text); + delivered_text = NULL; #if YASL_HAS_VULKAN extern void yasl_private_vulkan_reset(void); yasl_private_vulkan_reset(); #endif + return 0; } void yasl_wake(void) { pthread_mutex_lock(&lifecycle_mutex); - if(display && display->loop) yasl_private_loop_kick(display->loop); + if (display && display->loop) + yasl_private_loop_kick(display->loop); pthread_mutex_unlock(&lifecycle_mutex); } -uint64_t yasl_time_ns(void) { return yasl_private_loop_now_ns(); } +uint64_t yasl_time_ns(void) +{ + return yasl_private_loop_now_ns(); +} static double scale_of(const yasl_surface *s) -{ return s && s->scale_120 ? (double)s->scale_120/120.0 : 1.0; } -static int logical(int pixels,double scale) { return (int)lround(pixels/scale); } -enum yasl_backend yasl_surface_backend(const yasl_surface *s) -{ return s ? (enum yasl_backend)s->display->ops->type : YASL_BACKEND_AUTO; } -unsigned yasl_surface_features(const yasl_surface *s) -{ - if(!s) return 0; - unsigned caps=yasl_private_display_caps(s->display); - if(s->display->ops->surface_create_gl) caps|=YASL_CAP_OPENGL; +{ + return s && s->scale_120 ? (double)s->scale_120 / 120.0 : 1.0; +} +static int logical(int pixels, double scale) +{ + return (int)lround(pixels / scale); +} +enum yasl_backend yasl_surface_get_backend(const yasl_surface *s) +{ + return s && yasl_public_surface((yasl_surface *)s, false) + ? (enum yasl_backend)s->display->ops->type + : YASL_BACKEND_AUTO; +} +unsigned yasl_surface_get_features(const yasl_surface *s) +{ + if (!s || !yasl_public_surface((yasl_surface *)s, false)) + return 0; + unsigned caps = yasl_private_display_caps(s->display); + if (s->display->ops->surface_create_gl) + caps |= YASL_CAP_OPENGL; #if YASL_HAS_VULKAN - caps|=YASL_CAP_VULKAN; + caps |= YASL_CAP_VULKAN; #endif return caps; } -void yasl_surface_get_framebuffer_size(const yasl_surface *s,int *w,int *h) -{ if(w) *w=s?s->size.x:0; if(h) *h=s?s->size.y:0; } -void yasl_surface_get_size(const yasl_surface *s,int *w,int *h) -{ double scale=scale_of(s); if(w) *w=s?logical(s->size.x,scale):0; if(h) *h=s?logical(s->size.y,scale):0; } -double yasl_surface_get_scale(const yasl_surface *s) { return scale_of(s); } -unsigned yasl_surface_state(const yasl_surface *s) { return s?s->state:0; } -void *yasl_surface_userdata(const yasl_surface *s) { return s?s->userdata:NULL; } -void yasl_surface_set_userdata(yasl_surface *s,void *ud) { if(yasl_public_surface(s,false)) s->userdata=ud; } -bool yasl_surface_set_title(yasl_surface *s,const char *title) -{ - if(!yasl_public_surface(s,false)) return false; - if(!title) return yasl_public_fail(EINVAL); - if(!s->display->ops->surface_set_title) return yasl_public_fail(ENOTSUP); - s->display->ops->surface_set_title(s,title); return true; -} -#define REQUEST(name,priv,args,call) bool name args { if(!yasl_public_surface(s,false)) return false; errno=0; return priv call || yasl_public_fail(errno); } -REQUEST(yasl_surface_request_size,yasl_private_surface_set_size,(yasl_surface *s,int w,int h),(s,((struct yasl_private_vector2i){w,h}))) -REQUEST(yasl_surface_request_fullscreen,yasl_private_surface_set_fullscreen,(yasl_surface *s,bool v),(s,v)) -REQUEST(yasl_surface_request_maximized,yasl_private_surface_set_maximized,(yasl_surface *s,bool v),(s,v)) -REQUEST(yasl_surface_request_minimize,yasl_private_surface_minimize,(yasl_surface *s),(s)) -REQUEST(yasl_surface_set_pointer_mode,yasl_private_surface_set_pointer_mode,(yasl_surface *s,enum yasl_pointer_mode m),(s,(enum yasl_private_pointer_mode)m)) -bool yasl_surface_set_cursor(yasl_surface *s,enum yasl_cursor cursor) -{ - if(!yasl_public_surface(s,false)) return false; - if(cursor<YASL_CURSOR_ARROW || cursor>YASL_CURSOR_HIDDEN) return yasl_public_fail(EINVAL); - if(!s->display->ops->surface_set_cursor) return yasl_public_fail(ENOTSUP); - yasl_private_surface_set_cursor(s,(enum yasl_private_cursor)cursor); return true; -} -void yasl_surface_set_refresh_callback(yasl_surface *s,void(*fn)(yasl_surface *,void *),void *ud) -{ if(yasl_public_surface(s,false)) { s->refresh_callback=fn; s->refresh_userdata=ud; } } +void yasl_surface_get_framebuffer_size(const yasl_surface *s, int *w, int *h) +{ + if (s && !yasl_public_surface((yasl_surface *)s, false)) + s = NULL; + if (w) + *w = s ? s->size.x : 0; + if (h) + *h = s ? s->size.y : 0; +} +void yasl_surface_get_size(const yasl_surface *s, int *w, int *h) +{ + if (s && !yasl_public_surface((yasl_surface *)s, false)) + s = NULL; + double scale = scale_of(s); + if (w) + *w = s ? logical(s->size.x, scale) : 0; + if (h) + *h = s ? logical(s->size.y, scale) : 0; +} +double yasl_surface_get_scale(const yasl_surface *s) +{ + return s && yasl_public_surface((yasl_surface *)s, false) ? scale_of(s) : 1.0; +} +unsigned yasl_surface_get_state(const yasl_surface *s) +{ + return s && yasl_public_surface((yasl_surface *)s, false) ? s->state : 0; +} +void *yasl_surface_get_userdata(const yasl_surface *s) +{ + return s && yasl_public_surface((yasl_surface *)s, false) ? s->userdata : NULL; +} +int yasl_surface_set_userdata(yasl_surface *s, void *ud) +{ + if (!yasl_public_surface(s, false)) + return -errno; + s->userdata = ud; + return 0; +} +int yasl_surface_set_title(yasl_surface *s, const char *title) +{ + if (!yasl_public_surface(s, false)) + return -errno; + if (!title) + return yasl_public_error(EINVAL); + if (!s->display->ops->surface_set_title) + return yasl_public_error(ENOTSUP); + s->display->ops->surface_set_title(s, title); + return 0; +} +#define REQUEST(name, priv, args, call) \ + int name args \ + { \ + if (!yasl_public_surface(s, false)) \ + return -errno; \ + errno = 0; \ + return yasl_public_status(priv call || yasl_public_fail(errno)); \ + } +REQUEST(yasl_surface_request_size, yasl_private_surface_set_size, (yasl_surface * s, int w, int h), + (s, ((struct yasl_private_vector2i){w, h}))) +REQUEST(yasl_surface_request_fullscreen, yasl_private_surface_set_fullscreen, + (yasl_surface * s, bool v), (s, v)) +REQUEST(yasl_surface_request_maximized, yasl_private_surface_set_maximized, + (yasl_surface * s, bool v), (s, v)) +REQUEST(yasl_surface_request_minimize, yasl_private_surface_minimize, (yasl_surface * s), (s)) +REQUEST(yasl_surface_set_pointer_mode, yasl_private_surface_set_pointer_mode, + (yasl_surface * s, enum yasl_pointer_mode m), (s, (enum yasl_private_pointer_mode)m)) +int yasl_surface_set_cursor(yasl_surface *s, enum yasl_cursor cursor) +{ + if (!yasl_public_surface(s, false)) + return -errno; + if (cursor < YASL_CURSOR_ARROW || cursor > YASL_CURSOR_HIDDEN) + return yasl_public_error(EINVAL); + if (!s->display->ops->surface_set_cursor) + return yasl_public_error(ENOTSUP); + yasl_private_surface_set_cursor(s, (enum yasl_private_cursor)cursor); + return 0; +} +int yasl_surface_set_refresh_callback(yasl_surface *s, void (*fn)(yasl_surface *, void *), void *ud) +{ + if (!yasl_public_surface(s, false)) + return -errno; + s->refresh_callback = fn; + s->refresh_userdata = ud; + return 0; +} void yasl_private_surface_notify_refresh(yasl_surface *s) { - if(!s || !s->display) return; - struct yasl_private_event ev={.type=YASL_PRIVATE_EVENT_REFRESH,.surface=s}; - yasl_private_events_push(s->display,s,&ev); - if(s->refresh_callback && pumping && !refresh_depth) { - ++refresh_depth; s->refresh_callback(s,s->refresh_userdata); --refresh_depth; + if (!s || !s->display) + return; + struct yasl_private_event ev = {.type = YASL_PRIVATE_EVENT_REFRESH, .surface = s}; + yasl_private_events_push(s->display, s, &ev); + if (s->refresh_callback && pumping && !refresh_depth) { + ++refresh_depth; + s->refresh_callback(s, s->refresh_userdata); + --refresh_depth; } } -static char *copy_text(const char *data,size_t length) +static char *copy_text(const char *data, size_t length) { - if(length==SIZE_MAX || (!data&&length)) { errno=EINVAL; return NULL; } - char *p=malloc(length+1); if(!p) return NULL; - if(length) memcpy(p,data,length); - p[length]=0; return p; + if (length == SIZE_MAX || (!data && length)) { + errno = EINVAL; + return NULL; + } + char *p = malloc(length + 1); + if (!p) + return NULL; + if (length) + memcpy(p, data, length); + p[length] = 0; + return p; } -static const char *deliver_text(const char *data,size_t length) +static const char *deliver_text(const char *data, size_t length) { - free(delivered_text); delivered_text=copy_text(data,length); return delivered_text; + free(delivered_text); + delivered_text = copy_text(data, length); + return delivered_text; } -/* Folds native size, state and focus changes into one WINDOW snapshot; unchanged values report nothing. */ -static bool window_event(yasl_surface *s,struct yasl_private_vector2i size,uint32_t scale_120,uint32_t state,yasl_event *e) +/* Folds native size, state and focus changes into one WINDOW snapshot; unchanged values report + * nothing. */ +static bool window_event(yasl_surface *s, struct yasl_private_vector2i size, uint32_t scale_120, + uint32_t state, yasl_event *e) { - bool resized=size.x!=s->reported_size.x || size.y!=s->reported_size.y || scale_120!=s->reported_scale_120; - if(!resized && state==s->reported_state) return false; - s->reported_size=size; s->reported_scale_120=scale_120; s->reported_state=state; - if(resized) s->refresh_owed=true; - double scale=scale_120 ? scale_120/120.0 : 1.0; - e->type=YASL_EVENT_WINDOW; e->window.pixel_width=size.x; e->window.pixel_height=size.y; e->window.scale=scale; - e->window.width=logical(size.x,scale); e->window.height=logical(size.y,scale); - e->window.state=state; + bool resized = size.x != s->reported_size.x || size.y != s->reported_size.y || + scale_120 != s->reported_scale_120; + if (!resized && state == s->reported_state) + return false; + s->reported_size = size; + s->reported_scale_120 = scale_120; + s->reported_state = state; + if (resized) + s->refresh_owed = true; + double scale = scale_120 ? scale_120 / 120.0 : 1.0; + e->type = YASL_EVENT_WINDOW; + e->window.pixel_width = size.x; + e->window.pixel_height = size.y; + e->window.scale = scale; + e->window.width = logical(size.x, scale); + e->window.height = logical(size.y, scale); + e->window.state = state; return true; } -static bool refresh_ready(yasl_surface *s) { return s->reported_size.x>0 && s->reported_size.y>0; } -static bool convert_event(const struct yasl_private_event *p,yasl_event *e) -{ - *e=(yasl_event){.surface=p->surface,.time_ns=p->time_ns}; - double scale=scale_of(p->surface); - switch(p->type) { - case YASL_PRIVATE_EVENT_WINDOW_CLOSE:e->type=YASL_EVENT_CLOSE;break; - case YASL_PRIVATE_EVENT_DISPLAY_QUIT:e->type=YASL_EVENT_QUIT;break; - case YASL_PRIVATE_EVENT_DISPLAY_REOPEN:e->type=YASL_EVENT_REOPEN;break; - case YASL_PRIVATE_EVENT_DISPLAY_LOST:e->type=YASL_EVENT_DISPLAY_LOST;break; - case YASL_PRIVATE_EVENT_DISPLAY_RESTORED:e->type=YASL_EVENT_DISPLAY_RESTORED;break; +static bool refresh_ready(yasl_surface *s) +{ + return s->reported_size.x > 0 && s->reported_size.y > 0; +} +static bool convert_event(const struct yasl_private_event *p, yasl_event *e) +{ + *e = (yasl_event){.surface = p->surface, .time_ns = p->time_ns}; + double scale = scale_of(p->surface); + switch (p->type) { + case YASL_PRIVATE_EVENT_WINDOW_CLOSE: + e->type = YASL_EVENT_CLOSE; + break; + case YASL_PRIVATE_EVENT_DISPLAY_QUIT: + e->type = YASL_EVENT_QUIT; + break; + case YASL_PRIVATE_EVENT_DISPLAY_REOPEN: + e->type = YASL_EVENT_REOPEN; + break; + case YASL_PRIVATE_EVENT_DISPLAY_LOST: + e->type = YASL_EVENT_DISPLAY_LOST; + break; + case YASL_PRIVATE_EVENT_DISPLAY_RESTORED: + e->type = YASL_EVENT_DISPLAY_RESTORED; + break; case YASL_PRIVATE_EVENT_REFRESH: - if(!p->surface) return false; - if(!refresh_ready(p->surface)) { p->surface->refresh_owed=true; return false; } - p->surface->refresh_owed=false; e->type=YASL_EVENT_REFRESH; break; - case YASL_PRIVATE_EVENT_INPUT_RESET:e->type=YASL_EVENT_INPUT_RESET;break; + if (!p->surface) + return false; + if (!refresh_ready(p->surface)) { + p->surface->refresh_owed = true; + return false; + } + p->surface->refresh_owed = false; + e->type = YASL_EVENT_REFRESH; + break; + case YASL_PRIVATE_EVENT_INPUT_RESET: + e->type = YASL_EVENT_INPUT_RESET; + break; case YASL_PRIVATE_EVENT_FOCUS: { - yasl_surface *s=p->surface; if(!s) return false; - uint32_t state=p->focus.focused ? s->reported_state|YASL_STATE_ACTIVATED : s->reported_state&~(uint32_t)YASL_STATE_ACTIVATED; - return window_event(s,s->reported_size,s->reported_scale_120,state,e); + yasl_surface *s = p->surface; + if (!s) + return false; + uint32_t state = p->focus.focused ? s->reported_state | YASL_STATE_ACTIVATED + : s->reported_state & ~(uint32_t)YASL_STATE_ACTIVATED; + return window_event(s, s->reported_size, s->reported_scale_120, state, e); } case YASL_PRIVATE_EVENT_WINDOW_STATE: - if(!p->surface) return false; - return window_event(p->surface,p->surface->reported_size,p->surface->reported_scale_120,p->state.flags,e); + if (!p->surface) + return false; + return window_event(p->surface, p->surface->reported_size, p->surface->reported_scale_120, + p->state.flags, e); case YASL_PRIVATE_EVENT_WINDOW_RESIZE: - if(!p->surface) return false; - return window_event(p->surface,p->resize.geometry.size,p->resize.geometry.scale_120,p->surface->reported_state,e); + if (!p->surface) + return false; + return window_event(p->surface, p->resize.geometry.size, p->resize.geometry.scale_120, + p->surface->reported_state, e); case YASL_PRIVATE_EVENT_KEY: - e->type=YASL_EVENT_KEY;e->key.key=p->key.key;e->key.action=(enum yasl_key_action)p->key.action; - e->key.mods=p->key.mods;e->key.codepoint=p->key.codepoint;e->key.shifted=p->key.shifted;e->key.native_code=p->key.native_code;break; + e->type = YASL_EVENT_KEY; + e->key.key = p->key.key; + e->key.action = (enum yasl_key_action)p->key.action; + e->key.mods = p->key.mods; + e->key.codepoint = p->key.codepoint; + e->key.shifted = p->key.shifted; + e->key.native_code = p->key.native_code; + break; case YASL_PRIVATE_EVENT_TEXT: - e->type=YASL_EVENT_TEXT;e->text.length=p->text.len;e->text.data=deliver_text(p->text.data,p->text.len);return e->text.data!=NULL; + e->type = YASL_EVENT_TEXT; + e->text.length = p->text.len; + e->text.data = deliver_text(p->text.data, p->text.len); + return e->text.data != NULL; case YASL_PRIVATE_EVENT_DROP: - e->type=YASL_EVENT_DROP;e->drop.action=YASL_DROP_DATA;e->drop.length=p->text.len; - e->drop.data=deliver_text(p->text.data,p->text.len);return e->drop.data!=NULL; + e->type = YASL_EVENT_DROP; + e->drop.action = YASL_DROP_DATA; + e->drop.length = p->text.len; + e->drop.data = deliver_text(p->text.data, p->text.len); + return e->drop.data != NULL; case YASL_PRIVATE_EVENT_PASTE: - e->type=YASL_EVENT_CLIPBOARD;e->clipboard.length=p->paste.len;e->clipboard.request_id=p->paste.request_id; - e->clipboard.status=(enum yasl_transfer_status)p->paste.status; - e->clipboard.data=deliver_text(p->paste.data,p->paste.len);return e->clipboard.data!=NULL; + e->type = YASL_EVENT_CLIPBOARD; + e->clipboard.length = p->paste.len; + e->clipboard.request_id = p->paste.request_id; + e->clipboard.status = (enum yasl_transfer_status)p->paste.status; + e->clipboard.data = deliver_text(p->paste.data, p->paste.len); + return e->clipboard.data != NULL; case YASL_PRIVATE_EVENT_COMPOSITION: - e->type=YASL_EVENT_COMPOSITION;e->composition.length=p->composition.len;e->composition.begin=p->composition.begin; - e->composition.end=p->composition.end;e->composition.active=p->composition.active; - e->composition.revision=p->composition.revision; e->composition.generation=p->composition.generation; - e->composition.data=deliver_text(p->composition.data,p->composition.len);return e->composition.data!=NULL; + e->type = YASL_EVENT_COMPOSITION; + e->composition.length = p->composition.len; + e->composition.begin = p->composition.begin; + e->composition.end = p->composition.end; + e->composition.active = p->composition.active; + e->composition.revision = p->composition.revision; + e->composition.generation = p->composition.generation; + e->composition.data = deliver_text(p->composition.data, p->composition.len); + return e->composition.data != NULL; case YASL_PRIVATE_EVENT_TEXT_EDIT: - e->type=YASL_EVENT_TEXT_EDIT;e->text_edit.length=p->text_edit.len;e->text_edit.begin=p->text_edit.begin;e->text_edit.end=p->text_edit.end; - e->text_edit.revision=p->text_edit.revision;e->text_edit.generation=p->text_edit.generation; - e->text_edit.data=deliver_text(p->text_edit.data,p->text_edit.len);return e->text_edit.data!=NULL; + e->type = YASL_EVENT_TEXT_EDIT; + e->text_edit.length = p->text_edit.len; + e->text_edit.begin = p->text_edit.begin; + e->text_edit.end = p->text_edit.end; + e->text_edit.revision = p->text_edit.revision; + e->text_edit.generation = p->text_edit.generation; + e->text_edit.data = deliver_text(p->text_edit.data, p->text_edit.len); + return e->text_edit.data != NULL; case YASL_PRIVATE_EVENT_PEN: - e->type=YASL_EVENT_PEN; -#define PEN(field) e->pen.field=p->pen.field - PEN(device_id);PEN(tool_id);PEN(x);PEN(y);PEN(pressure);PEN(tilt_x);PEN(tilt_y);PEN(rotation);PEN(distance);PEN(tangential);PEN(wheel_degrees); - PEN(axes_valid);PEN(axes_changed);PEN(buttons);PEN(changed_button);PEN(tool);PEN(action);PEN(in_contact); + e->type = YASL_EVENT_PEN; +#define PEN(field) e->pen.field = p->pen.field + PEN(device_id); + PEN(tool_id); + PEN(x); + PEN(y); + PEN(pressure); + PEN(tilt_x); + PEN(tilt_y); + PEN(rotation); + PEN(distance); + PEN(tangential); + PEN(wheel_degrees); + PEN(axes_valid); + PEN(axes_changed); + PEN(buttons); + PEN(changed_button); + PEN(tool); + PEN(action); + PEN(in_contact); #undef PEN break; case YASL_PRIVATE_EVENT_POINTER_SCROLL: - e->type=YASL_EVENT_SCROLL;e->scroll.x=p->pointer.pos.x/scale;e->scroll.y=p->pointer.pos.y/scale; - e->scroll.lines_x=p->pointer.scroll.x;e->scroll.lines_y=p->pointer.scroll.y; - e->scroll.pixels_x=p->pointer.pixel_scroll.x/scale;e->scroll.pixels_y=p->pointer.pixel_scroll.y/scale; - e->scroll.valid=p->pointer.scroll_valid?p->pointer.scroll_valid:YASL_SCROLL_LINES; - e->scroll.source=p->pointer.scroll_source;e->scroll.phase=p->pointer.scroll_phase;e->scroll.momentum=p->pointer.scroll_momentum;e->scroll.mods=p->pointer.mods;break; - case YASL_PRIVATE_EVENT_POINTER_DOWN:case YASL_PRIVATE_EVENT_POINTER_UP:case YASL_PRIVATE_EVENT_POINTER_MOTION:case YASL_PRIVATE_EVENT_POINTER_LEAVE: - e->type=YASL_EVENT_POINTER;e->pointer.x=(p->pointer.precise_position?p->pointer.precise_x:p->pointer.pos.x)/scale; - e->pointer.y=(p->pointer.precise_position?p->pointer.precise_y:p->pointer.pos.y)/scale; - e->pointer.dx=p->pointer.delta.x/scale;e->pointer.dy=p->pointer.delta.y/scale; - e->pointer.action=p->type==YASL_PRIVATE_EVENT_POINTER_DOWN?YASL_POINTER_DOWN:p->type==YASL_PRIVATE_EVENT_POINTER_UP?YASL_POINTER_UP: - p->type==YASL_PRIVATE_EVENT_POINTER_LEAVE?YASL_POINTER_LEAVE:YASL_POINTER_MOVE; - e->pointer.button=p->pointer.button;e->pointer.buttons=p->pointer.buttons;e->pointer.mods=p->pointer.mods;break; + e->type = YASL_EVENT_SCROLL; + e->scroll.x = p->pointer.pos.x / scale; + e->scroll.y = p->pointer.pos.y / scale; + e->scroll.lines_x = p->pointer.scroll.x; + e->scroll.lines_y = p->pointer.scroll.y; + e->scroll.pixels_x = p->pointer.pixel_scroll.x / scale; + e->scroll.pixels_y = p->pointer.pixel_scroll.y / scale; + e->scroll.valid = p->pointer.scroll_valid ? p->pointer.scroll_valid : YASL_SCROLL_LINES; + e->scroll.source = p->pointer.scroll_source; + e->scroll.phase = p->pointer.scroll_phase; + e->scroll.momentum = p->pointer.scroll_momentum; + e->scroll.mods = p->pointer.mods; + break; + case YASL_PRIVATE_EVENT_POINTER_DOWN: + case YASL_PRIVATE_EVENT_POINTER_UP: + case YASL_PRIVATE_EVENT_POINTER_MOTION: + case YASL_PRIVATE_EVENT_POINTER_LEAVE: + e->type = YASL_EVENT_POINTER; + e->pointer.x = + (p->pointer.precise_position ? p->pointer.precise_x : p->pointer.pos.x) / scale; + e->pointer.y = + (p->pointer.precise_position ? p->pointer.precise_y : p->pointer.pos.y) / scale; + e->pointer.dx = p->pointer.delta.x / scale; + e->pointer.dy = p->pointer.delta.y / scale; + e->pointer.action = p->type == YASL_PRIVATE_EVENT_POINTER_DOWN ? YASL_POINTER_DOWN + : p->type == YASL_PRIVATE_EVENT_POINTER_UP ? YASL_POINTER_UP + : p->type == YASL_PRIVATE_EVENT_POINTER_LEAVE ? YASL_POINTER_LEAVE + : YASL_POINTER_MOVE; + e->pointer.button = p->pointer.button; + e->pointer.buttons = p->pointer.buttons; + e->pointer.mods = p->pointer.mods; + break; case YASL_PRIVATE_EVENT_DRAG: - e->type=YASL_EVENT_DRAG;e->drag.action=(enum yasl_drag_action)p->drag.action; - e->drag.x=p->drag.pos.x/scale;e->drag.y=p->drag.pos.y/scale;break; + e->type = YASL_EVENT_DRAG; + e->drag.action = (enum yasl_drag_action)p->drag.action; + e->drag.x = p->drag.pos.x / scale; + e->drag.y = p->drag.pos.y / scale; + break; case YASL_PRIVATE_EVENT_DROP_HOVER: - e->type=YASL_EVENT_DROP;e->drop.action=p->drop.action==YASL_PRIVATE_DROP_LEAVE?YASL_DROP_LEAVE:YASL_DROP_OVER; - e->drop.x=p->drop.pos.x/scale;e->drop.y=p->drop.pos.y/scale;break; - default:return false; + e->type = YASL_EVENT_DROP; + e->drop.action = + p->drop.action == YASL_PRIVATE_DROP_LEAVE ? YASL_DROP_LEAVE : YASL_DROP_OVER; + e->drop.x = p->drop.pos.x / scale; + e->drop.y = p->drop.pos.y / scale; + break; + default: + return false; } return true; } static int take_event(yasl_event *out) { - for(yasl_surface *s=display->surfaces;s;s=s->event_next) if(s->refresh_owed && refresh_ready(s)) { - s->refresh_owed=false; - *out=(yasl_event){.type=YASL_EVENT_REFRESH,.surface=s,.time_ns=yasl_time_ns()}; - return 1; - } + for (yasl_surface *s = display->surfaces; s; s = s->event_next) + if (s->refresh_owed && refresh_ready(s)) { + s->refresh_owed = false; + *out = + (yasl_event){.type = YASL_EVENT_REFRESH, .surface = s, .time_ns = yasl_time_ns()}; + return 1; + } struct yasl_private_event p; - while(yasl_private_display_poll_event(display,&p)) { - if(p.surface && ((p.type==YASL_PRIVATE_EVENT_COMPOSITION && p.composition.generation!=p.surface->text_generation) || - (p.type==YASL_PRIVATE_EVENT_TEXT_EDIT && p.text_edit.generation!=p.surface->text_generation))) continue; + while (yasl_private_display_poll_event(display, &p)) { + if (p.surface && ((p.type == YASL_PRIVATE_EVENT_COMPOSITION && + p.composition.generation != p.surface->text_generation) || + (p.type == YASL_PRIVATE_EVENT_TEXT_EDIT && + p.text_edit.generation != p.surface->text_generation))) + continue; yasl_event event; - errno=0; - if(convert_event(&p,&event)) { *out=event;return 1; } - if(errno) { yasl_public_fail(errno);return -1; } + errno = 0; + if (convert_event(&p, &event)) { + *out = event; + return 1; + } + if (errno) { + yasl_public_fail(errno); + return -errno; + } } return 0; } -int yasl_wait_event(yasl_event *out,int timeout) +int yasl_wait_event(yasl_event *out, int timeout) { - if(!out) { yasl_public_fail(EINVAL);return -1; } - *out=(yasl_event){.type=YASL_EVENT_NONE}; - if(!yasl_public_owner()) return -1; - if(pumping || refresh_depth) { yasl_public_fail(EBUSY);return -1; } - free(delivered_text); delivered_text=NULL; - int n=take_event(out); if(n) return n; - pumping=true; + if (!out) { + yasl_public_fail(EINVAL); + return -errno; + } + *out = (yasl_event){.type = YASL_EVENT_NONE}; + if (!yasl_public_owner()) + return -errno; + if (pumping || refresh_depth) { + yasl_public_fail(EBUSY); + return -errno; + } + for (yasl_surface *s = display->surfaces; s; s = s->event_next) + s->cpu_acquired = false; + free(delivered_text); + delivered_text = NULL; + int n = take_event(out); + if (n) + return n; + pumping = true; yasl_private_display_flush(display); - n=take_event(out); - if(!n) { - int work=yasl_private_display_dispatch(display,timeout); - if(work<0) { yasl_public_fail(errno);n=-1; } + n = take_event(out); + if (!n) { + int work = yasl_private_display_dispatch(display, timeout); + if (work < 0) { + yasl_public_fail(errno); + n = -errno; + } yasl_private_display_flush(display); - if(n>=0) n=take_event(out); - } - pumping=false;return n; -} -uint32_t *yasl_cpu_pixels(yasl_surface *s,int *w,int *h) -{ - if(w) *w=0; - if(h) *h=0; - if(!yasl_public_surface(s,false)) return NULL; - if(s->presenter!=YASL_PRIVATE_PRESENTER_CPU) { yasl_public_fail(ENOTSUP); return NULL; } - int width=s->size.x,height=s->size.y; - if(width<=0 || height<=0) { yasl_public_fail(EBUSY); return NULL; } - if(width!=s->committed_width || height!=s->committed_height || !s->committed_pixels) { - uint32_t *next=calloc((size_t)width*height,4); - if(!next) { yasl_public_fail(ENOMEM); return NULL; } - int keep_w=width<s->committed_width?width:s->committed_width,keep_h=height<s->committed_height?height:s->committed_height; - if(s->committed_pixels) for(int y=0;y<keep_h;y++) - memcpy(next+(size_t)y*width,s->committed_pixels+(size_t)y*s->committed_width,(size_t)keep_w*4); - free(s->committed_pixels); s->committed_pixels=next; s->committed_width=width; s->committed_height=height; - } - if(w) *w=width; - if(h) *h=height; - return s->committed_pixels; -} -bool yasl_cpu_present(yasl_surface *s) -{ - if(!yasl_public_surface(s,false)) return false; - if(s->presenter!=YASL_PRIVATE_PRESENTER_CPU) return yasl_public_fail(ENOTSUP); - if(!s->committed_pixels || s->committed_width!=s->size.x || s->committed_height!=s->size.y) return yasl_public_fail(EINVAL); - yasl_private_surface_request_frame(s); return true; -} -int yasl_double_click_ms(void) { return display?yasl_private_display_double_click_ms(display):400; } -bool yasl_clipboard_set(enum yasl_selection sel,const char *text) -{ if(!yasl_public_owner())return false;errno=0;return yasl_private_clipboard_set(display,(enum yasl_private_selection)sel,text)||yasl_public_fail(errno); } -uint64_t yasl_clipboard_request(yasl_surface *s,enum yasl_selection sel) -{ if(!yasl_public_surface(s,false))return 0;errno=0;uint64_t id=yasl_private_clipboard_request(s,(enum yasl_private_selection)sel);if(!id)yasl_public_fail(errno);return id; } + if (n >= 0) + n = take_event(out); + } + pumping = false; + return n; +} +static uint64_t cpu_sequence; +int yasl_cpu_acquire(yasl_surface *s, struct yasl_cpu_buffer *out) +{ + if (!out) + return yasl_public_error(EINVAL); + *out = (struct yasl_cpu_buffer){0}; + if (!yasl_public_surface(s, false)) + return -errno; + if (s->presenter != YASL_PRIVATE_PRESENTER_CPU) + return yasl_public_error(ENOTSUP); + if (s->display->offline) + return yasl_public_error(ENOTCONN); + if (s->cpu_acquired) + return yasl_public_error(EBUSY); + int w = s->size.x, h = s->size.y; + if (w <= 0 || h <= 0) + return yasl_public_error(EAGAIN); + if ((size_t)w > SIZE_MAX / sizeof(uint32_t) / (size_t)h) + return yasl_public_error(EOVERFLOW); + if (s->cpu_width != w || s->cpu_height != h || !s->cpu_pixels) { + uint32_t *pixels = malloc((size_t)w * h * sizeof(*pixels)); + if (!pixels) + return yasl_public_error(ENOMEM); + free(s->cpu_pixels); + s->cpu_pixels = pixels; + s->cpu_width = w; + s->cpu_height = h; + } + memset(s->cpu_pixels, 0, (size_t)w * h * sizeof(uint32_t)); + int keep_w = w < s->committed_width ? w : s->committed_width; + int keep_h = h < s->committed_height ? h : s->committed_height; + if (s->committed_pixels) + for (int y = 0; y < keep_h; y++) + memcpy(s->cpu_pixels + (size_t)y * w, + s->committed_pixels + (size_t)y * s->committed_width, + (size_t)keep_w * sizeof(uint32_t)); + if (++cpu_sequence == 0) + ++cpu_sequence; + s->cpu_token = cpu_sequence; + s->cpu_acquired = true; + *out = + (struct yasl_cpu_buffer){s->cpu_pixels, w, h, (size_t)w * sizeof(uint32_t), s->cpu_token}; + return 0; +} +static int cpu_validate(yasl_surface *s, const struct yasl_cpu_buffer *buffer) +{ + if (!yasl_public_surface(s, false)) + return -errno; + if (!buffer) + return yasl_public_error(EINVAL); + if (s->presenter != YASL_PRIVATE_PRESENTER_CPU) + return yasl_public_error(ENOTSUP); + if (!s->cpu_acquired || !buffer->token || buffer->token != s->cpu_token || + s->cpu_width != s->size.x || s->cpu_height != s->size.y) + return yasl_public_error(ESTALE); + if (buffer->pixels != s->cpu_pixels || buffer->width != s->cpu_width || + buffer->height != s->cpu_height || + buffer->stride_bytes != (size_t)s->cpu_width * sizeof(uint32_t)) + return yasl_public_error(EINVAL); + return 0; +} +int yasl_cpu_present(yasl_surface *s, const struct yasl_cpu_buffer *buffer) +{ + int error = cpu_validate(s, buffer); + if (error) + return error; + if (s->display->offline) + return yasl_public_error(ENOTCONN); + size_t bytes = (size_t)s->cpu_width * s->cpu_height * sizeof(uint32_t); + if (s->committed_width != s->cpu_width || s->committed_height != s->cpu_height || + !s->committed_pixels) { + uint32_t *pixels = malloc(bytes); + if (!pixels) + return yasl_public_error(ENOMEM); + free(s->committed_pixels); + s->committed_pixels = pixels; + s->committed_width = s->cpu_width; + s->committed_height = s->cpu_height; + } + memcpy(s->committed_pixels, s->cpu_pixels, bytes); + s->cpu_acquired = false; + yasl_private_surface_request_frame(s); + return 0; +} +int yasl_cpu_discard(yasl_surface *s, const struct yasl_cpu_buffer *buffer) +{ + int error = cpu_validate(s, buffer); + if (error) + return error; + s->cpu_acquired = false; + return 0; +} +int yasl_get_double_click_ms(void) +{ + return display && yasl_public_owner() ? yasl_private_display_double_click_ms(display) : 400; +} +int yasl_clipboard_set(enum yasl_selection sel, const char *text) +{ + if (!yasl_public_owner()) + return -errno; + errno = 0; + return yasl_public_status( + yasl_private_clipboard_set(display, (enum yasl_private_selection)sel, text) || + yasl_public_fail(errno)); +} +uint64_t yasl_clipboard_request(yasl_surface *s, enum yasl_selection sel) +{ + if (!yasl_public_surface(s, false)) + return 0; + errno = 0; + uint64_t id = yasl_private_clipboard_request(s, (enum yasl_private_selection)sel); + if (!id) + yasl_public_fail(errno); + return id; +} static bool text_update(yasl_surface *s) -{ if(!s->display->ops->surface_update_text_input)return true;errno=0;return s->display->ops->surface_update_text_input(s)||yasl_public_fail(errno); } -bool yasl_surface_set_text_input(yasl_surface *s,bool active,enum yasl_text_purpose purpose) { - if(!yasl_public_surface(s,false))return false; - if(purpose<YASL_TEXT_NORMAL||purpose>YASL_TEXT_TERMINAL)return yasl_public_fail(EINVAL); - bool old=s->text_input_active;unsigned old_purpose=s->text_purpose;uint64_t generation=s->text_generation; - if(old!=active || old_purpose!=(unsigned)purpose)++s->text_generation; - s->text_input_active=active;s->text_purpose=purpose; - if(!text_update(s)) { s->text_input_active=old;s->text_purpose=old_purpose;s->text_generation=generation;return false; }return true; + if (!s->display->ops->surface_update_text_input) + return true; + errno = 0; + return s->display->ops->surface_update_text_input(s) || yasl_public_fail(errno); } -bool yasl_surface_set_surrounding_text(yasl_surface *s,const char *text,size_t len,size_t begin,size_t end,uint64_t revision) +int yasl_surface_set_text_input(yasl_surface *s, bool active, enum yasl_text_purpose purpose) { - if(!yasl_public_surface(s,false))return false; - if((!text&&len)||begin>end||end>len||len>INT32_MAX || (len&&memchr(text,0,len)))return yasl_public_fail(EINVAL); + if (!yasl_public_surface(s, false)) + return -errno; + if (purpose < YASL_TEXT_NORMAL || purpose > YASL_TEXT_TERMINAL) + return yasl_public_error(EINVAL); + bool old = s->text_input_active; + unsigned old_purpose = s->text_purpose; + uint64_t generation = s->text_generation; + if (old != active || old_purpose != (unsigned)purpose) + ++s->text_generation; + s->text_input_active = active; + s->text_purpose = purpose; + if (!text_update(s)) { + s->text_input_active = old; + s->text_purpose = old_purpose; + s->text_generation = generation; + return -errno; + } + return 0; +} +int yasl_surface_set_surrounding_text(yasl_surface *s, const char *text, size_t len, size_t begin, + size_t end, uint64_t revision) +{ + if (!yasl_public_surface(s, false)) + return -errno; + if ((!text && len) || begin > end || end > len || len > INT32_MAX || + (len && memchr(text, 0, len))) + return yasl_public_error(EINVAL); /* Validate UTF-8 and require selection boundaries between code points. */ - if((begin<len&&((unsigned char)text[begin]&0xc0)==0x80)||(end<len&&((unsigned char)text[end]&0xc0)==0x80))return yasl_public_fail(EINVAL); - for(size_t i=0;i<len;) { unsigned char c=(unsigned char)text[i];size_t n=c<0x80?1:c>=0xc2&&c<=0xdf?2:c>=0xe0&&c<=0xef?3:c>=0xf0&&c<=0xf4?4:0; - if(!n||i+n>len)return yasl_public_fail(EILSEQ); - for(size_t j=1;j<n;j++)if(((unsigned char)text[i+j]&0xc0)!=0x80)return yasl_public_fail(EILSEQ); - if(n>=3 && ((c==0xe0&&(unsigned char)text[i+1]<0xa0)||(c==0xed&&(unsigned char)text[i+1]>=0xa0)|| - (c==0xf0&&(unsigned char)text[i+1]<0x90)||(c==0xf4&&(unsigned char)text[i+1]>=0x90)))return yasl_public_fail(EILSEQ); - i+=n; + if ((begin < len && ((unsigned char)text[begin] & 0xc0) == 0x80) || + (end < len && ((unsigned char)text[end] & 0xc0) == 0x80)) + return yasl_public_error(EINVAL); + for (size_t i = 0; i < len;) { + unsigned char c = (unsigned char)text[i]; + size_t n = c < 0x80 ? 1 + : c >= 0xc2 && c <= 0xdf ? 2 + : c >= 0xe0 && c <= 0xef ? 3 + : c >= 0xf0 && c <= 0xf4 ? 4 + : 0; + if (!n || i + n > len) + return yasl_public_error(EILSEQ); + for (size_t j = 1; j < n; j++) + if (((unsigned char)text[i + j] & 0xc0) != 0x80) + return yasl_public_error(EILSEQ); + if (n >= 3 && ((c == 0xe0 && (unsigned char)text[i + 1] < 0xa0) || + (c == 0xed && (unsigned char)text[i + 1] >= 0xa0) || + (c == 0xf0 && (unsigned char)text[i + 1] < 0x90) || + (c == 0xf4 && (unsigned char)text[i + 1] >= 0x90))) + return yasl_public_error(EILSEQ); + i += n; + } + char *copy = copy_text(text, len); + if (!copy) + return yasl_public_error(errno); + char *old = s->text_surrounding; + size_t old_len = s->text_length, old_begin = s->text_begin, old_end = s->text_end; + uint64_t old_rev = s->text_revision; + s->text_surrounding = copy; + s->text_length = len; + s->text_begin = begin; + s->text_end = end; + s->text_revision = revision; + if (!text_update(s)) { + free(copy); + s->text_surrounding = old; + s->text_length = old_len; + s->text_begin = old_begin; + s->text_end = old_end; + s->text_revision = old_rev; + return -errno; } - char *copy=copy_text(text,len);if(!copy)return yasl_public_fail(errno); - char *old=s->text_surrounding;size_t old_len=s->text_length,old_begin=s->text_begin,old_end=s->text_end;uint64_t old_rev=s->text_revision; - s->text_surrounding=copy;s->text_length=len;s->text_begin=begin;s->text_end=end;s->text_revision=revision; - if(!text_update(s)){free(copy);s->text_surrounding=old;s->text_length=old_len;s->text_begin=old_begin;s->text_end=old_end;s->text_revision=old_rev;return false;} - free(old);return true; + free(old); + return 0; } -static bool logical_rect(yasl_surface *s,double x,double y,double w,double h,struct yasl_private_rect2i *r) +static bool logical_rect(yasl_surface *s, double x, double y, double w, double h, + struct yasl_private_rect2i *r) { - if(!isfinite(x)||!isfinite(y)||!isfinite(w)||!isfinite(h)||w<0||h<0)return yasl_public_fail(EINVAL); - r->x=yasl_private_scale_to_device(x,s->scale_120);r->y=yasl_private_scale_to_device(y,s->scale_120); - r->width=yasl_private_scale_to_device(w,s->scale_120);r->height=yasl_private_scale_to_device(h,s->scale_120);return true; + if (!isfinite(x) || !isfinite(y) || !isfinite(w) || !isfinite(h) || w < 0 || h < 0) + return yasl_public_fail(EINVAL); + double scale = scale_of(s); + if (fabs(x) * scale > INT_MAX || fabs(y) * scale > INT_MAX || w * scale > INT_MAX || + h * scale > INT_MAX) + return yasl_public_fail(EOVERFLOW); + r->x = yasl_private_scale_to_device(x, s->scale_120); + r->y = yasl_private_scale_to_device(y, s->scale_120); + r->width = yasl_private_scale_to_device(w, s->scale_120); + r->height = yasl_private_scale_to_device(h, s->scale_120); + return true; } -bool yasl_surface_set_ime_caret(yasl_surface *s,double x,double y,double w,double h) +int yasl_surface_set_ime_caret(yasl_surface *s, double x, double y, double w, double h) { - if(!yasl_public_surface(s,false))return false; + if (!yasl_public_surface(s, false)) + return -errno; struct yasl_private_rect2i r; - if(!logical_rect(s,x,y,w,h,&r))return false; - if(!s->display->ops->surface_set_ime_caret)return yasl_public_fail(ENOTSUP); - yasl_private_surface_set_ime_caret(s,r);return true; + if (!logical_rect(s, x, y, w, h, &r)) + return -errno; + if (!s->display->ops->surface_set_ime_caret) + return yasl_public_error(ENOTSUP); + yasl_private_surface_set_ime_caret(s, r); + return 0; } -static bool trigger_valid(yasl_surface *s,const yasl_event *e) +static bool trigger_valid(yasl_surface *s, const yasl_event *e) { - if(!e||e->surface!=s||!e->time_ns||yasl_time_ns()-e->time_ns>5000000000ull || - !((e->type==YASL_EVENT_POINTER&&e->pointer.action==YASL_POINTER_DOWN)||(e->type==YASL_EVENT_PEN&&e->pen.action==YASL_PEN_DOWN))) { - yasl_public_set_error(YASL_ERROR_CONTEXT_EXPIRED,0);return false; - }return true; + if (!e || e->surface != s || !e->time_ns || yasl_time_ns() - e->time_ns > 5000000000ull || + !((e->type == YASL_EVENT_POINTER && e->pointer.action == YASL_POINTER_DOWN) || + (e->type == YASL_EVENT_PEN && e->pen.action == YASL_PEN_DOWN))) { + return yasl_public_fail(ESTALE); + } + return true; } -static bool popup_spec(yasl_surface *s,int w,int h,double x,double y,double aw,double ah,enum yasl_popup_edge anchor,enum yasl_popup_edge gravity,unsigned constraints,struct yasl_private_popup_spec *out) +static bool popup_spec(yasl_surface *s, int w, int h, double x, double y, double aw, double ah, + enum yasl_popup_edge anchor, enum yasl_popup_edge gravity, + unsigned constraints, struct yasl_private_popup_spec *out) { - if(w<=0||h<=0 || (unsigned)anchor>8 || (unsigned)gravity>8 || (constraints&~63u))return yasl_public_fail(EINVAL); - *out=(struct yasl_private_popup_spec){.size={yasl_private_scale_to_device(w,s->scale_120),yasl_private_scale_to_device(h,s->scale_120)},.anchor_edges=anchor,.gravity=gravity,.constraints=constraints}; - return logical_rect(s,x,y,aw,ah,&out->anchor); + if (w <= 0 || h <= 0 || w > 32767 || h > 32767 || (unsigned)anchor > 8 || + (unsigned)gravity > 8 || (constraints & ~63u)) + return yasl_public_fail(EINVAL); + if (w * scale_of(s) > 32767 || h * scale_of(s) > 32767) + return yasl_public_fail(EOVERFLOW); + *out = (struct yasl_private_popup_spec){.size = {yasl_private_scale_to_device(w, s->scale_120), + yasl_private_scale_to_device(h, s->scale_120)}, + .anchor_edges = anchor, + .gravity = gravity, + .constraints = constraints}; + return logical_rect(s, x, y, aw, ah, &out->anchor); } -yasl_surface *yasl_popup_create(yasl_surface *parent,int w,int h,double x,double y,double aw,double ah,enum yasl_popup_edge anchor,enum yasl_popup_edge gravity,unsigned constraints,const yasl_event *trigger) +yasl_surface *yasl_popup_create(yasl_surface *parent, const struct yasl_popup_options *options, + const yasl_event *trigger) { - if(!yasl_public_surface(parent,true)||!trigger_valid(parent,trigger))return NULL; - struct yasl_private_popup_spec spec;if(!popup_spec(parent,w,h,x,y,aw,ah,anchor,gravity,constraints,&spec))return NULL; - yasl_surface *s=yasl_private_surface_create_popup(parent,&spec);if(!s){yasl_public_fail(errno);return NULL;} - yasl_public_register_surface(s,parent->creation_flags,parent);return s; + if (!options) { + yasl_public_fail(EINVAL); + return NULL; + } + int w = options->width, h = options->height; + double x = options->x, y = options->y, aw = options->anchor_width, ah = options->anchor_height; + enum yasl_popup_edge anchor = options->anchor, gravity = options->gravity; + unsigned constraints = options->constraints; + if (!yasl_public_surface(parent, true) || !trigger_valid(parent, trigger)) + return NULL; + struct yasl_private_popup_spec spec; + if (!popup_spec(parent, w, h, x, y, aw, ah, anchor, gravity, constraints, &spec)) + return NULL; + yasl_surface *s = yasl_private_surface_create_popup(parent, &spec); + if (!s) { + yasl_public_fail(errno); + return NULL; + } + yasl_public_register_surface(s, parent->creation_flags, parent); + return s; } -bool yasl_popup_reposition(yasl_surface *s,int w,int h,double x,double y,double aw,double ah,enum yasl_popup_edge anchor,enum yasl_popup_edge gravity,unsigned constraints) +int yasl_popup_reposition(yasl_surface *s, const struct yasl_popup_options *options) { - if(!yasl_public_surface(s,false))return false; + if (!options) + return yasl_public_error(EINVAL); + int w = options->width, h = options->height; + double x = options->x, y = options->y, aw = options->anchor_width, ah = options->anchor_height; + enum yasl_popup_edge anchor = options->anchor, gravity = options->gravity; + unsigned constraints = options->constraints; + if (!yasl_public_surface(s, false)) + return -errno; struct yasl_private_popup_spec spec; - if(!s->parent)return yasl_public_fail(EINVAL); - if(!popup_spec(s->parent,w,h,x,y,aw,ah,anchor,gravity,constraints,&spec))return false; - errno=0;return yasl_private_surface_popup_reposition(s,&spec)||yasl_public_fail(errno); -} -bool yasl_surface_start_interactive_move(yasl_surface *s,const yasl_event *e) -{ if(!yasl_public_surface(s,false)||!trigger_valid(s,e))return false;errno=0;return yasl_private_surface_start_interactive_move(s)||yasl_public_fail(errno); } -bool yasl_surface_start_interactive_resize(yasl_surface *s,enum yasl_resize_edge edge,const yasl_event *e) -{ if(!yasl_public_surface(s,false)||!trigger_valid(s,e))return false;errno=0;return yasl_private_surface_start_interactive_resize(s,(enum yasl_private_resize_edge)edge)||yasl_public_fail(errno); } -bool yasl_surface_show_window_menu(yasl_surface *s,double x,double y,const yasl_event *e) -{ if(!yasl_public_surface(s,false)||!trigger_valid(s,e))return false; - struct yasl_private_rect2i r;if(!logical_rect(s,x,y,0,0,&r))return false;errno=0;return yasl_private_surface_show_window_menu(s,(struct yasl_private_vector2i){r.x,r.y})||yasl_public_fail(errno); } -bool yasl_drag_start(yasl_surface *s,const yasl_event *e,const uint32_t *pixels,int w,int h,int hx,int hy) -{ - if(!yasl_public_surface(s,false)||!trigger_valid(s,e))return false; - struct yasl_private_drag_image image={.pixels=pixels,.size={w,h},.hotspot={hx,hy}}; - errno=0;return yasl_private_display_drag_start(display,s,pixels?&image:NULL,NULL,NULL)||yasl_public_fail(errno); -} -void yasl_drag_cancel(void) { if(yasl_public_owner())yasl_private_display_drag_cancel(display); } -bool yasl_surface_drag_carry(yasl_surface *s,double x,double y) -{ if(!yasl_public_surface(s,false))return false; - struct yasl_private_rect2i r;if(!logical_rect(s,x,y,0,0,&r))return false;errno=0;return yasl_private_surface_drag_carry(s,(struct yasl_private_vector2i){r.x,r.y})||yasl_public_fail(errno); } -bool yasl_surface_place_under_pointer(yasl_surface *s,double x,double y) -{ if(!yasl_public_surface(s,false))return false; - struct yasl_private_rect2i r;if(!logical_rect(s,x,y,0,0,&r))return false;errno=0;return yasl_private_surface_place_under_pointer(s,(struct yasl_private_vector2i){r.x,r.y})||yasl_public_fail(errno); } -size_t yasl_drop_next_path(const char **cursor,char *out,size_t cap) -{ return yasl_private_drop_next_path(cursor,out,cap); } + if (!s->parent) + return yasl_public_error(EINVAL); + if (!popup_spec(s->parent, w, h, x, y, aw, ah, anchor, gravity, constraints, &spec)) + return -errno; + errno = 0; + return yasl_public_status(yasl_private_surface_popup_reposition(s, &spec) || + yasl_public_fail(errno)); +} +int yasl_surface_start_interactive_move(yasl_surface *s, const yasl_event *e) +{ + if (!yasl_public_surface(s, false) || !trigger_valid(s, e)) + return -errno; + errno = 0; + return yasl_public_status(yasl_private_surface_start_interactive_move(s) || + yasl_public_fail(errno)); +} +int yasl_surface_start_interactive_resize(yasl_surface *s, enum yasl_resize_edge edge, + const yasl_event *e) +{ + if (!yasl_public_surface(s, false) || !trigger_valid(s, e)) + return -errno; + errno = 0; + return yasl_public_status( + yasl_private_surface_start_interactive_resize(s, (enum yasl_private_resize_edge)edge) || + yasl_public_fail(errno)); +} +int yasl_surface_show_window_menu(yasl_surface *s, double x, double y, const yasl_event *e) +{ + if (!yasl_public_surface(s, false) || !trigger_valid(s, e)) + return -errno; + struct yasl_private_rect2i r; + if (!logical_rect(s, x, y, 0, 0, &r)) + return -errno; + errno = 0; + return yasl_public_status( + yasl_private_surface_show_window_menu(s, (struct yasl_private_vector2i){r.x, r.y}) || + yasl_public_fail(errno)); +} +int yasl_drag_start(yasl_surface *s, const yasl_event *e, const struct yasl_drag_image *source) +{ + if (!yasl_public_surface(s, false) || !trigger_valid(s, e)) + return -errno; + struct yasl_private_drag_image image = {0}; + if (source) + image = (struct yasl_private_drag_image){.pixels = source->pixels, + .size = {source->width, source->height}, + .hotspot = {source->hotspot_x, source->hotspot_y}}; + errno = 0; + return yasl_public_status( + yasl_private_display_drag_start(display, s, source ? &image : NULL, NULL, NULL) || + yasl_public_fail(errno)); +} +int yasl_drag_cancel(void) +{ + if (!yasl_public_owner()) + return -errno; + yasl_private_display_drag_cancel(display); + return 0; +} +int yasl_surface_drag_carry(yasl_surface *s, double x, double y) +{ + if (!yasl_public_surface(s, false)) + return -errno; + struct yasl_private_rect2i r; + if (!logical_rect(s, x, y, 0, 0, &r)) + return -errno; + errno = 0; + return yasl_public_status( + yasl_private_surface_drag_carry(s, (struct yasl_private_vector2i){r.x, r.y}) || + yasl_public_fail(errno)); +} +int yasl_surface_place_under_pointer(yasl_surface *s, double x, double y) +{ + if (!yasl_public_surface(s, false)) + return -errno; + struct yasl_private_rect2i r; + if (!logical_rect(s, x, y, 0, 0, &r)) + return -errno; + errno = 0; + return yasl_public_status( + yasl_private_surface_place_under_pointer(s, (struct yasl_private_vector2i){r.x, r.y}) || + yasl_public_fail(errno)); +} +size_t yasl_drop_next_path(const char **cursor, char *out, size_t cap) +{ + return yasl_private_drop_next_path(cursor, out, cap); +} -yasl_surface *yasl_gl_surface_create(const char *title,int w,int h,unsigned flags,const int *attrs,yasl_surface *share) -{ - if(!creation_valid(w,h,flags)||(flags&YASL_SURFACE_CPU)) { yasl_public_fail(EINVAL);return NULL; } - struct yasl_private_gl_options parsed;if(!yasl_private_gl_parse_options(attrs,&parsed)){yasl_public_fail(errno);return NULL;} - bool fresh=!display;if(!initialize())return NULL; - if(share && (share->display!=display || share->presenter!=YASL_PRIVATE_PRESENTER_GL)) {yasl_public_fail(EINVAL);return NULL;} - if(!display->ops->surface_create_gl) {if(fresh)yasl_shutdown();yasl_public_fail(ENOTSUP);return NULL;} - struct yasl_private_window_spec spec={.title=title,.size={w,h},.flags=flags,.external_gpu=true}; - yasl_surface *s=display->ops->surface_create_gl(display,&spec,attrs,share); - if(!s){int error=errno;if(fresh)yasl_shutdown();yasl_public_fail(error);return NULL;} - if(!yasl_private_events_register(s)){int error=errno;display->ops->surface_destroy(s);if(fresh)yasl_shutdown();yasl_public_fail(error);return NULL;} - s->presenter=YASL_PRIVATE_PRESENTER_GL;yasl_public_register_surface(s,flags,NULL);return s; -} -bool yasl_gl_make_current(yasl_surface *s) -{ - if(!display){yasl_public_set_error(YASL_ERROR_NOT_INITIALIZED,0);return false;} - if(s && (s->display!=display||s->presenter!=YASL_PRIVATE_PRESENTER_GL))return yasl_public_fail(EINVAL); - if(!display->ops->gl_make_current)return yasl_public_fail(ENOTSUP); - errno=0;return display->ops->gl_make_current(display,s)||yasl_public_fail(errno); +yasl_surface *yasl_gl_surface_create(const struct yasl_surface_options *options, + const struct yasl_gl_options *gl) +{ + if (!options || options->type != YASL_SURFACE_NATIVE || (options->flags & ~14u)) { + yasl_public_fail(EINVAL); + return NULL; + } + const struct yasl_gl_options defaults = YASL_GL_OPTIONS_INIT; + if (!gl) + gl = &defaults; + const int attrs[] = { + YASL_PRIVATE_GL_MAJOR, + gl->major, + YASL_PRIVATE_GL_MINOR, + gl->minor, + YASL_PRIVATE_GL_PROFILE, + gl->profile, + YASL_PRIVATE_GL_API, + gl->api, + YASL_PRIVATE_GL_RED_BITS, + gl->red_bits, + YASL_PRIVATE_GL_GREEN_BITS, + gl->green_bits, + YASL_PRIVATE_GL_BLUE_BITS, + gl->blue_bits, + YASL_PRIVATE_GL_ALPHA_BITS, + gl->alpha_bits, + YASL_PRIVATE_GL_DEPTH_BITS, + gl->depth_bits, + YASL_PRIVATE_GL_STENCIL_BITS, + gl->stencil_bits, + YASL_PRIVATE_GL_SAMPLES, + gl->samples, + YASL_PRIVATE_GL_DEBUG, + gl->debug, + YASL_PRIVATE_GL_FORWARD_COMPAT, + gl->forward_compat, + YASL_PRIVATE_GL_SRGB, + gl->srgb, + YASL_PRIVATE_GL_END, + }; + const char *title = options->title; + int w = options->width, h = options->height; + unsigned flags = options->flags; + yasl_surface *share = gl->share; + if (!creation_valid(w, h, flags)) { + return NULL; + } + struct yasl_private_gl_options parsed; + if (!yasl_private_gl_parse_options(attrs, &parsed)) { + yasl_public_fail(errno); + return NULL; + } + if (share && !display) { + yasl_public_fail(EINVAL); + return NULL; + } + bool fresh = !display; + if (!initialize()) + return NULL; + if (share && (share->display != display || share->presenter != YASL_PRIVATE_PRESENTER_GL)) { + yasl_public_fail(EINVAL); + return NULL; + } + if (!display->ops->surface_create_gl) { + if (fresh) + yasl_shutdown(); + yasl_public_fail(ENOTSUP); + return NULL; + } + struct yasl_private_window_spec spec = { + .title = title, .size = {w, h}, .flags = flags, .external_gpu = true}; + errno = 0; + yasl_surface *s = display->ops->surface_create_gl(display, &spec, attrs, share); + if (!s) { + int error = errno; + if (fresh) + yasl_shutdown(); + yasl_public_fail(error); + return NULL; + } + if (!yasl_private_events_register(s)) { + int error = errno; + display->ops->surface_destroy(s); + if (fresh) + yasl_shutdown(); + yasl_public_fail(error); + return NULL; + } + s->presenter = YASL_PRIVATE_PRESENTER_GL; + yasl_public_register_surface(s, flags, NULL); + s->userdata = options->userdata; + return s; +} +int yasl_gl_make_current(yasl_surface *s) +{ + if (!display) { + return yasl_public_error(ENODEV); + } + if (s && (s->display != display || s->presenter != YASL_PRIVATE_PRESENTER_GL)) + return yasl_public_error(EINVAL); + if (display->offline) + return yasl_public_error(ENOTCONN); + if (!display->ops->gl_make_current) + return yasl_public_error(ENOTSUP); + errno = 0; + return yasl_public_status(display->ops->gl_make_current(display, s) || yasl_public_fail(errno)); } yasl_gl_proc yasl_gl_get_proc_address(const char *name) { - if(!display||!name||!display->ops->gl_get_proc_address){yasl_public_fail(ENOTSUP);return NULL;} - yasl_gl_proc p=display->ops->gl_get_proc_address(display,name);if(!p)yasl_public_fail(ENOENT);return p; + if (!display) { + yasl_public_fail(ENODEV); + return NULL; + } + if (!name || !*name) { + yasl_public_fail(EINVAL); + return NULL; + } + if (display->offline) { + yasl_public_fail(ENOTCONN); + return NULL; + } + if (!display->ops->gl_get_proc_address) { + yasl_public_fail(ENOTSUP); + return NULL; + } + yasl_gl_proc p = display->ops->gl_get_proc_address(display, name); + if (!p) + yasl_public_fail(ENOENT); + return p; } -bool yasl_gl_swap_interval(yasl_surface *s,int interval) +int yasl_gl_set_swap_interval(yasl_surface *s, int interval) { - if(!s||s->presenter!=YASL_PRIVATE_PRESENTER_GL||!s->display->ops->gl_swap_interval)return yasl_public_fail(EINVAL); - errno=0;return s->display->ops->gl_swap_interval(s->display,s,interval)||yasl_public_fail(errno); + if (!display) + return yasl_public_error(ENODEV); + if (display->offline) + return yasl_public_error(ENOTCONN); + if (!s || s->display != display || s->presenter != YASL_PRIVATE_PRESENTER_GL || + !s->display->ops->gl_swap_interval) + return yasl_public_error(EINVAL); + errno = 0; + return yasl_public_status(s->display->ops->gl_swap_interval(s->display, s, interval) || + yasl_public_fail(errno)); } -bool yasl_gl_swap_buffers(yasl_surface *s) +int yasl_gl_present(yasl_surface *s) { - if(!s||s->presenter!=YASL_PRIVATE_PRESENTER_GL||!s->display->ops->gl_swap_buffers)return yasl_public_fail(EINVAL); - errno=0;return s->display->ops->gl_swap_buffers(s->display,s)||yasl_public_fail(errno); + if (!display) + return yasl_public_error(ENODEV); + if (display->offline) + return yasl_public_error(ENOTCONN); + if (!s || s->display != display || s->presenter != YASL_PRIVATE_PRESENTER_GL || + !s->display->ops->gl_swap_buffers) + return yasl_public_error(EINVAL); + errno = 0; + return yasl_public_status(s->display->ops->gl_swap_buffers(s->display, s) || + yasl_public_fail(errno)); } |
