Started writing the uiControl implementation.
This commit is contained in:
parent
e2842bae35
commit
1189877ca5
|
@ -0,0 +1,162 @@
|
||||||
|
// 8 june 2019
|
||||||
|
#include "uipriv.h"
|
||||||
|
|
||||||
|
struct controlType {
|
||||||
|
uint32_t id;
|
||||||
|
char *name;
|
||||||
|
uiControlVtable vtable;
|
||||||
|
uiControlOSVtable *osVtable;
|
||||||
|
size_t implDataSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int controlTypeCmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct controlType *ca = (const struct controlType *) a;
|
||||||
|
const struct controlType *cb = (const struct controlType *) b;
|
||||||
|
|
||||||
|
if (ca->id < cb->id)
|
||||||
|
return -1;
|
||||||
|
if (ca->id > cb->id)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uiControl {
|
||||||
|
uint32_t controlID;
|
||||||
|
uint32_t typeID;
|
||||||
|
struct controlType *type;
|
||||||
|
void *implData;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uiprivArray controlTypes = uiprivArrayStaticInit(struct controlType, 32, "uiControl type information");
|
||||||
|
|
||||||
|
#define controlTypeID UINT32_C(0x1F2E3C4D)
|
||||||
|
|
||||||
|
uint32_t uiControlType(void)
|
||||||
|
{
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return 0;
|
||||||
|
return controlTypeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t nextControlID = UINT32_C(0x80000000);
|
||||||
|
|
||||||
|
uint32_t uiRegisterControlType(const char *name, uiControlVtable *vtable, uiControlOSVtable *osVtable, size_t implDataSize)
|
||||||
|
{
|
||||||
|
struct controlType *ct;
|
||||||
|
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return 0;
|
||||||
|
if (vtable == NULL) {
|
||||||
|
uiprivProgrammerErrorNullPointer("uiControlVtable", uiprivFunc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (vtable->Size != sizeof (uiControlVtable)) {
|
||||||
|
uiprivProgrammerErrorWrongStructSize(vtable->Size, "uiControlVtable");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#define checkMethod(method) \
|
||||||
|
if (vtable->method == NULL) { \
|
||||||
|
uiprivProgrammerErrorRequiredMethodMissing(name, "uiControlVtable", #method, uiprivFunc); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
checkMethod(Init)
|
||||||
|
checkMethod(Free)
|
||||||
|
#undef checkMethod
|
||||||
|
|
||||||
|
if (osVtable == NULL) {
|
||||||
|
uiprivProgrammerErrorNullPointer("uiControlOSVtable", uiprivFunc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!uiprivOSVtableValid(osVtable, uiprivFunc))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ct = (struct controlType *) uiprivArr
|
||||||
|
ayAppend(&controlTypes, 1);
|
||||||
|
ct->id = nextControlID;
|
||||||
|
nextControlID++;
|
||||||
|
ct->name = uiprivStrdup(name);
|
||||||
|
ct->vtable = *vtable;
|
||||||
|
ct->osVtable = uiprivCloneOSVtable(osVtable);
|
||||||
|
ct->implDataSize = implDataSize;
|
||||||
|
return ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *uiCheckControlType(void *c, uint32_t type)
|
||||||
|
{
|
||||||
|
struct controlType *got, *want;
|
||||||
|
struct controlType key;
|
||||||
|
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return NULL;
|
||||||
|
if (c == NULL) {
|
||||||
|
uiprivProgrammerErrorNullPointer("uiControl", uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (c->controlID != controlTypeID) {
|
||||||
|
uiprivProgrammerErrorNotAControl(uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now grab the type information for c itself
|
||||||
|
// do this even if we were asked if this is a uiControl; we want to make absolutely sure this is a *real* uiControl
|
||||||
|
memset(&key, 0, sizeof (struct controlType));
|
||||||
|
key.id = c->typeID;
|
||||||
|
got = (struct controlType *) uiprivArrayBsearch(&controlTypes &key, controlTypeCmp);
|
||||||
|
if (got == NULL) {
|
||||||
|
uiprivProgrammerErrorUnknownTypeUsed(c->typeID, uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == controlTypeID)
|
||||||
|
// this is a real uiControl; no need to check further
|
||||||
|
return c;
|
||||||
|
|
||||||
|
// type isn't uiControlType(); make sure it is valid too
|
||||||
|
memset(&key, 0, sizeof (struct controlType));
|
||||||
|
key.id = type;
|
||||||
|
want = (struct controlType *) uiprivArrayBsearch(&controlTypes &key, controlTypeCmp);
|
||||||
|
if (want == NULL) {
|
||||||
|
uiprivProgrammerErrorUnknownTypeRequested(type, uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->typeID != type) {
|
||||||
|
uiprivProgrammerErrorWrongType(got->name, want->name, uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiControl *uiNewControl(uint32_t type, void *initData)
|
||||||
|
{
|
||||||
|
uiControl *c;
|
||||||
|
struct controlType *ct;
|
||||||
|
struct controlType key;
|
||||||
|
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return NULL;
|
||||||
|
if (type == controlTypeID) {
|
||||||
|
uiprivProgrammerErrorCannotCreateBaseControl();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(&key, 0, sizeof (struct controlType));
|
||||||
|
key.id = type;
|
||||||
|
ct = (struct controlType *) uiprivArrayBsearch(&controlTypes, &key, controlTypeCmp);
|
||||||
|
if (ct == NULL) {
|
||||||
|
uiprivProgrammerErrorUnknownTypeRequested(type, uiprivFunc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiControlFree(uiControl *c)
|
||||||
|
{
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *uiControlImplData(uiControl *c)
|
||||||
|
{
|
||||||
|
if (!uiprivCheckInitializedAndThread())
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -24,7 +24,25 @@
|
||||||
uiprivProgrammerError("%s identifier %d not found in %s()", \
|
uiprivProgrammerError("%s identifier %d not found in %s()", \
|
||||||
idDesc, badID, func)
|
idDesc, badID, func)
|
||||||
|
|
||||||
// TODO type mismatch
|
#define uiprivProgrammerErrorRequiredMethodMissing(typeName, tableType, methodName, func) \
|
||||||
|
uiprivProgrammerError("%s: required %s method %s() missing in %s()", \
|
||||||
|
typeName, tableType, methodName, func)
|
||||||
|
|
||||||
|
#define uiprivProgrammerErrorNotAControl(func) \
|
||||||
|
uiprivProgrammerError("object passed in to %s() not a uiControl", \
|
||||||
|
func)
|
||||||
|
|
||||||
|
#define uiprivProgrammerErrorUnknownTypeUsed(type, func) \
|
||||||
|
uiprivProgrammerError("unknown type %" PRIu32 " found in uiControl passed to %s(); this is likely not a real uiControl or some data is corrupt", \
|
||||||
|
type, func)
|
||||||
|
|
||||||
|
#define uiprivProgrammerErrorUnknownTypeRequested(type, func) \
|
||||||
|
uiprivProgrammerError("unknown type %" PRIu32 " passed to %s()", \
|
||||||
|
type, func)
|
||||||
|
|
||||||
|
#define uiprivProgrammerErrorWrongType(got, want, func) \
|
||||||
|
uiprivProgrammerError("wrong type passed to %s(): got %s, want %s",
|
||||||
|
func, got, want)
|
||||||
|
|
||||||
#define uiprivProgrammerErrorBadSenderForEvent(senderDesc, eventDesc, func) \
|
#define uiprivProgrammerErrorBadSenderForEvent(senderDesc, eventDesc, func) \
|
||||||
uiprivProgrammerError("attempt to use a %s sender with a %s event in %s()", \
|
uiprivProgrammerError("attempt to use a %s sender with a %s event in %s()", \
|
||||||
|
@ -45,3 +63,8 @@
|
||||||
|
|
||||||
#define uiprivProgrammerErrorInvalidatingGlobalEvent() \
|
#define uiprivProgrammerErrorInvalidatingGlobalEvent() \
|
||||||
uiprivProgrammerError("attempt to call uiEventInvalidateSender() on a global uiEvent")
|
uiprivProgrammerError("attempt to call uiEventInvalidateSender() on a global uiEvent")
|
||||||
|
|
||||||
|
// TODO move the type stuff here
|
||||||
|
|
||||||
|
#define uiprivProgrammerErrorCannotCreateBaseControl() \
|
||||||
|
uiprivProgrammerError("cannot create a uiControl of type uiControl; you must use a specific control type")
|
||||||
|
|
|
@ -42,14 +42,18 @@ Each method is named for the `uiControl` function that it implements. As such, d
|
||||||
### `uiRegisterControlType()`
|
### `uiRegisterControlType()`
|
||||||
|
|
||||||
```c
|
```c
|
||||||
uint32_t uiRegisterControlType(uiControlVtable *vtable, uiControlOSVtable *osVtable, size_t implDataSize);
|
uint32_t uiRegisterControlType(const char *name, uiControlVtable *vtable, 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()`.
|
`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()`.
|
||||||
|
|
||||||
`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.
|
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 either vtable. An `implDataSize` of 0 is legal; the implementation data pointer will be `NULL`. This is not particularly useful, however. 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.
|
`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()`
|
### `uiCheckControlType()`
|
||||||
|
|
||||||
|
|
2
ui.h
2
ui.h
|
@ -75,7 +75,7 @@ struct uiControlVtable {
|
||||||
void (*Free)(uiControl *c, void *implData);
|
void (*Free)(uiControl *c, void *implData);
|
||||||
};
|
};
|
||||||
|
|
||||||
uiprivExtern uint32_t uiRegisterControlType(uiControlVtable *vtable, uiControlOSVtable *osVtable, size_t implDataSize);
|
uiprivExtern uint32_t uiRegisterControlType(const char *nane, uiControlVtable *vtable, uiControlOSVtable *osVtable, size_t implDataSize);
|
||||||
uiprivExtern void *uiCheckControlType(void *c, uint32_t type);
|
uiprivExtern void *uiCheckControlType(void *c, uint32_t type);
|
||||||
|
|
||||||
uiprivExtern uiControl *uiNewControl(uint32_t type, void *initData);
|
uiprivExtern uiControl *uiNewControl(uint32_t type, void *initData);
|
||||||
|
|
Loading…
Reference in New Issue