Started writing the uiControl implementation.

This commit is contained in:
Pietro Gagliardi 2019-06-08 13:00:30 -04:00
parent e2842bae35
commit 1189877ca5
4 changed files with 194 additions and 5 deletions

162
common/controls.c Normal file
View File

@ -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;
}

View File

@ -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")

View File

@ -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
View File

@ -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);