From 7362a612c458a620ccbc1e74caae26cdf6e8b9c8 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 25 Nov 2007 14:11:58 +0000 Subject: [PATCH] * Add cucul_manage_canvas() and cucul_unmanage_canvas(). Display drivers no longer need to access the cv->refcount private member and __cucul_set_canvas_size() is no longer needed. --- caca/caca.c | 23 ++++++++--- caca/caca_internals.h | 1 + caca/driver_cocoa.m | 4 +- caca/driver_conio.c | 7 +++- caca/driver_gl.c | 4 +- caca/driver_ncurses.c | 4 +- caca/driver_raw.c | 4 +- caca/driver_slang.c | 4 +- caca/driver_vga.c | 4 +- caca/driver_win32.c | 8 ++-- caca/driver_x11.c | 4 +- caca/graphics.c | 6 ++- cucul/cucul.c | 90 ++++++++++++++++++++++++++++++++++++----- cucul/cucul.h | 2 + cucul/cucul_internals.h | 7 ++-- msvc/libcucul.def | 4 -- 16 files changed, 139 insertions(+), 37 deletions(-) diff --git a/caca/caca.c b/caca/caca.c index 59b4cf9..f99cd6d 100644 --- a/caca/caca.c +++ b/caca/caca.c @@ -42,6 +42,7 @@ # define x11_install(p) caca_plugin_install("x11", p) #endif +static int caca_can_resize(caca_display_t *); static int caca_select_driver(caca_display_t *); #if defined(USE_PLUGINS) static int caca_plugin_install(char const *, caca_display_t *); @@ -61,7 +62,7 @@ static int caca_plugin_install(char const *, caca_display_t *); * \param cv The cucul cavas. * \return The caca graphical context or NULL if an error occurred. */ -caca_display_t * caca_create_display(cucul_canvas_t * cv) +caca_display_t * caca_create_display(cucul_canvas_t *cv) { caca_display_t *dp = malloc(sizeof(caca_display_t)); @@ -71,6 +72,13 @@ caca_display_t * caca_create_display(cucul_canvas_t * cv) return NULL; } + if(cucul_manage_canvas(cv, (int (*)(void *))caca_can_resize, (void *)dp)) + { + free(dp); + seterrno(EBUSY); + return NULL; + } + dp->cv = cv; #if defined(USE_PLUGINS) dp->plugin = NULL; @@ -82,6 +90,7 @@ caca_display_t * caca_create_display(cucul_canvas_t * cv) if(dp->plugin) dlclose(dp->plugin); #endif + cucul_unmanage_canvas(cv, (int (*)(void *))caca_can_resize, (void *)dp); free(dp); seterrno(ENODEV); return NULL; @@ -93,14 +102,12 @@ caca_display_t * caca_create_display(cucul_canvas_t * cv) if(dp->plugin) dlclose(dp->plugin); #endif + cucul_unmanage_canvas(cv, (int (*)(void *))caca_can_resize, (void *)dp); free(dp); seterrno(ENODEV); return NULL; } - /* Attached! */ - dp->cv->refcount++; - /* Graphics stuff */ dp->delay = 0; dp->rendertime = 0; @@ -127,6 +134,7 @@ caca_display_t * caca_create_display(cucul_canvas_t * cv) /* Resize events */ dp->resize.resized = 0; + dp->resize.allow = 0; return dp; } @@ -149,7 +157,7 @@ int caca_free_display(caca_display_t *dp) if(dp->plugin) dlclose(dp->plugin); #endif - dp->cv->refcount--; + cucul_unmanage_canvas(dp->cv, (int (*)(void *))caca_can_resize, (void *)dp); free(dp); return 0; @@ -159,6 +167,11 @@ int caca_free_display(caca_display_t *dp) * XXX: The following functions are local. */ +static int caca_can_resize(caca_display_t *dp) +{ + return dp->resize.allow; +} + static int caca_select_driver(caca_display_t *dp) { #if defined(HAVE_GETENV) && defined(HAVE_STRCASECMP) diff --git a/caca/caca_internals.h b/caca/caca_internals.h index 31ae339..bf9dbb1 100644 --- a/caca/caca_internals.h +++ b/caca/caca_internals.h @@ -141,6 +141,7 @@ struct caca_display struct resize { int resized; /* A resize event was requested */ + int allow; /* The display driver allows resizing */ unsigned w, h; /* Requested width and height */ } resize; diff --git a/caca/driver_cocoa.m b/caca/driver_cocoa.m index 67d741f..7ac8d27 100644 --- a/caca/driver_cocoa.m +++ b/caca/driver_cocoa.m @@ -834,7 +834,9 @@ static int cocoa_init_graphics(caca_display_t *dp) return -1; unsigned int width = dp->cv->width, height = dp->cv->height; - __cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 0; // first create a full cocoa app if the host has no bundle if(![[NSBundle mainBundle] bundleIdentifier]) diff --git a/caca/driver_conio.c b/caca/driver_conio.c index b32004c..c4d5500 100644 --- a/caca/driver_conio.c +++ b/caca/driver_conio.c @@ -58,8 +58,11 @@ static int conio_init_graphics(caca_display_t *dp) # else /* FIXME */ # endif - __cucul_set_canvas_size(dp->cv, dp->drv.p->ti.screenwidth, - dp->drv.p->ti.screenheight); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, dp->drv.p->ti.screenwidth, + dp->drv.p->ti.screenheight); + dp->resize.allow = 0; + return 0; } diff --git a/caca/driver_gl.c b/caca/driver_gl.c index 5067bd2..71c337c 100644 --- a/caca/driver_gl.c +++ b/caca/driver_gl.c @@ -102,7 +102,9 @@ static int gl_init_graphics(caca_display_t *dp) sscanf(geometry, "%ux%u", &width, &height); #endif - __cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 0; /* Load a libcucul internal font */ fonts = cucul_get_font_list(); diff --git a/caca/driver_ncurses.c b/caca/driver_ncurses.c index dd95c5e..fbf4646 100644 --- a/caca/driver_ncurses.c +++ b/caca/driver_ncurses.c @@ -301,7 +301,9 @@ static int ncurses_init_graphics(caca_display_t *dp) } } - __cucul_set_canvas_size(dp->cv, COLS, LINES); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, COLS, LINES); + dp->resize.allow = 0; return 0; } diff --git a/caca/driver_raw.c b/caca/driver_raw.c index 1d98767..fa49796 100644 --- a/caca/driver_raw.c +++ b/caca/driver_raw.c @@ -40,7 +40,9 @@ static int raw_init_graphics(caca_display_t *dp) sscanf(geometry, "%ux%u", &width, &height); #endif - __cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 24); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 24); + dp->resize.allow = 0; return 0; } diff --git a/caca/driver_slang.c b/caca/driver_slang.c index 6d06528..ac41b71 100644 --- a/caca/driver_slang.c +++ b/caca/driver_slang.c @@ -170,7 +170,9 @@ static int slang_init_graphics(caca_display_t *dp) SLtt_utf8_enable(1); #endif - __cucul_set_canvas_size(dp->cv, SLtt_Screen_Cols, SLtt_Screen_Rows); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, SLtt_Screen_Cols, SLtt_Screen_Rows); + dp->resize.allow = 0; return 0; } diff --git a/caca/driver_vga.c b/caca/driver_vga.c index 656c765..24b174f 100644 --- a/caca/driver_vga.c +++ b/caca/driver_vga.c @@ -76,7 +76,9 @@ static int vga_init_graphics(caca_display_t *dp) outb(tmp, 0x3d5); /* We don't have much choice */ - __cucul_set_canvas_size(dp->cv, 80, 25); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, 80, 25); + dp->resize.allow = 0; return 0; } diff --git a/caca/driver_win32.c b/caca/driver_win32.c index 88f475b..5968313 100644 --- a/caca/driver_win32.c +++ b/caca/driver_win32.c @@ -126,9 +126,11 @@ static int win32_init_graphics(caca_display_t *dp) if(!GetConsoleScreenBufferInfo(dp->drv.p->screen, &csbi)) return -1; - __cucul_set_canvas_size(dp->cv, - csbi.srWindow.Right - csbi.srWindow.Left + 1, - csbi.srWindow.Bottom - csbi.srWindow.Top + 1); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, + csbi.srWindow.Right - csbi.srWindow.Left + 1, + csbi.srWindow.Bottom - csbi.srWindow.Top + 1); + dp->resize.allow = 0; SetConsoleMode(dp->drv.p->screen, 0); diff --git a/caca/driver_x11.c b/caca/driver_x11.c index 867cb0a..5ab7999 100644 --- a/caca/driver_x11.c +++ b/caca/driver_x11.c @@ -88,7 +88,9 @@ static int x11_init_graphics(caca_display_t *dp) sscanf(geometry, "%ux%u", &width, &height); #endif - __cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); + dp->resize.allow = 0; dp->drv.p->dpy = XOpenDisplay(NULL); if(dp->drv.p->dpy == NULL) diff --git a/caca/graphics.c b/caca/graphics.c index 8c09d6d..ad127b2 100644 --- a/caca/graphics.c +++ b/caca/graphics.c @@ -238,7 +238,11 @@ void _caca_handle_resize(caca_display_t *dp) /* Tell libcucul we changed size */ if(dp->resize.w != dp->cv->width || dp->resize.h != dp->cv->height) - __cucul_set_canvas_size(dp->cv, dp->resize.w, dp->resize.h); + { + dp->resize.allow = 1; + cucul_set_canvas_size(dp->cv, dp->resize.w, dp->resize.h); + dp->resize.allow = 0; + } } void _caca_set_term_title(char const *str) diff --git a/cucul/cucul.c b/cucul/cucul.c index 0527f00..5e8965c 100644 --- a/cucul/cucul.c +++ b/cucul/cucul.c @@ -34,6 +34,8 @@ #include "cucul.h" #include "cucul_internals.h" +static int cucul_resize(cucul_canvas_t *, unsigned int, unsigned int); + /** \brief Initialise a \e libcucul canvas. * * Initialise internal \e libcucul structures and the backend that will @@ -60,6 +62,8 @@ cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height) cv->refcount = 0; cv->autoinc = 0; + cv->resize_callback = NULL; + cv->resize_data = NULL; cv->frame = 0; cv->framecount = 1; @@ -81,7 +85,7 @@ cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height) _cucul_load_frame_info(cv); cucul_set_color_ansi(cv, CUCUL_DEFAULT, CUCUL_TRANSPARENT); - if(__cucul_set_canvas_size(cv, width, height) < 0) + if(cucul_resize(cv, width, height) < 0) { int saved_errno = geterrno(); free(cv->frames[0].name); @@ -98,6 +102,70 @@ nomem: return NULL; } +/** \brief Manage a canvas. + * + * Lock a canvas to prevent it from being resized. If non-NULL, + * the \e callback function pointer will be called upon each + * \e cucul_set_canvas_size call and if the returned value is zero, the + * canvas resize request will be denied. + * + * This function is only useful for display drivers such as the \e libcaca + * library. + * + * If an error occurs, -1 is returned and \b errno is set accordingly: + * - \c EBUSY The canvas is already being managed. + * + * \param cv A libcucul canvas. + * \param callback An optional callback function pointer. + * \param p The argument to be passed to \e callback. + * \return 0 in case of success, -1 if an error occurred. + */ +int cucul_manage_canvas(cucul_canvas_t *cv, int (*callback)(void *), void *p) +{ + if(cv->refcount) + { + seterrno(EBUSY); + return -1; + } + + cv->refcount = 1; + + return 0; +} + +/** \brief Unmanage a canvas. + * + * Unlock a canvas previously locked by cucul_manage_canvas(). For safety + * reasons, the callback and callback data arguments must be the same as for + * the cucul_manage_canvas() call. + * + * This function is only useful for display drivers such as the \e libcaca + * library. + * + * If an error occurs, -1 is returned and \b errno is set accordingly: + * - \c EINVAL The canvas is not managed, or the callback arguments do + * not match. + * + * \param cv A libcucul canvas. + * \param callback The \e callback argument previously passed to + cucul_manage_canvas(). + * \param p The \e p argument previously passed to cucul_manage_canvas(). + * \return 0 in case of success, -1 if an error occurred. + */ +int cucul_unmanage_canvas(cucul_canvas_t *cv, int (*callback)(void *), void *p) +{ + if(!cv->refcount + || cv->resize_callback != callback || cv->resize_data != p) + { + seterrno(EINVAL); + return -1; + } + + cv->refcount = 0; + + return 0; +} + /** \brief Resize a canvas. * * Set the canvas' width and height, in character cells. @@ -123,21 +191,22 @@ nomem: * - \c ENOMEM Not enough memory for the requested canvas size. If this * happens, the canvas handle becomes invalid and should not be used. * - * \param cv A libcucul canvas - * \param width The desired canvas width - * \param height The desired canvas height + * \param cv A libcucul canvas. + * \param width The desired canvas width. + * \param height The desired canvas height. * \return 0 in case of success, -1 if an error occurred. */ int cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width, unsigned int height) { - if(cv->refcount) + if(cv->refcount && cv->resize_callback + && !cv->resize_callback(cv->resize_data)) { seterrno(EBUSY); return -1; } - return __cucul_set_canvas_size(cv, width, height); + return cucul_resize(cv, width, height); } /** \brief Get the canvas width. @@ -146,7 +215,7 @@ int cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width, * * This function never fails. * - * \param cv A libcucul canvas + * \param cv A libcucul canvas. * \return The canvas width. */ unsigned int cucul_get_canvas_width(cucul_canvas_t const *cv) @@ -160,7 +229,7 @@ unsigned int cucul_get_canvas_width(cucul_canvas_t const *cv) * * This function never fails. * - * \param cv A libcucul canvas + * \param cv A libcucul canvas. * \return The canvas height. */ unsigned int cucul_get_canvas_height(cucul_canvas_t const *cv) @@ -177,7 +246,7 @@ unsigned int cucul_get_canvas_height(cucul_canvas_t const *cv) * If an error occurs, -1 is returned and \b errno is set accordingly: * - \c EBUSY The canvas is in use by a display driver and cannot be freed. * - * \param cv A libcucul canvas + * \param cv A libcucul canvas. * \return 0 in case of success, -1 if an error occurred. */ int cucul_free_canvas(cucul_canvas_t *cv) @@ -231,8 +300,7 @@ int cucul_rand(int min, int max) * XXX: The following functions are local. */ -int __cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width, - unsigned int height) +int cucul_resize(cucul_canvas_t *cv, unsigned int width, unsigned int height) { unsigned int x, y, f, old_width, old_height, new_size, old_size; diff --git a/cucul/cucul.h b/cucul/cucul.h index bd2e5f5..659fd66 100644 --- a/cucul/cucul.h +++ b/cucul/cucul.h @@ -84,6 +84,8 @@ typedef struct cucul_font cucul_font_t; * * @{ */ __extern cucul_canvas_t * cucul_create_canvas(unsigned int, unsigned int); +__extern int cucul_manage_canvas(cucul_canvas_t *, int (*)(void *), void *); +__extern int cucul_unmanage_canvas(cucul_canvas_t *, int (*)(void *), void *); __extern int cucul_set_canvas_size(cucul_canvas_t *, unsigned int, unsigned int); __extern unsigned int cucul_get_canvas_width(cucul_canvas_t const *); diff --git a/cucul/cucul_internals.h b/cucul/cucul_internals.h index 5a5ab57..252d3bf 100644 --- a/cucul/cucul_internals.h +++ b/cucul/cucul_internals.h @@ -43,8 +43,11 @@ struct cucul_canvas unsigned int frame, framecount; struct cucul_frame *frames; + /* Canvas management */ unsigned int refcount; unsigned int autoinc; + int (*resize_callback)(void *); + void *resize_data; /* Shortcut to the active frame information */ unsigned int width, height; @@ -60,10 +63,6 @@ struct cucul_buffer int user_data; }; -/* Canvas functions */ -extern int __cucul_set_canvas_size(cucul_canvas_t *, - unsigned int, unsigned int); - /* Colour functions */ extern uint16_t _cucul_attr_to_rgb12fg(uint32_t); extern uint16_t _cucul_attr_to_rgb12bg(uint32_t); diff --git a/msvc/libcucul.def b/msvc/libcucul.def index cb414e0..e69de29 100644 --- a/msvc/libcucul.def +++ b/msvc/libcucul.def @@ -1,4 +0,0 @@ -LIBRARY "libcucul" - -EXPORTS - __cucul_set_canvas_size ; Private symbol used by libcaca