This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via 910d31f9711c5e518189c5e5f47761125ef06207 (commit) via 6812b812594d07e3a6b7543400e710424ce23597 (commit) from 89909d1774eb1b3ac35e2e643401bab3b79c9dc2 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/910d31f9711c5e518189c5e5f47761125ef06...
commit 910d31f9711c5e518189c5e5f47761125ef06207 Author: Cyril Hrubis metan@ucw.cz Date: Tue Dec 18 13:55:12 2012 +0100
doc: input: Add input events docs + code cleanup.
diff --git a/build/syms/Event_symbols.txt b/build/syms/Event_symbols.txt index 9f80506..6dc7e12 100644 --- a/build/syms/Event_symbols.txt +++ b/build/syms/Event_symbols.txt @@ -9,7 +9,7 @@ GP_EventDump GP_EventPushResize GP_EventPushRelTo GP_EventSetScreenCursor -GP_EventQueued +GP_EventsQueued
GP_InputDriverLinuxRead GP_InputDriverSDLEventPut diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile index e64dda7..cce46d8 100644 --- a/demos/c_simple/Makefile +++ b/demos/c_simple/Makefile @@ -16,9 +16,9 @@ LDLIBS+=-lrt `$(TOPDIR)/gfxprim-config --libs --libs-backends`
APPS=backend_example loaders_example loaders filters_symmetry gfx_koch virtual_backend_example meta_data meta_data_dump tmp_file showimage- v4l2_show v4l2_grab convolution weighted_median shapetest koch input- fileview linetest randomshapetest fonttest loaders_register blittest- textaligntest + v4l2_show v4l2_grab convolution weighted_median shapetest koch + input_example fileview linetest randomshapetest fonttest+ loaders_register blittest textaligntest
ifeq ($(HAVE_LIBSDL),yes) APPS+=SDL_glue diff --git a/demos/c_simple/input.c b/demos/c_simple/input_example.c similarity index 98% rename from demos/c_simple/input.c rename to demos/c_simple/input_example.c index 6a083e2..38cc1e3 100644 --- a/demos/c_simple/input.c +++ b/demos/c_simple/input_example.c @@ -56,7 +56,7 @@ static void event_loop(void) for (;;) { GP_BackendWait(backend); - while (GP_EventQueued()) { + while (GP_EventsQueued()) { GP_Event ev;
GP_EventGet(&ev); @@ -128,8 +128,6 @@ int main(int argc, char *argv[]) } }
-// GP_SetDebugLevel(10); - backend = GP_BackendInit(backend_opts, "Input Test", stderr);
if (backend == NULL) { diff --git a/doc/Makefile b/doc/Makefile index 4160ae0..f72b8c3 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,6 +1,6 @@ SOURCES=general.txt context.txt loaders.txt filters.txt basic_types.txt drawing_api.txt backends.txt gamma.txt grabbers.txt - environment_variables.txt debug.txt core.txt api.txt + environment_variables.txt debug.txt core.txt api.txt input.txt
EXAMPLE_SOURCES=$(wildcard example_*.txt)
diff --git a/doc/api.txt b/doc/api.txt index aff68ea..cee4d1a 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -49,6 +49,11 @@ Cyril Hrubis metan@ucw.cz + Backends API for drawing on the screen or into a window. + +. link:input.html[Input Events] + + + Input event handling such as key presses, mouse coordinates, touchscreens + and window manager events such as window close or window resize. + + . link:grabbers.html[Grabbers] + Video grabbers interface such as V4L2. diff --git a/doc/backends.txt b/doc/backends.txt index 86d5d51..d760daf 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -274,3 +274,20 @@ returned. If backend size already matches w and h, nothing is done. Note that backend->context pointer may change upon calling this function and at least backend->context->pixels pointer will change.
+[source,c] +------------------------------------------------------------------------------- +#include <backends/GP_Backend.h> +/* or */ +#include <GP.h> + +int GP_BackendResizeAck(GP_Backend *self); +------------------------------------------------------------------------------- + +If backend is resizeable by user interaction (for example X Window) you will +get resize event for each change of window size, however the backend context +will not be resized untill you call this function. This is usefull in +multithreaded application where one threads waits for events and others draws +into the buffer so you can stop the drawing threads before the backend context +size change. + +See input link:input.html[input events] for more information. diff --git a/doc/example_input.txt b/doc/example_input.txt new file mode 100644 index 0000000..15b7233 --- /dev/null +++ b/doc/example_input.txt @@ -0,0 +1,7 @@ +Input Events Example +-------------------- + +[source,c] +------------------------------------------------------------------ +include::../demos/c_simple/input_example.c[] +------------------------------------------------------------------ diff --git a/doc/input.txt b/doc/input.txt new file mode 100644 index 0000000..44da370 --- /dev/null +++ b/doc/input.txt @@ -0,0 +1,271 @@ +Input Events +------------ + +Input events are somehow tied to the link:backends.html[backends]. Possibly in +contrast with other libraries there is not always 1:1 correspondence between +input driver and backend graphics driver. That means that you can, for +example, use linux input events together with X Window without any problems. +You can even write application that doesn't draw any graphics at all and still +use some of the input drivers. There are, of course, cases where input driver +is created only together with graphics driver, this is the case for example +for X Window backends or SDL backends. + +The basic structure is roughly modeled after Linux kernel input API. The main +difference is that events that belongs together are delivered together. For +example mouse coordinates are bundled in one event. + +For example usage see backend link:example_input.html[example]. + +Event Structure Description +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +typedef struct GP_Event { + /* event */ + uint16_t type; + uint32_t code; + union GP_EventValue val; + + /* input device id */ + uint32_t dev_id; + + /* event timestamp */ + struct timeval time; + + /* + * Cursor possition, possition on screen accumulated + * from all pointer devices + */ + uint32_t cursor_x; + uint32_t cursor_y; + + /* + * Bitmap of pressed keys including mouse buttons + * accumulated for all input devices. + */ + uint8_t keys_pressed[GP_EVENT_KEYMAP_BYTES]; +} GP_Event; +------------------------------------------------------------------------------- + +The GP_Event structure is basic block that describes input event (i.e. key was +pressed/released, mouse was moved, window was resized by user). + +[source,c] +------------------------------------------------------------------------------- +enum GP_EventType { + GP_EV_KEY, /* key/button press event */ + GP_EV_REL, /* relative event */ + GP_EV_ABS, /* absolute event */ + GP_EV_SYS, /* system events window close, resize... */ + GP_EV_MAX = GP_EV_SYS, /* maximum, greater values are free */ +}; +------------------------------------------------------------------------------- + +The event 'type' determines highlevel nature of the event. + +* Key events covers keyboard button presses, mouse buttons, etc. +* Relative events covers mostly mouse coordinates +* Absolute events covers touchscreens and tablets +* System events are used mostly for propagating window close and window + resize events +* Values greater than 'GP_EV_MAX' are free for user events + +[source,c] +------------------------------------------------------------------------------- +enum GP_EventKeyCode { + GP_EV_KEY_UP, + GP_EV_KEY_DOWN, + GP_EV_KEY_REPEAT, +}; + +enum GP_EventRelCode { + GP_EV_REL_POS, + GP_EV_REL_WHEEL, +}; + +enum GP_EventAbsCode { + GP_EV_ABS_POS, +}; + +enum GP_EventSysCode { + GP_EV_SYS_QUIT, + GP_EV_SYS_RESIZE, +}; +------------------------------------------------------------------------------- + +The event 'code' specifies the event nature more closely, it has different +meaning for each event type. The names are (hopefully) self explanatory. + +[source,c] +------------------------------------------------------------------------------- +union GP_EventValue { + /* generic one integer value */ + int32_t val; + /* key */ + struct GP_EventKey key; + /* position */ + struct GP_EventPosRel rel; + struct GP_EventPosAbs abs; + /* system event */ + struct GP_EventSys sys; +}; + +struct GP_EventPosRel { + int32_t rx; + int32_t ry; +}; + +struct GP_EventPosAbs { + uint32_t x, x_max; /* the x is between 0 and x_max */ + uint32_t y, y_max; + uint32_t pressure, pressure_max; +}; + +struct GP_EventKey { + uint32_t key; + char ascii; +}; + +struct GP_EventSys { + uint32_t w, h; +}; +------------------------------------------------------------------------------- + +The event value is a union that could hold different information. The right +format of the data is known from the 'type' and 'code'. For some types of the +events it's not used at all. + +* The relative coordinates are used for 'GP_EV_REL_POS' and absolute coordinates + for 'GP_EV_ABS_POS'. + +* The key event value is used for keypresses, additionally it holds the key + value mapped to ASCII if conversion is applicable otherwise it's set to + zero. You should consult the header 'input/GP_Event.h' for comprehensive + list of key values. + +* And finally the system event is used with 'GP_EV_SYS_RESIZE' and informs you + of the new window size. + +The 'dev_id' is not used at the moment and may be removed. + +The timeval structure 'time' holds time when the event was created (or +received by GFXprim input driver). + +The 'cursor_x' and 'cursor_y' holds pointer coodinates merged from all input +sources. + +The 'key_pressed' is bitflag array of currently pressed keys which is useful +for using keys as modificators. The array holds most of the standard keyboard +keys and mouse buttons. + +Event API +~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +unsigned int GP_EventsQueued(void); +------------------------------------------------------------------------------- + +The 'GP_EventsQueued' returns number of queued events. + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +int GP_EventGet(struct GP_Event *ev); +------------------------------------------------------------------------------- + +The 'GP_EventGet' returns nonzero if event was copied to the structure pointed +by ev pointer. + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +void GP_EventDump(struct GP_Event *ev); +------------------------------------------------------------------------------- + +Dumps event in human-readable format into the 'stdout'. + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +void GP_EventSetScreenSize(uint32_t w, uint32_t h); + +void GP_EventSetScreenCursor(uint32_t x, uint32_t y); +------------------------------------------------------------------------------- + +Sets screen size and pointer position, which is needed for calculating the +'cursor_x' and 'cursor_y' coordinates. + +void GP_EventPushRel(int32_t rx, int32_t ry, struct timeval *time); + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +/* + * Produces relative event that moves to the point x, y + */ +void GP_EventPushRelTo(uint32_t x, uint32_t y, struct timeval *time); + +/* + * Inject absolute event. + */ +void GP_EventPushAbs(uint32_t x, uint32_t y, uint32_t pressure, + uint32_t x_max, uint32_t y_max, uint32_t pressure_max, + struct timeval *time); + +/* + * Inject event that changes key state. + */ +void GP_EventPushKey(uint32_t key, uint8_t code, struct timeval *time); + +/* + * Inject common event. + */ +void GP_EventPush(uint16_t type, uint32_t code, int32_t value, + struct timeval *time); +------------------------------------------------------------------------------- + +Following functions are used for adding events into the event queue. If +pointer to the timeval structure is 'NULL' the event 'time' will be filled +with exact time the event was added to the queue. + +[source,c] +------------------------------------------------------------------------------- +#include <GP.h> +/* or */ +#include <input/GP_Event.h> + +void GP_EventSetKey(struct GP_Event *ev, uint32_t key) + +GP_EventGetKey(struct GP_Event *ev, uint32_t key) + +GP_EventResetKey(struct GP_Event *ev, uint32_t key) +------------------------------------------------------------------------------- + +These functions are helpers for setting/getting key pressed bits in the +'keys_pressed' bit array. + +You will mostly need the 'GP_EventGetKey' function to figure out if some of +the modificator keys (such as Ctrl or Shift) was pressed at the time the event +was received. diff --git a/include/input/GP_Event.h b/include/input/GP_Event.h index 71eef60..de5d93e 100644 --- a/include/input/GP_Event.h +++ b/include/input/GP_Event.h @@ -299,7 +299,7 @@ void GP_EventSetScreenCursor(uint32_t x, uint32_t y); /* * Returns number of queued events. */ -uint32_t GP_EventQueued(void); +unsigned int GP_EventsQueued(void);
/* * Dump event into stdout. diff --git a/libs/input/GP_Event.c b/libs/input/GP_Event.c index eab6b2e..cb66c4f 100644 --- a/libs/input/GP_Event.c +++ b/libs/input/GP_Event.c @@ -89,7 +89,7 @@ void GP_EventSetScreenCursor(uint32_t x, uint32_t y) cur_state.cursor_y = y; }
-uint32_t GP_EventQueued(void) +unsigned int GP_EventsQueued(void) { if (queue_first <= queue_last) return queue_last - queue_first;
http://repo.or.cz/w/gfxprim.git/commit/6812b812594d07e3a6b7543400e710424ce23...
commit 6812b812594d07e3a6b7543400e710424ce23597 Author: Cyril Hrubis metan@ucw.cz Date: Tue Dec 18 11:49:01 2012 +0100
backends: Add GP_BackendResizeAck().
This is not yet finished but seems to work fine. More testing is required.
diff --git a/build/syms/Backend_symbols.txt b/build/syms/Backend_symbols.txt index 7eddbe5..abcd681 100644 --- a/build/syms/Backend_symbols.txt +++ b/build/syms/Backend_symbols.txt @@ -7,4 +7,5 @@ GP_BackendSDLInit GP_ContextFromSurface
GP_BackendResize +GP_BackendResizeAck GP_BackendUpdateRectXYXY diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c index abe7395..79de755 100644 --- a/demos/spiv/spiv.c +++ b/demos/spiv/spiv.c @@ -350,24 +350,6 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size return img; }
-/* - * This function tries to resize spiv window - * and if succedes blits the image directly to the screen. - */ -static int resize_backend_and_blit(struct loader_params *params) -{ - GP_Context *img = load_image(params, 1); - - if (GP_BackendResize(backend, img->w, img->h)) - return 1; - - GP_Blit_Raw(img, 0, 0, img->w, img->h, backend->context, 0, 0); - GP_BackendFlip(backend); - set_caption(params->img_path, 1); - - return 0; -} - static void *image_loader(void *ptr) { struct loader_params *params = ptr; @@ -565,6 +547,23 @@ static void init_caches(struct loader_params *params) // params->img_orig_cache = NULL; }
+/* + * Ask backend to resize window. Once window is resized we will + * get SYS_RESIZE event, see the main event loop. + */ +static void resize_backend(struct loader_params *params, float ratio, int shift_flag) +{ + GP_Context *img = load_image(params, 1); + + if (!shift_flag) + ratio = 1.00 / ratio; + + unsigned int w = img->w * ratio + 0.5; + unsigned int h = img->h * ratio + 0.5; + + GP_BackendResize(backend, w, h); +} + static void print_help(void) { printf("Usage: spiv [opts] imagesnn"); @@ -601,6 +600,15 @@ static void print_help(void) printf("Downn"); printf("BckSpc - move to the prev imagen"); printf("n"); + printf("1 - resize spiv window to the image sizen"); + printf("2 - resize spiv window to the half of the image sizen"); + printf("3 - resize spiv window to the third of the image sizen"); + printf("...n"); + printf("9 - resize spiv window to the ninth of the image sizen"); + printf("n"); + printf("Shift 2 - resize spiv window twice of the image sizen"); + printf("Shift 3 - resize spiv window three times of the image sizen"); + printf("...nn");
printf("Some cool options to try:nn"); printf("spiv -e G1 -f imagesn"); @@ -618,6 +626,7 @@ int main(int argc, char *argv[]) const char *backend_opts = "X11"; int sleep_sec = -1; int opt, debug_level = 0; + int shift_flag; GP_PixelType emul_type = GP_PIXEL_UNKNOWN; struct loader_params params = { @@ -734,7 +743,10 @@ int main(int argc, char *argv[]) while (GP_EventGet(&ev)) {
GP_EventDump(&ev); - + + shift_flag = GP_EventGetKey(&ev, GP_KEY_LEFT_SHIFT) || + GP_EventGetKey(&ev, GP_KEY_RIGHT_SHIFT); + switch (ev.type) { case GP_EV_REL: switch (ev.code) { @@ -863,7 +875,31 @@ int main(int argc, char *argv[]) show_image(¶ms, argv[argn]); break; case GP_KEY_1: - resize_backend_and_blit(¶ms); + resize_backend(¶ms, 1, shift_flag); + break; + case GP_KEY_2: + resize_backend(¶ms, 2, shift_flag); + break; + case GP_KEY_3: + resize_backend(¶ms, 3, shift_flag); + break; + case GP_KEY_4: + resize_backend(¶ms, 4, shift_flag); + break; + case GP_KEY_5: + resize_backend(¶ms, 5, shift_flag); + break; + case GP_KEY_6: + resize_backend(¶ms, 6, shift_flag); + break; + case GP_KEY_7: + resize_backend(¶ms, 7, shift_flag); + break; + case GP_KEY_8: + resize_backend(¶ms, 8, shift_flag); + break; + case GP_KEY_9: + resize_backend(¶ms, 9, shift_flag); break; } break; @@ -872,7 +908,7 @@ int main(int argc, char *argv[]) case GP_EV_SYS_RESIZE: /* stop loader thread before resizing backend buffer */ stop_loader(); - GP_BackendResize(backend, ev.val.sys.w, ev.val.sys.h); + GP_BackendResizeAck(backend); GP_Fill(backend->context, 0); params.show_progress_once = 1; show_image(¶ms, NULL); diff --git a/include/backends/GP_Backend.h b/include/backends/GP_Backend.h index 64b504d..01bf3c1 100644 --- a/include/backends/GP_Backend.h +++ b/include/backends/GP_Backend.h @@ -95,6 +95,13 @@ typedef struct GP_Backend { const char *caption);
/* + * Resize acknowledge callback. This must be called + * after you got resize event in order to resize + * backend buffers. + */ + int (*ResizeAck)(struct GP_Backend *self); + + /* * Exits the backend. */ void (*Exit)(struct GP_Backend *self); @@ -207,4 +214,18 @@ static inline int GP_BackendSetCaption(GP_Backend *backend, */ int GP_BackendResize(GP_Backend *backend, uint32_t w, uint32_t h);
+ +/* + * Resize acknowledge. You must call this right after you application has + * received resize event. + * + * This will resize backend buffers. After this call returns the backend width + * height and context pointer are most likely different. + * + * This function returns zero on succes. Non zero on failure. If it fails the + * best action to take is to save application data and exit (as the backend + * may be in undefined state). + */ +int GP_BackendResizeAck(GP_Backend *self); + #endif /* BACKENDS_GP_BACKEND_H */ diff --git a/libs/backends/GP_Backend.c b/libs/backends/GP_Backend.c index b81808e..6839187 100644 --- a/libs/backends/GP_Backend.c +++ b/libs/backends/GP_Backend.c @@ -83,3 +83,13 @@ int GP_BackendResize(GP_Backend *backend, uint32_t w, uint32_t h)
return backend->SetAttributes(backend, w, h, NULL); } + +int GP_BackendResizeAck(GP_Backend *self) +{ + GP_DEBUG(2, "Calling backend %s ResizeAck()", self->name); + + if (self->ResizeAck) + return self->ResizeAck(self); + + return 0; +} diff --git a/libs/backends/GP_LinuxFB.c b/libs/backends/GP_LinuxFB.c index 6d69ce4..e819ae5 100644 --- a/libs/backends/GP_LinuxFB.c +++ b/libs/backends/GP_LinuxFB.c @@ -324,6 +324,7 @@ GP_Backend *GP_BackendLinuxFBInit(const char *path, int flag) backend->UpdateRect = fb_update_rect_noop; backend->Exit = fb_exit; backend->SetAttributes = NULL; + backend->ResizeAck = NULL; backend->Poll = flag ? fb_poll : NULL; backend->Wait = flag ? fb_wait : NULL; backend->fd = fb->con_fd; diff --git a/libs/backends/GP_SDL.c b/libs/backends/GP_SDL.c index 0faff30..d3afcca 100644 --- a/libs/backends/GP_SDL.c +++ b/libs/backends/GP_SDL.c @@ -164,6 +164,7 @@ static struct GP_Backend backend = { .Flip = sdl_flip, .UpdateRect = sdl_update_rect, .SetAttributes = sdl_set_attributes, + .ResizeAck = NULL, .Exit = sdl_exit, .fd = -1, .Poll = sdl_poll, diff --git a/libs/backends/GP_X11.c b/libs/backends/GP_X11.c index afe38fd..e543d48 100644 --- a/libs/backends/GP_X11.c +++ b/libs/backends/GP_X11.c @@ -45,6 +45,7 @@ #include "GP_X11.h"
struct x11_priv { + /* Connection details */ Display *dpy; int scr; Screen *scr_ptr; @@ -52,6 +53,7 @@ struct x11_priv { Window win; Visual *vis;
+ /* Image details */ XImage *img;
#ifdef HAVE_X_SHM @@ -61,31 +63,27 @@ struct x11_priv {
int resized_flag:1; int shm_flag:1; -};
-static void destroy_ximage(GP_Backend *self); -static void destroy_shm_ximage(GP_Backend *self); + /* used to store width and height from ConfigureNotify event */ + unsigned int new_w; + unsigned int new_h; +};
static int resize_ximage(GP_Backend *self, int w, int h); static int resize_shm_ximage(GP_Backend *self, int w, int h);
-static void x11_exit(GP_Backend *self) +static void putimage(struct GP_Backend *self, int x0, int y0, int x1, int y1) { struct x11_priv *x11 = GP_BACKEND_PRIV(self); - - XLockDisplay(x11->dpy);
+#ifdef HAVE_X_SHM if (x11->shm_flag) - destroy_shm_ximage(self); + XShmPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), + x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1, False); else - destroy_ximage(self); - - XDestroyWindow(x11->dpy, x11->win); - /* I wonder if this is right sequence... */ - XUnlockDisplay(x11->dpy); - XCloseDisplay(x11->dpy); - - free(self); +#endif /* HAVE_X_SHM */ + XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), + x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1); }
static void x11_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0, @@ -94,19 +92,15 @@ static void x11_update_rect(GP_Backend *self, GP_Coord x0, GP_Coord y0, struct x11_priv *x11 = GP_BACKEND_PRIV(self); GP_DEBUG(4, "Updating rect %ix%i-%ix%i", x0, y0, x1, y1); - + + if (x11->resized_flag) { + GP_DEBUG(4, "Ignoring update rect, waiting for resize ack"); + return; + } + XLockDisplay(x11->dpy);
-#ifdef HAVE_X_SHM - if (x11->shm_flag) - XShmPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), - x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1, False); - else -#endif /* HAVE_X_SHM */ - XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), - x11->img, x0, y0, x0, y0, x1-x0+1, y1-y0+1); - - XFlush(x11->dpy); + putimage(self, x0, y0, x1, y1);
XUnlockDisplay(x11->dpy); } @@ -118,12 +112,22 @@ static void x11_flip(GP_Backend *self) unsigned int h = self->context->h;
GP_DEBUG(4, "Flipping context"); - + + if (x11->resized_flag) { + GP_DEBUG(4, "Ignoring flip, waiting for resize ack"); + return; + } + XLockDisplay(x11->dpy);
- XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), - x11->img, 0, 0, 0, 0, w, h); - XFlush(x11->dpy); +#ifdef HAVE_X_SHM + if (x11->shm_flag) + XShmPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), + x11->img, 0, 0, 0, 0, w, h, False); + else +#endif /* HAVE_X_SHM */ + XPutImage(x11->dpy, x11->win, DefaultGC(x11->dpy, x11->scr), + x11->img, 0, 0, 0, 0, w, h); XUnlockDisplay(x11->dpy); } @@ -138,14 +142,22 @@ static void x11_ev(GP_Backend *self, XEvent *ev) ev->xexpose.x, ev->xexpose.y, ev->xexpose.width, ev->xexpose.height, ev->xexpose.count); - - /* - * Ignore Expose events in case user wasn't notified - * about change and acked image resize. - */ + if (x11->resized_flag) break;
+ /* Safety measure */ + if (ev->xexpose.x + ev->xexpose.width > (int)self->context->w) { + GP_WARN("Expose x + w > context->w"); + break; + } + + if (ev->xexpose.y + ev->xexpose.height > (int)self->context->h) { + GP_WARN("Expose y + h > context->h"); + break; + } + + /* Update the rectangle */ x11_update_rect(self, ev->xexpose.x, ev->xexpose.y, ev->xexpose.x + ev->xexpose.width - 1, ev->xexpose.y + ev->xexpose.height - 1); @@ -154,10 +166,17 @@ static void x11_ev(GP_Backend *self, XEvent *ev) if (ev->xconfigure.width == (int)self->context->w && ev->xconfigure.height == (int)self->context->h) break; - - /* - * Window has been resized, set flag. - */ + + if (ev->xconfigure.width == (int)x11->new_w && + ev->xconfigure.height == (int)x11->new_h) + break; + + x11->new_w = ev->xconfigure.width; + x11->new_h = ev->xconfigure.height; + + GP_DEBUG(4, "Configure Notify %ux%u", x11->new_w, x11->new_h); + + /* Window has been resized, set flag. */ x11->resized_flag = 1; default: GP_InputDriverX11EventPut(ev); @@ -193,6 +212,21 @@ static void x11_wait(GP_Backend *self) XUnlockDisplay(x11->dpy); }
+static int resize_buffer(struct GP_Backend *self, uint32_t w, uint32_t h) +{ + struct x11_priv *x11 = GP_BACKEND_PRIV(self); + + if (x11->shm_flag) { + if (resize_shm_ximage(self, w, h)) + return 1; + } else { + if (resize_ximage(self, w, h)) + return 1; + } + + return 0; +} + static int x11_set_attributes(struct GP_Backend *self, uint32_t w, uint32_t h, const char *caption) @@ -209,20 +243,7 @@ static int x11_set_attributes(struct GP_Backend *self,
if (w != 0 && h != 0) { GP_DEBUG(3, "Setting window size to %ux%u", w, h); - - if (x11->shm_flag) { - if (resize_shm_ximage(self, w, h)) - return 1; - } else { - if (resize_ximage(self, w, h)) - return 1; - } - - /* Resize X11 window */ - // XResizeWindow(x11->dpy, x11->win, w, h); - XFlush(x11->dpy); - - x11->resized_flag = 0; + XResizeWindow(x11->dpy, x11->win, w, h); } XUnlockDisplay(x11->dpy); @@ -230,6 +251,26 @@ static int x11_set_attributes(struct GP_Backend *self, return 0; }
+static int x11_resize_ack(struct GP_Backend *self) +{ + struct x11_priv *x11 = GP_BACKEND_PRIV(self); + int ret; + + XLockDisplay(x11->dpy); + + GP_DEBUG(3, "Setting buffer size to %ux%u", x11->new_w, x11->new_h); + + ret = resize_buffer(self, x11->new_w, x11->new_h); + + x11->resized_flag = 0; + + GP_DEBUG(3, "Done"); + + XUnlockDisplay(x11->dpy); + + return ret; +} + static void match_pixel_type(struct x11_priv *x11, enum GP_PixelType *pixel_type, int *depth) { @@ -261,12 +302,16 @@ static int create_shm_ximage(GP_Backend *self, GP_Size w, GP_Size h) return 1; }
- GP_DEBUG(1, "Using MIT SHM Extension"); + if (self->context == NULL) + GP_DEBUG(1, "Using MIT SHM Extension");
enum GP_PixelType pixel_type; int depth;
- match_pixel_type(x11, &pixel_type, &depth); + if (self->context == NULL) + match_pixel_type(x11, &pixel_type, &depth); + else + pixel_type = self->context->pixel_type; if (pixel_type == GP_PIXEL_UNKNOWN) { GP_DEBUG(1, "Unknown pixel type"); @@ -283,13 +328,13 @@ static int create_shm_ximage(GP_Backend *self, GP_Size w, GP_Size h) size_t size = x11->img->bytes_per_line * x11->img->height;
- x11->shminfo.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777); + x11->shminfo.shmid = shmget(IPC_PRIVATE, size, 0600);
if (x11->shminfo.shmid == -1) { GP_WARN("Calling shmget() failed: %s", strerror(errno)); goto err0; } - + x11->shminfo.shmaddr = x11->img->data = shmat(x11->shminfo.shmid, 0, 0);
if (x11->shminfo.shmaddr == (void *)-1) { @@ -297,6 +342,13 @@ static int create_shm_ximage(GP_Backend *self, GP_Size w, GP_Size h) goto err1; }
+ /* Mark SHM for deletion after detach */ + if (shmctl(x11->shminfo.shmid, IPC_RMID, 0)) { + GP_WARN("Calling shmctl(..., IPC_RMID), 0) failed: %s", + strerror(errno)); + goto err2; + } + x11->shminfo.readOnly = False;
if (XShmAttach(x11->dpy, &x11->shminfo) == False) { @@ -311,6 +363,9 @@ static int create_shm_ximage(GP_Backend *self, GP_Size w, GP_Size h)
x11->shm_flag = 1;
+ //FIXME: Proper synchronization + XSync(x11->dpy, True); + return 0; err2: shmdt(x11->shminfo.shmaddr); @@ -324,22 +379,34 @@ err0: static void destroy_shm_ximage(GP_Backend *self) { struct x11_priv *x11 = GP_BACKEND_PRIV(self); + + XLockDisplay(x11->dpy); XShmDetach(x11->dpy, &x11->shminfo); XFlush(x11->dpy); shmdt(x11->shminfo.shmaddr); - shmctl(x11->shminfo.shmid, IPC_RMID, 0); XDestroyImage(x11->img); + XFlush(x11->dpy); + + XUnlockDisplay(x11->dpy); }
static int resize_shm_ximage(GP_Backend *self, int w, int h) { + struct x11_priv *x11 = GP_BACKEND_PRIV(self); + int ret; + GP_DEBUG(4, "Resizing XShmImage %ux%u -> %ux%u", self->context->w, self->context->h, w, h); + XLockDisplay(x11->dpy); + destroy_shm_ximage(self); - - return create_shm_ximage(self, w, h); + ret = create_shm_ximage(self, w, h); + + XUnlockDisplay(x11->dpy); + + return ret; }
#else @@ -406,7 +473,6 @@ static void destroy_ximage(GP_Backend *self) XDestroyImage(x11->img); }
- static int resize_ximage(GP_Backend *self, int w, int h) { struct x11_priv *x11 = GP_BACKEND_PRIV(self); @@ -423,7 +489,7 @@ static int resize_ximage(GP_Backend *self, int w, int h)
/* Resize context */ if (GP_ContextResize(self->context, w, h)) { - XDestroyImage(img); + XDestroyImage(img); return 1; }
@@ -438,6 +504,37 @@ static int resize_ximage(GP_Backend *self, int w, int h) return 0; }
+static void window_close(GP_Backend *self) +{ + struct x11_priv *x11 = GP_BACKEND_PRIV(self); + + XLockDisplay(x11->dpy); + + if (x11->shm_flag) + destroy_shm_ximage(self); + else + destroy_ximage(self); + + XDestroyWindow(x11->dpy, x11->win); + + XUnlockDisplay(x11->dpy); +} + +static void x11_exit(GP_Backend *self) +{ + struct x11_priv *x11 = GP_BACKEND_PRIV(self); + + XLockDisplay(x11->dpy); + + window_close(self); + + /* I wonder if this is right sequence... */ + //XUnlockDisplay(x11->dpy); + XCloseDisplay(x11->dpy); + + free(self); +} + static void create_window(struct x11_priv *x11, int x, int y, unsigned int *w, unsigned int *h, const char *caption, enum GP_BackendX11Flags flags) @@ -658,6 +755,8 @@ GP_Backend *GP_BackendX11Init(const char *display, int x, int y, if (x11->dpy == NULL) goto err0;
+ //XSynchronize(x11->dpy, True); + x11->scr = DefaultScreen(x11->dpy); x11->vis = DefaultVisual(x11->dpy, x11->scr); x11->scr_ptr = DefaultScreenOfDisplay(x11->dpy); @@ -673,6 +772,8 @@ GP_Backend *GP_BackendX11Init(const char *display, int x, int y, goto err1; }
+ backend->context = NULL; + if (create_shm_ximage(backend, w, h)) if (create_ximage(backend, w, h)) goto err1; @@ -688,6 +789,7 @@ GP_Backend *GP_BackendX11Init(const char *display, int x, int y, backend->Poll = x11_poll; backend->Wait = x11_wait; backend->SetAttributes = x11_set_attributes; + backend->ResizeAck = x11_resize_ack; backend->fd = XConnectionNumber(x11->dpy);
return backend;
-----------------------------------------------------------------------
Summary of changes: build/syms/Backend_symbols.txt | 1 + build/syms/Event_symbols.txt | 2 +- demos/c_simple/Makefile | 6 +- demos/c_simple/{input.c => input_example.c} | 4 +- demos/spiv/spiv.c | 78 ++++-- doc/Makefile | 2 +- doc/api.txt | 5 + doc/backends.txt | 17 ++ ...ers_progress_callback.txt => example_input.txt} | 6 +- doc/input.txt | 271 ++++++++++++++++++++ include/backends/GP_Backend.h | 21 ++ include/input/GP_Event.h | 2 +- libs/backends/GP_Backend.c | 10 + libs/backends/GP_LinuxFB.c | 1 + libs/backends/GP_SDL.c | 1 + libs/backends/GP_X11.c | 226 ++++++++++++----- libs/input/GP_Event.c | 2 +- 17 files changed, 559 insertions(+), 96 deletions(-) rename demos/c_simple/{input.c => input_example.c} (98%) copy doc/{example_loaders_progress_callback.txt => example_input.txt} (62%) create mode 100644 doc/input.txt
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.