Finished all the necessary bits to implement what little of uiWindow we have now on Windows. Now to fill in the tests.

This commit is contained in:
Pietro Gagliardi 2020-06-07 14:10:16 -04:00
parent 188d9f736f
commit 7cdd6ee38c
10 changed files with 72 additions and 22 deletions

View File

@ -86,6 +86,7 @@ This function is meant for control implementations to use in the implementation
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. Before calling `Init()`, libui will clear the `implData` memory, as with `memset(0)`. 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.
TODO is this whole spiel about the return value even necessary? shouldn't the outer library be responsible for handling errors instead?
### `uiControlFree()`

View File

@ -28,13 +28,13 @@ Each method is named for the `uiHaikuControl` function that it implements. As su
### `uiHaikuControlHandle()`
```objective-c
```c
uiprivExtern void *uiHaikuControlHandle(uiControl *c);
```
`uiHaikuControlHandle()` returns the Objective-C object that underpins `c`, or `NULL` if `c` does not have any underlying object associated with it when called.
The object returned by `uiDarwinControlHandle()` is owned by `c`; you do not receive a reference to it at all. The object is valid until either `c` is destroyed or until `c` decides to destroy the object; you can handle the latter by catching TODO. In general, you should not store the returned object pointer directly for later use, nor should you attempt to retain the returned object. Instead, use the returned handle immediately if you have to, or follow TODO if you need to adjust properties of the handle that should persist across handle destruction/creation.
The object returned by `uiHaikuControlHandle()` is owned by `c`; you do not receive a reference to it at all. The object is valid until either `c` is destroyed or until `c` decides to destroy the object; you can handle the latter by catching TODO. In general, you should not store the returned object pointer directly for later use. Instead, use the returned handle immediately if you have to, or follow TODO if you need to adjust properties of the handle that should persist across handle destruction/creation.
`uiWindow`s have a single handle of type `BWindow` that is created when the `uiWindow` is created and destroyed when the `uiWindow` is destroyed. Despite this, you should still follow the best practices described above.

View File

@ -14,6 +14,7 @@ TODO
typedef struct uiControlOSVtable uiControlOSVtable;
struct uiControlOSVtable {
size_t Size;
HWND (*Handle)(uiControl *c, void *implData);
};
```
@ -23,4 +24,22 @@ You are responsible for allocating and initializing this struct. To do so, you s
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 `uiWindowsControl` function that it implements. As such, details on how to implement these methods are documented alongside those functions. For instance, instructions on implementing `TODO()` are given under the documentation for `TODO()`.
Each method is named for the `uiWindowsControl` function that it implements. As such, details on how to implement these methods are documented alongside those functions. For instance, instructions on implementing `Handle()` are given under the documentation for `uiWindowsControlHandle()`.
### `uiWindowsControlHandle()`
```c
uiprivExtern HWND uiWindowsControlHandle(uiControl *c);
```
`uiWindowsControlHandle()` returns the window handle that underpins `c`, or `NULL` if `c` does not have any underlying window handle associated with it when called.
The window returned by `uiWindowsControlHandle()` is owned by `c`; you do not receive a reference to it at all. The window is valid until either `c` is destroyed or until `c` decides to destroy the window; you can handle the latter by catching TODO. In general, you should not store the returned window handle directly for later use. Instead, use the returned handle immediately if you have to, or follow TODO if you need to adjust properties of the handle that should persist across handle destruction/creation.
`uiWindow`s have a single window that is created when the `uiWindow` is created and destroyed when the `uiWindow` is destroyed. Despite this, you should still follow the best practices described above. The window is of a special libui-internal window class.
For all other `uiControl`s defined by libui, the returned window is of the appropriate window class:
* TODO
It is a programmer error to pass `NULL` for `c`. TODO a non-`uiControl`?

View File

@ -1,3 +1,5 @@
// 10 june 2019
// TODO proper macros and headers
#include "../windows/winapi.hpp"
#define libuiOSHeader "../ui_windows.h"
#include "test.h"

View File

@ -13,8 +13,11 @@ extern "C" {
struct uiControlOSVtable {
size_t Size;
HWND (*Handle)(uiControl *c, void *implData);
};
uiprivExtern HWND uiWindowsControlHandle(uiControl *c);
#ifdef __cplusplus
}
#endif

View File

@ -1,12 +1,18 @@
// 8 june 2019
#include "uipriv_windows.hpp"
bool uiprivOSVtableValid(const uiControlOSVtable *osVtable, const char *func)
bool uiprivOSVtableValid(const char *name, const uiControlOSVtable *osVtable, const char *func)
{
if (osVtable->Size != sizeof (uiControlOSVtable)) {
uiprivProgrammerErrorWrongStructSize(osVtable->Size, "uiControlOSVtable", func);
return false;
}
#define checkMethod(method) \
if (osVtable->method == NULL) { \
uiprivProgrammerErrorRequiredControlMethodMissing(name, "uiControlOSVtable", #method, func); \
return 0; \
}
checkMethod(Handle)
return true;
}
@ -18,3 +24,19 @@ uiControlOSVtable *uiprivCloneOSVtable(const uiControlOSVtable *osVtable)
*v2 = *osVtable;
return v2;
}
#define callVtable(method, ...) ((*(method))(__VA_ARGS__))
HWND uiWindowsControlHandle(uiControl *c)
{
uiControlOSVtable *osVtable;
if (!uiprivCheckInitializedAndThread())
return NULL;
if (c == NULL) {
uiprivProgrammerErrorNullPointer("uiControl", uiprivFunc);
return NULL;
}
osVtable = uiprivControlOSVtable(c);
return callVtable(osVtable->Handle, c, uiControlImplData(c));
}

View File

@ -1,7 +1,9 @@
// 21 april 2016
#include "uipriv_windows.hpp"
#include "../common/third_party/utf.h"
// TODO clean this up
#define emptyUTF8() ((char *) uiprivAlloc(1 * sizeof (char), "char[]"))
#define emptyUTF16() ((WCHAR *) uiprivAlloc(1 * sizeof (WCHAR), "WCHAR[]"))
WCHAR *uiprivToUTF16(const char *str)

View File

@ -5,7 +5,7 @@
struct windowImplData {
HWND hwnd;
const char *title;
char *title;
#if 0
HMENU menubar;
uiControl *child;
@ -156,18 +156,6 @@ static void uiWindowDestroy(uiControl *c)
uiFreeControl(uiControl(w));
}
uiWindowsControlDefaultHandle(uiWindow)
uiControl *uiWindowParent(uiControl *c)
{
return NULL;
}
void uiWindowSetParent(uiControl *c, uiControl *parent)
{
uiUserBugCannotSetParentOnToplevel("uiWindow");
}
static int uiWindowToplevel(uiControl *c)
{
return 1;
@ -511,7 +499,8 @@ static bool windowInit(uiControl *c, void *implData, void *initData)
NULL, NULL, uipriv_hInstance, c,
&(wi->hwnd));
if (hr != S_OK) {
// TODO
uiprivInternalError("CreateWindowExW() failed in windowInit(): 0x%08I32X", hr);
return true;
}
return true;
@ -520,12 +509,15 @@ static bool windowInit(uiControl *c, void *implData, void *initData)
static void windowFree(uiControl *c, void *implData)
{
struct windowImplData *wi = (struct windowImplData *) implData;
HRESULT hr;
if (wi->title != NULL) {
uiprivFreeUTF8(wi->title);
wi->title = NULL;
}
xxxx
hr = uiprivHrDestroyWindow(wi->hwnd);
if (hr != S_OK)
uiprivInternalError("DestroyWindow() failed in windowFree(): 0x%08I32X", hr);
}
static void windowParentChanging(uiControl *c, void *implData, uiControl *oldParent)
@ -596,6 +588,7 @@ void uiprivSysWindowSetTitle(uiWindow *w, const char *title)
{
struct windowImplData *wi = (struct windowImplData *) uiControlImplData(uiControl(w));
WCHAR *wtitle;
HRESULT hr;
if (wi->title != NULL)
uiprivFreeUTF8(wi->title);
@ -603,9 +596,8 @@ void uiprivSysWindowSetTitle(uiWindow *w, const char *title)
wtitle = uiprivToUTF16(wi->title);
hr = uiprivHrSetWindowTextW(wi->hwnd, wtitle);
uiprivFree(wtitle);
if (hr != S_OK) {
// TODO
}
if (hr != S_OK)
uiprivInternalError("SetWindowTextW() failed in uiWindowSetTitle(): 0x%08I32X", hr);
// don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long)
}

View File

@ -90,3 +90,11 @@ HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text)
return lastErrorToHRESULT();
return S_OK;
}
HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd)
{
SetLastError(0);
if (DestroyWindow(hwnd) == 0)
return lastErrorToHRESULT();
return S_OK;
}

View File

@ -8,3 +8,4 @@ extern HRESULT WINAPI uiprivHrPostMessageW(HWND hwnd, UINT uMsg, WPARAM wParam,
extern HRESULT WINAPI uiprivHrLoadIconW(HINSTANCE hInstance, LPCWSTR name, HICON *hIcon);
extern HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor);
extern HRESULT WINAPI uiprivHrSetWindowTextW(HWND hwnd, LPCWSTR text);
extern HRESULT WINAPI uiprivHrDestroyWindow(HWND hwnd);