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()", \
|
||||
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) \
|
||||
uiprivProgrammerError("attempt to use a %s sender with a %s event in %s()", \
|
||||
|
@ -45,3 +63,8 @@
|
|||
|
||||
#define uiprivProgrammerErrorInvalidatingGlobalEvent() \
|
||||
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()`
|
||||
|
||||
```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()`.
|
||||
|
||||
`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()`
|
||||
|
||||
|
|
2
ui.h
2
ui.h
|
@ -75,7 +75,7 @@ struct uiControlVtable {
|
|||
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 uiControl *uiNewControl(uint32_t type, void *initData);
|
||||
|
|
Loading…
Reference in New Issue