diff --git a/common/controls.c b/common/controls.c index 32c8baa6..fd950b7a 100644 --- a/common/controls.c +++ b/common/controls.c @@ -184,9 +184,6 @@ void uiControlFree(uiControl *c) return; } - uiEventFire(uiControlOnFree(), c, NULL); - uiEventInvalidateSender(uiControlOnFree(), c); - callVtable(c->type->vtable.Free, c, c->implData); uiprivFree(c->implData); diff --git a/common/meson.build b/common/meson.build index bfb71f62..dc2f62af 100644 --- a/common/meson.build +++ b/common/meson.build @@ -4,6 +4,5 @@ libui_sources += [ 'common/alloc.c', 'common/controls.c', 'common/errors.c', - 'common/events.c', 'common/main.c', ] diff --git a/common/programmererrors.h b/common/programmererrors.h index 89c9e2ae..a529878a 100644 --- a/common/programmererrors.h +++ b/common/programmererrors.h @@ -24,38 +24,6 @@ // } -// events { - -#define uiprivProgrammerErrorEventHandlerNotFound(badID, func) \ - uiprivProgrammerError("%s(): event handler %d not found", \ - func, badID) - -#define uiprivProgrammerErrorBadSenderForEvent(senderDesc, eventDesc, func) \ - uiprivProgrammerError("%s(): can't use a %s sender with a %s event", \ - func, senderDesc, eventDesc) - -#define uiprivProgrammerErrorChangingEventDuringFire(func) \ - uiprivProgrammerError("%s(): can't change a uiEvent while it is firing", \ - func) - -#define uiprivProgrammerErrorRecursiveEventFire(func) \ - uiprivProgrammerError("%s(): can't recursively fire a uiEvent", \ - func) - -#define uiprivProgrammerErrorFreeingInternalEvent(func) \ - uiprivProgrammerError("%s(): can't free a libui-provided event", \ - func) - -#define uiprivProgrammerErrorFreeingEventInUse(func) \ - uiprivProgrammerError("%s(): can't free event that still has handlers registered", \ - func) - -#define uiprivProgrammerErrorInvalidatingGlobalEvent(func) \ - uiprivProgrammerError("%s(): can't invalidate a global event", \ - func) - -// } - // controls { #define uiprivProgrammerErrorRequiredControlMethodMissing(typeName, tableType, methodName, func) \ diff --git a/doc/00_index.md b/doc/00_index.md index 88c76cb2..ecae405f 100644 --- a/doc/00_index.md +++ b/doc/00_index.md @@ -2,7 +2,6 @@ * [Using libui](using-libui.md) * [Initialization and the Main Loop](init-main.md) -* [Event Handling](events.md) * [Controls](controls.md) * Windows ** [Controls](windows-controls.md) diff --git a/doc/controls.md b/doc/controls.md index f286acda..a467d964 100644 --- a/doc/controls.md +++ b/doc/controls.md @@ -132,11 +132,3 @@ void *uiControlImplData(uiControl *c); This function is meant to be used by control implementations only. There is in general no guarantee as to the size or format of this pointer. Normal users should not call `uiControlImplData()`. It is a programmer error to pass `NULL` or a non-`uiControl` for `c`. - -## `uiControlOnFree()` - -```c -uiEvent *uiControlOnFree(void); -``` - -`uiControlOnFree()` returns a `uiEvent` that is fired by `uiControlFree()` to indicate that a control is about to be freed. In your handler, `sender` is the control in question and `args` is `NULL`. diff --git a/test/allcalls.h b/test/allcalls.h index 0d136546..3ec24eb6 100644 --- a/test/allcalls.h +++ b/test/allcalls.h @@ -8,14 +8,6 @@ allcallsCase(uiQuit, /* no arguments */) allcallsCase(uiQueueMain, NULL, NULL) #endif -allcallsCase(uiNewEvent, NULL) -allcallsCase(uiEventAddHandler, NULL, NULL, NULL, NULL) -allcallsCase(uiEventDeleteHandler, NULL, 0) -allcallsCase(uiEventFire, NULL, NULL, NULL) -allcallsCase(uiEventHandlerBlocked, NULL, 0) -allcallsCase(uiEventSetHandlerBlocked, NULL, 0, false) -allcallsCase(uiEventInvalidateSender, NULL, NULL) - allcallsCase(uiControlType, /* no arguments */) allcallsCase(uiRegisterControlType, NULL, NULL, NULL, 0) diff --git a/test/meson.build b/test/meson.build index d51d8684..38e58716 100644 --- a/test/meson.build +++ b/test/meson.build @@ -2,8 +2,6 @@ # Using files() is the cleanest way to ensure the python script below gets the right filenames regardless of how meson sandboxes the command it's running. libui_test_sources = files([ - 'events.c', -# 'events_errors.cpp', 'initmain.c', # 'noinitwrongthread.c', ]) diff --git a/ui.h b/ui.h index 0880f1b2..4d339039 100644 --- a/ui.h +++ b/ui.h @@ -43,25 +43,6 @@ uiprivExtern void uiMain(void); uiprivExtern void uiQuit(void); uiprivExtern void uiQueueMain(void (*f)(void *data), void *data); -typedef struct uiEvent uiEvent; -typedef struct uiEventOptions uiEventOptions; - -typedef void (*uiEventHandler)(void *sender, void *args, void *data); - -struct uiEventOptions { - size_t Size; - bool Global; -}; - -uiprivExtern uiEvent *uiNewEvent(const uiEventOptions *options); -uiprivExtern void uiEventFree(uiEvent *e); -uiprivExtern int uiEventAddHandler(uiEvent *e, uiEventHandler handler, void *sender, void *data); -uiprivExtern void uiEventDeleteHandler(uiEvent *e, int id); -uiprivExtern void uiEventFire(uiEvent *e, void *sender, void *args); -uiprivExtern bool uiEventHandlerBlocked(const uiEvent *e, int id); -uiprivExtern void uiEventSetHandlerBlocked(uiEvent *e, int id, bool blocked); -uiprivExtern void uiEventInvalidateSender(uiEvent *e, void *sender); - typedef struct uiControl uiControl; typedef struct uiControlVtable uiControlVtable; typedef struct uiControlOSVtable uiControlOSVtable; @@ -82,7 +63,6 @@ uiprivExtern uiControl *uiNewControl(uint32_t type, void *initData); uiprivExtern void uiControlFree(uiControl *c); uiprivExtern void uiControlSetParent(uiControl *c, uiControl *parent); uiprivExtern void *uiControlImplData(uiControl *c); -uiprivExtern uiEvent *uiControlOnFree(void); #ifdef __cplusplus } diff --git a/zNEW_events/common_controls.c b/zNEW_events/common_controls.c new file mode 100644 index 00000000..e5cac870 --- /dev/null +++ b/zNEW_events/common_controls.c @@ -0,0 +1,15 @@ +... + +void uiControlFree(uiControl *c) +{ + ... + } + + uiEventFire(uiControlOnFree(), c, NULL); + uiEventInvalidateSender(uiControlOnFree(), c); + + callVtable(c->type->vtable.Free, c, c->implData); + ... +} + +... diff --git a/common/events.c b/zNEW_events/common_events.c similarity index 100% rename from common/events.c rename to zNEW_events/common_events.c diff --git a/zNEW_events/common_programmererrors.h b/zNEW_events/common_programmererrors.h new file mode 100644 index 00000000..692931f0 --- /dev/null +++ b/zNEW_events/common_programmererrors.h @@ -0,0 +1,45 @@ +... +#define uiprivProgrammerErrorNullPointer(paramDesc, func) \ + uiprivProgrammerError("%s(): invalid null pointer for %s", \ + func, paramDesc) + +// } + +// events { + +#define uiprivProgrammerErrorEventHandlerNotFound(badID, func) \ + uiprivProgrammerError("%s(): event handler %d not found", \ + func, badID) + +#define uiprivProgrammerErrorBadSenderForEvent(senderDesc, eventDesc, func) \ + uiprivProgrammerError("%s(): can't use a %s sender with a %s event", \ + func, senderDesc, eventDesc) + +#define uiprivProgrammerErrorChangingEventDuringFire(func) \ + uiprivProgrammerError("%s(): can't change a uiEvent while it is firing", \ + func) + +#define uiprivProgrammerErrorRecursiveEventFire(func) \ + uiprivProgrammerError("%s(): can't recursively fire a uiEvent", \ + func) + +#define uiprivProgrammerErrorFreeingInternalEvent(func) \ + uiprivProgrammerError("%s(): can't free a libui-provided event", \ + func) + +#define uiprivProgrammerErrorFreeingEventInUse(func) \ + uiprivProgrammerError("%s(): can't free event that still has handlers registered", \ + func) + +#define uiprivProgrammerErrorInvalidatingGlobalEvent(func) \ + uiprivProgrammerError("%s(): can't invalidate a global event", \ + func) + +// } + +// controls { + +#define uiprivProgrammerErrorRequiredControlMethodMissing(typeName, tableType, methodName, func) \ + uiprivProgrammerError("%s(): required %s method %s() missing for uiControl type %s", \ + func, tableType, methodName, typeName) +... diff --git a/zNEW_events/doc_00_index.md b/zNEW_events/doc_00_index.md new file mode 100644 index 00000000..e654d8f0 --- /dev/null +++ b/zNEW_events/doc_00_index.md @@ -0,0 +1,5 @@ +... +* [Initialization and the Main Loop](init-main.md) +* [Event Handling](events.md) +* [Controls](controls.md) +... diff --git a/zNEW_events/doc_controls.md b/zNEW_events/doc_controls.md new file mode 100644 index 00000000..f286acda --- /dev/null +++ b/zNEW_events/doc_controls.md @@ -0,0 +1,142 @@ + + +# Controls + +## Overview + +TODO + +## Reference + +### `uiControl` + +```c +typedef struct uiControl uiControl; +uint32_t uiControlType(void); +#define uiControl(obj) ((uiControl *) uiCheckControlType((obj), uiControlType())) +``` + +`uiControl` is an opaque type that describes a control. + +`uiControlType()` is the type identifier of a `uiControl` as passed to `uiCheckControlType()`. You rarely need to call this directly; the `uiControl()` conversion macro does this for you. + +### `uiControlVtable` + +```c +typedef struct uiControlVtable uiControlVtable; +struct uiControlVtable { + size_t Size; + bool (*Init)(uiControl *c, void *implData, void *initData); + void (*Free)(uiControl *c, void *implData); +}; +``` + +`uiControlVtable` describes the set of functions that control implementations need to implement. When registering your control type, you pass this in as a parameter to `uiRegisterControlType()`. Each method here is required. + +You are responsible for allocating and initializing this struct. To do so, you simply zero the memory for this struct and set its `Size` field to `sizeof (uiControlVtable)`. (TODO put this in a common place) + +Each method takes at least two parameters. The first, `c`, is the `uiControl` itself. The second, `implData`, is the implementation data pointer; it is the same as the pointer returned by `uiControlImplData(c)`, and is provided here as a convenience. + +Each method is named for the `uiControl` function that it implements. As such, details on how to implement these methods are documented alongside those functions. For instance, instructions on implementing `Free()` are given under the documentation for `uiControlFree()`. The only exception is `Init()`, which is discussed under `uiNewControl()` below. + +### `uiRegisterControlType()` + +```c +uint32_t uiRegisterControlType(const char *name, const uiControlVtable *vtable, const uiControlOSVtable *osVtable, size_t implDataSize); +``` + +`uiRegisterControlType()` registers a new `uiControl` type with the given vtables and returns its ID as passed to `uiNewControl()`. `implDataSize` is the size of the implementation data struct that is created by `uiNewControl()`. + +Each type has a name, passed in the `name` parameter. The type name is only used for debugging and error reporting purposes. The type name is copied into libui-internal memory; the `name` pointer passed to `uiRegisterControlType()` is not used after it returns. It is a programmer error to specify `NULL` for `name`. (TODO anything else? Empty string? Duplicate name?) + +`uiControlVtable` describes the functions of a `uiControl` common between platforms, and is discussed on this page. `uiControlOSVtable` describes functionst hat vary from OS to OS, and are described in the respective OS-specific uiControl implementation pages. The two vtables are copied into libui-internal memory; the vtable pointers passed to `uiRegisterControlType()` are not used after it returns. + +It is a programmer error to specify `NULL` for either vtable. It is also a programmer error to specify `NULL` for any of the methods in either vtable — that is, all methods are required. It is also a programmer error to pass the wrong value to the `Size` field of either vtable. + +An `implDataSize` of 0 is legal; the implementation data pointer will be `NULL`. This is not particularly useful, however. + +### `uiCheckControlType()` + +```c +void *uiCheckControlType(void *c, uint32_t type); +``` + +`uiCheckControlType()` checks whether `c` is a `uiControl`, and if so, whether it is of the type specified by `type`. If `c` is `NULL`, or if either of the above conditions is false, a programmer error is raised. If the conditions are met, the function returns `c` unchanged. + +This function is intended to be used to implement a macro that converts an arbitrary `uiControl` pointer into a specific type. For instance, `uiButton` exposes its type ID as a function `uiButtonType()`, and provides the macro `uiButton()` that does the actual conversion as so: + +```c +#define uiButton(c) ((uiButton *) uiCheckControlType((c), uiButtonType())) +``` + +### `uiNewControl()` + +```c +uiControl *uiNewControl(uint32_t type, void *initData); +``` + +`uiNewControl()` creates a new `uiControl` of the given type. + +This function is meant for control implementations to use in the implementation of dedicated creation functions; for instance, `uiNewButton()` calls `uiNewControl()`, passing in the appropriate values for `initData`. `initData` is, in turn, passed to the control's `Init()` method, and its format is generally internal to the control. Normal users should not call this function. + +It is a programmer error to pass an invalid value for either `type` or `initData`. + +**For control implementations**: This function allocates both the `uiControl` and the memory for the implementation data, and then passes both of these allocations as well as the value of `initData` into your `Init()` method. Return `false` from the `Init()` method if `initData` is invalid; if it is valid, initialize the control and return `true`. To discourage direct use of `uiNewControl()`, you should generally not allow `initData` to be `NULL`, even if there are no parameters. Do **not** return `false` for any other reason, including other forms of initialization failures; see [Error handling](error-handling.md) for details on what to do instead. + +### `uiControlFree()` + +```c +void uiControlFree(uiControl *c); +``` + +`uiControlFree()` frees the given control. + +If `c` has children, those children are also freed. It is a programmer error to free a control that is itself a child of another control. + +If `c` has any registered events, those event handlers will be set to be no longer run via `uiEventInvalidateSender()`. The registered handlers themselves will not be removed, to avoid the scenario of another `uiControl` being created with the same pointer value later triggering your handler unexpectedly. + +It is a programmer error to specify `NULL` for `c`. + +**For control implementations**: This function calls your vtable's `Free()` method. Parameter validity checks are already performed, `uiControlOnFree()` handlers have been called, and `uiControl`-specific events have been invalidated. Your `Free()` should invalidate any events that are specific to your controls, call `uiControlFree()` on all the children of this control, and free dynamically allocated memory that is part of your implementation data. Once your `Free()` method returns, libui will take care of freeing the implementation data memory block itself. + +## `uiControlSetParent()` + +```c +uiprivExtern void uiControlSetParent(uiControl *c, uiControl *parent); +``` + +`uiControlSetParent()` marks `parent` as the parent of `c`. `parent` may be `NULL`, in which case the control has no parent. + +This function is used by the implementation of a container control to actually establish a parent-child relationship from libui's point of view. This function is only intended to be called by control implementations. You should not call it directly; instead, use the methods provided by your container control to add children. + +This function can only be used to set the parent of an unparented control or to remove its parent. It may not be used to change the parent of an already parented control. It is a programmer error to set the parent of a control that already has a parent to something other than `NULL`, or to set the parent of a control with no parent to `NULL`. (The idea here is to reinforce the concept of container implementations being responsible for setting their children properly, not the user.) + +It is a programmer error to pass `NULL` or a non-control for `c`. + +TODO circular parenting +TODO self-parenting +TODO top-levels and parenting + +**For control implementations**: You would call this when adding a control to your container, preferably before actually doing the OS-level work involved. Likewise, call this when removing a child, preferably after doing the OS-level work involved. + +TODO do things this way to avoid needing to check if reparenting from a container implementation, or do that manually each time? we used to have uiControlVerifySetParent()... + +## `uiControlImplData()` + +```c +void *uiControlImplData(uiControl *c); +``` + +`uiControlImplData()` returns the pointer to the implementation data for `c`. The returned pointer is valid for the lifetime of `c`. + +This function is meant to be used by control implementations only. There is in general no guarantee as to the size or format of this pointer. Normal users should not call `uiControlImplData()`. + +It is a programmer error to pass `NULL` or a non-`uiControl` for `c`. + +## `uiControlOnFree()` + +```c +uiEvent *uiControlOnFree(void); +``` + +`uiControlOnFree()` returns a `uiEvent` that is fired by `uiControlFree()` to indicate that a control is about to be freed. In your handler, `sender` is the control in question and `args` is `NULL`. diff --git a/doc/events.md b/zNEW_events/doc_events.md similarity index 100% rename from doc/events.md rename to zNEW_events/doc_events.md diff --git a/zNEW_events/doc_init-main.md b/zNEW_events/doc_init-main.md new file mode 100644 index 00000000..7667ba26 --- /dev/null +++ b/zNEW_events/doc_init-main.md @@ -0,0 +1,142 @@ + + +# Initialization and the Main Loop + +## Overview + +In order to use libui, you must first initialize it. All initialization is done through the `uiInit()` function. This is usually one of the first things you do in your program. + +The thread you call `uiInit()` on becomes the "GUI thread". This is the thread that all your UI is done on from the perspective of the operating system, so it is absolutely essential that you do **not** call any other function of libui from any other thread that you create (except for `uiQueueMain()`, which is discussed later). + +Furthermore, on some systems, this thread must also be the thread that `main()` is called on; macOS is the notable example here. Therefore, to be safe, you should only call `uiInit()` from `main()`, or from a function that runs on the same thread as `main()`. If you are using a language binding, that binding may provide further instruction on how to do so in that language. + +`uiInit()` *can* fail, in which case it will provide information about that failure in a special variable of type `uiInitError` that you provide it. The most useful member of this struct is `Message`, which contains a human-readable error message you can use to diagnose problems initializing libui. If you are using a language binding, the language binding may abstract this away and provide the error to you in a langauge-specific form. + +Here is an example of correct use of `uiInit()` in C: + +```c +int main(void) +{ + uiInitError err; + + memset(&err, 0, sizeof (uiInitError)); + err.Size = sizeof (uiInitError); + if (!uiInit(NULL, &err)) { + fprintf(stderr, "error initializing libui: %s\n", err.Message); + return 1; + } + // ... +} +``` + +Note that if `uiInit()` fails, you **cannot** use libui's message box functions to report the error. + +Once you have called `uiInit()`, you should set up the initial UI for your program. Once that is done, you start the program event loop by calling `uiMain()`. `uiMain()` runs the *main event loop*, which processes all events for the GUI and dispatches them to the event handlers you write. As this function does everything for you, all you need to do is call it: + +```c +int main(void) +{ + // ... + uiMain(); + return 0; +} +``` + +`uiMain()` will not return until one of your event handlers calls `uiQuit()`. `uiQuit()` informs `uiMain()` that it should return, but it won't actually return until the current event handler has finished being processed. Once it does return, you will be dropped back into `main()`. + +Event handlers can be more than just actions in response to user action to a control, such as clicking a button. The OS can use events to tell your program things that happen outside your program, such as "the user wants to close your application from within a program list/taskbar/dock". libui provides methods of catching and handling these. You can also schedule code to run when there is no event pending, or on a timed loop. While these scheduled code paths are not technically events per se, they operate exactly like event handlers. + +TODO should quit + +The simplest way to schedule code to run the next time no event is pending is to use `uiQueueMain()`. `uiQueueMain()` takes a function and some data to pass to that function, and returns immediately, so you can continue working. When `uiMain()` goes to get the next event, it will notice that your function is ready to run, and if there are no events that need to be handled, will do so. + +`uiQueueMain()` is special in that it is the only function in libui that you can call from any thread, not just the UI thread. This is intentional: `uiQueueMain()` allows you to communicate between the UI thread and another thread, as all code that is scheduled by `uiQueueMain()` is run on the UI thread. For example, if you are downloading assets in a background thread and want to update a progressbar, you can do so: + +```c +void updateProgressBar(void *data) +{ + uiProgressBar *p = uiProgressBar(data); + + uiProgressBarSetValue(p, uiProgressBarValue(p) + 1); +} + +extern uiProgressBar *progressbar; + +void backgroundThread(void) +{ + while (fileIsDownloading()) + uiQueueMain(updateProgressBar, progressbar); +} +``` + +If you want to wait for the function in `uiQueueMain()` to be called, you will need to provide some synchronization method yourself. Be careful not to do this if you call `uiQueueMain()` on the UI thread, to avoid deadlocking your program! + +TODO timers + +## Reference + +### `uiInit()` + +```c +bool uiInit(void *options, uiInitError *err); +``` + +`uiInit()` initializes libui. It returns `true` on success and `false` on failure; in the event of a failure, `err` is filled with relevant information explaining the failure. + +`err` is required and must be properly initialized. If `err` is `NULL` or `err->Size` does not match `sizeof (uiError)`, `uiInit()` immediately returns `false` without doing anything. If any of the other fields of `err` are not zero-initialized as with `memset(0)`, the behavior is undefined. + +`options` must be `NULL`; no options are currently defined. If `options` is not `NULL`, `uiInit()` will return an error without initializing anything. + +As part of initialization, the thread that `uiInit()` is called on becomes the GUI thread. All of the functions of libui except `uiQueueMain()` **must** be called from this thread. On platforms where which thread you run GUI code on is restricted, `uiMain()` will return an error if it is called from the wrong thread; to avoid this, you should always call `uiInit()` from the thread that `main()` itself is called from. + +If `uiInit()` fails, no other libui function is safe to call. This means that you cannot use any of libui's message box functions to report the error. + +**Notes for language binding authors**: Your language will likely provide its own preferred mechanism for reporting errors. You should wrap `uiInit()` to return errors this way, creating and managing the memory for `uiInitError` yourself and transforming the returned error according to both the format of `uiInitError` described below and the rules for encoding errors in your language of choice. + +### `uiInitError` + +```c +typedef struct uiInitError uiInitError; +struct uiInitError { + size_t Size; + char Message[256]; +}; +``` + +`uiInitError` describes an error returned by `uiInit()`. + +You are responsible for allocating and initializing this struct. To do so, you simply zero the memory for this struct and set its `Size` field to `sizeof (uiInitError)`. The example in the main section of this page demonstrates how to do this. + +In the event of an error, `Message` will contain a NUL-terminated C string in the encoding expected by `fprintf()`. This is in contrast to the rest of libui, which uses UTF-8 strings. + +### `uiMain()` + +```c +void uiMain(void); +``` + +`uiMain()` runs the main event loop. It does not return until `uiQuit()` is called. + +### `uiQuit()` + +```c +void uiQuit(void); +``` + +`uiQuit()` causes `uiMain()` to return once the current event has finished processing. + +TODO safety of calling `uiMain()` again after `uiQuit()`? + +TODO behavior of calling `uiQuit()` outside of a `uiMain()` (before, after, etc.) + +### `uiQueueMain()` + +```c +void uiQueueMain(void (*f)(void *data), void *data); +``` + +`uiQueueMain()` schedules `f` to be called with `data` as a parameter on the next iteration of the main loop when no event is pending. It returns immediately. + +`uiQueueMain()` can safely be called from any thread, not just the UI thread. + +If you call `uiQueueMain()` in sequence, the functions will execute in that order; if other threads are calling `uiQueueMain()` at the same time, there is no guarantee as to whether the calls are interleaved, but the order per-thread will be maintained. diff --git a/zNEW_events/test_allcalls.h b/zNEW_events/test_allcalls.h new file mode 100644 index 00000000..93b4e976 --- /dev/null +++ b/zNEW_events/test_allcalls.h @@ -0,0 +1,13 @@ +... +#endif + +allcallsCase(uiNewEvent, NULL) +allcallsCase(uiEventAddHandler, NULL, NULL, NULL, NULL) +allcallsCase(uiEventDeleteHandler, NULL, 0) +allcallsCase(uiEventFire, NULL, NULL, NULL) +allcallsCase(uiEventHandlerBlocked, NULL, 0) +allcallsCase(uiEventSetHandlerBlocked, NULL, 0, false) +allcallsCase(uiEventInvalidateSender, NULL, NULL) + +allcallsCase(uiControlType, /* no arguments */) +... diff --git a/test/events.c b/zNEW_events/test_events.c similarity index 100% rename from test/events.c rename to zNEW_events/test_events.c diff --git a/test/events_errors.cpp b/zNEW_events/test_events_errors.cpp similarity index 100% rename from test/events_errors.cpp rename to zNEW_events/test_events_errors.cpp diff --git a/zNEW_events/ui.h b/zNEW_events/ui.h new file mode 100644 index 00000000..90d86446 --- /dev/null +++ b/zNEW_events/ui.h @@ -0,0 +1,29 @@ +... +uiprivExtern void uiQueueMain(void (*f)(void *data), void *data); + +typedef struct uiEvent uiEvent; +typedef struct uiEventOptions uiEventOptions; + +typedef void (*uiEventHandler)(void *sender, void *args, void *data); + +struct uiEventOptions { + size_t Size; + bool Global; +}; + +uiprivExtern uiEvent *uiNewEvent(const uiEventOptions *options); +uiprivExtern void uiEventFree(uiEvent *e); +uiprivExtern int uiEventAddHandler(uiEvent *e, uiEventHandler handler, void *sender, void *data); +uiprivExtern void uiEventDeleteHandler(uiEvent *e, int id); +uiprivExtern void uiEventFire(uiEvent *e, void *sender, void *args); +uiprivExtern bool uiEventHandlerBlocked(const uiEvent *e, int id); +uiprivExtern void uiEventSetHandlerBlocked(uiEvent *e, int id, bool blocked); +uiprivExtern void uiEventInvalidateSender(uiEvent *e, void *sender); + +typedef struct uiControl uiControl; +... +uiprivExtern void *uiControlImplData(uiControl *c); +uiprivExtern uiEvent *uiControlOnFree(void); + +#ifdef __cplusplus +...