Okay new plan: we're going to start with the Windows implementation instead, since that's the one that's going to have to be more complicated. I'll then decide if we should copy this strategy on the other platforms or not.
This commit is contained in:
parent
69dbafe6f2
commit
f3820ac4b0
|
@ -15,6 +15,8 @@ typedef struct uiControlOSVtable uiControlOSVtable;
|
|||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
HWND (*Handle)(uiControl *c, void *implData);
|
||||
HWND (*ParentHandleForChild)(uiControl *c, void *implData, uiControl *child);
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -43,3 +45,36 @@ For all other `uiControl`s defined by libui, the returned window is of the appro
|
|||
* TODO
|
||||
|
||||
It is a programmer error to pass `NULL` for `c`. TODO a non-`uiControl`?
|
||||
|
||||
**For control implementations**: This function does the above programmer error checks and then calls your `Handle()` method. You do not need to repeat the check yourself.
|
||||
|
||||
### `uiWindowsControlParentHandle()`
|
||||
|
||||
```c
|
||||
uiprivExtern HWND uiWindowsControlParentHandle(uiControl *c);
|
||||
```
|
||||
|
||||
`uiWindowsControlParentHandle()` returns the parent handle for `c`, or `NULL` if there currently is no such handle (either because `c` has no parent control or because none of its parent controls have a handle).
|
||||
|
||||
This is the parent from the point of view of the Windows API. When creating the window handle for a uiControl, this is the handle to use as the `hwndParent`.
|
||||
|
||||
The value returned by this function TODO should not be stored TODO refer to the top of this page for the control model
|
||||
|
||||
It is a programmer error to pass `NULL` for `c`. TODO a non-`uiControl`?
|
||||
|
||||
**For control implementations**: This function does the above programmer error checks; you do not need to repeat the checks yourself.
|
||||
|
||||
Unlike the other functions that operate on a `uiControl`, this function actually calls the `ParentHandleForChild()` method of the *parent control* of `c`, passing `c` as the `child` argument. If your parent control is a container that has window handles to use as the parent handles of its children, you should return the approprpiate window handle. (As an example of a case where knowing the child is important, `uiTab` has a separate parent handle for each of its tab pages.)
|
||||
|
||||
If your parent control is a container that does not have window handles of its own, you should call `uiWindowsControlParentHandle()` on the parent control itself, which will cause libui to chain up until it has reached the top level:
|
||||
|
||||
```c
|
||||
static HWND controlParentHandleForChild(uiControl *c, void *implData, uiControl *child)
|
||||
{
|
||||
return uiWindowsControlParentHandle(c);
|
||||
}
|
||||
```
|
||||
|
||||
If your parent control is not a container, return `NULL`. TODO programmer error?
|
||||
|
||||
As libui ensures that the arguments to `ParentHandleForChild()` are actually related, you do not need to check that `child` is actually your child yourself.
|
||||
|
|
|
@ -21,3 +21,5 @@ allcallsCase(uiWindowType, /* no arguments */)
|
|||
allcallsCase(uiNewWindow, /* no arguments */)
|
||||
allcallsCase(uiWindowTitle, NULL)
|
||||
allcallsCase(uiWindowSetTitle, NULL, NULL)
|
||||
allcallsCase(uiWindowChild, NULL)
|
||||
allcallsCase(uiWindowSetChild, NULL, NULL)
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
// This file should NOT have include guards as it is intended to be included more than once; see noinitwrongthread_windows.c for details.
|
||||
|
||||
allcallsCase(uiWindowsControlHandle, NULL)
|
||||
allcallsCase(uiWindowsControlParentHandle, NULL)
|
||||
|
|
|
@ -6,9 +6,15 @@ static HWND osVtableNopHandle(uiControl *c, void *implData)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static HWND osVtableNopParentHandleForChild(uiControl *c, void *implData, uiControl *child)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uiControlOSVtable osVtable = {
|
||||
.Size = sizeof (uiControlOSVtable),
|
||||
.Handle = osVtableNopHandle,
|
||||
.ParentHandleForChild = osVtableNopParentHandleForChild,
|
||||
};
|
||||
|
||||
const uiControlOSVtable *testOSVtable(void)
|
||||
|
@ -44,6 +50,20 @@ Test(ControlOSVtableWithMissingHandleMethodIsProgrammerError)
|
|||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
||||
Test(ControlOSVtableWithMissingParentHandleForChildMethodIsProgrammerError)
|
||||
{
|
||||
uiControlVtable vtable;
|
||||
uiControlOSVtable osvt;
|
||||
void *ctx;
|
||||
|
||||
testControlLoadNopVtable(&vtable);
|
||||
ctx = beginCheckProgrammerError("uiRegisterControlType(): required uiControlOSVtable method ParentHandleForChild() missing for uiControl type name");
|
||||
osvt = osVtable;
|
||||
osvt.ParentHandleForChild = NULL;
|
||||
uiRegisterControlType("name", &vtable, &osvt, 0);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
||||
Test(GettingWindowsHandleOfNullControlIsProgrammerError)
|
||||
{
|
||||
void *ctx;
|
||||
|
@ -52,3 +72,12 @@ Test(GettingWindowsHandleOfNullControlIsProgrammerError)
|
|||
uiWindowsControlHandle(NULL);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
||||
Test(GettingWindowsParentHandleOfNullControlIsProgrammerError)
|
||||
{
|
||||
void *ctx;
|
||||
|
||||
ctx = beginCheckProgrammerError("uiWindowsControlHandle(): invalid null pointer for uiControl");
|
||||
uiWindowsControlParentHandle(NULL);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ extern "C" {
|
|||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
HWND (*Handle)(uiControl *c, void *implData);
|
||||
HWND (*ParentHandleForChild)(uiControl *c, void *implData, uiControl *child);
|
||||
};
|
||||
|
||||
uiprivExtern HWND uiWindowsControlHandle(uiControl *c);
|
||||
uiprivExtern HWND uiWindowsControlParentHandle(uiControl *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ bool uiprivOSVtableValid(const char *name, const uiControlOSVtable *osVtable, co
|
|||
return 0; \
|
||||
}
|
||||
checkMethod(Handle)
|
||||
checkMethod(ParentHandleForChild)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -40,3 +41,21 @@ HWND uiWindowsControlHandle(uiControl *c)
|
|||
osVtable = uiprivControlOSVtable(c);
|
||||
return callVtable(osVtable->Handle, c, uiControlImplData(c));
|
||||
}
|
||||
|
||||
HWND uiWindowsControlParentHandle(uiControl *c)
|
||||
{
|
||||
uiControl *parent;
|
||||
uiControlOSVtable *parentVtable;
|
||||
|
||||
if (!uiprivCheckInitializedAndThread())
|
||||
return NULL;
|
||||
if (c == NULL) {
|
||||
uiprivProgrammerErrorNullPointer("uiControl", uiprivFunc);
|
||||
return NULL;
|
||||
}
|
||||
parent = uiControlParent(c);
|
||||
if (parent == NULL)
|
||||
return NULL;
|
||||
parentVtable = uiprivControlOSVtable(parent);
|
||||
return callVtable(parentVtable->ParentHandleForChild, parent, uiControlImplData(parent), c);
|
||||
}
|
||||
|
|
|
@ -537,6 +537,14 @@ static HWND windowHandle(uiControl *c, void *implData)
|
|||
return wi->hwnd;
|
||||
}
|
||||
|
||||
static HWND windowParentHandleForChild(uiControl *c, void *implData, uiControl *child)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) implData;
|
||||
|
||||
// In this case, we have a fixed handle for the entire lifetime of the uiWindow that should be used as the parent.
|
||||
return wi->hwnd;
|
||||
}
|
||||
|
||||
// gotta do this because of lack of C99-style initializers in C++11
|
||||
// see also https://stackoverflow.com/questions/11516657/c-structure-initialization
|
||||
static const uiControlVtable windowVtable = [](void) {
|
||||
|
@ -557,6 +565,7 @@ static const uiControlOSVtable windowOSVtable = [](void) {
|
|||
memset(&vt, 0, sizeof (uiControlOSVtable));
|
||||
vt.Size = sizeof (uiControlOSVtable);
|
||||
vt.Handle = windowHandle;
|
||||
vt.ParentHandleForChild = windowParentHandleForChild;
|
||||
return vt;
|
||||
}();
|
||||
|
||||
|
|
Loading…
Reference in New Issue