Added uiDarwinControlHandle(), and added it to uiWindow, and added uiWindow handle tests (including underlying string tests) to the test suite. Oof. Also I just remembered we're missing tests of these new functions in noinitwrongthread.c.
This commit is contained in:
parent
16d2380adc
commit
0dd4bec2af
|
@ -75,7 +75,7 @@ uint32_t uiRegisterControlType(const char *name, const uiControlVtable *vtable,
|
|||
uiprivProgrammerErrorNullPointer("uiControlOSVtable", uiprivFunc);
|
||||
return 0;
|
||||
}
|
||||
if (!uiprivOSVtableValid(osVtable, uiprivFunc))
|
||||
if (!uiprivOSVtableValid(name, osVtable, uiprivFunc))
|
||||
return 0;
|
||||
|
||||
ct = (struct controlType *) uiprivArrayAppend(&controlTypes, 1);
|
||||
|
@ -259,6 +259,11 @@ void *uiControlImplData(uiControl *c)
|
|||
return c->implData;
|
||||
}
|
||||
|
||||
uiControlOSVtable *uiprivControlOSVtable(uiControl *c)
|
||||
{
|
||||
return c->type->osVtable;
|
||||
}
|
||||
|
||||
static uiControl testHookControlWithInvalidControlMarker = {
|
||||
// use something other than 0 here to make it look like accidental real data
|
||||
.controlID = UINT32_C(0x5A5A5A5A),
|
||||
|
|
|
@ -73,8 +73,9 @@ uiprivPrintfFunc(
|
|||
extern void uiprivReportError(const char *prefix, const char *msg, const char *suffix, bool internal);
|
||||
|
||||
// controls.c
|
||||
extern bool uiprivOSVtableValid(const uiControlOSVtable *osVtable, const char *func);
|
||||
extern bool uiprivOSVtableValid(const char *name, const uiControlOSVtable *osVtable, const char *func);
|
||||
extern uiControlOSVtable *uiprivCloneOSVtable(const uiControlOSVtable *osVtable);
|
||||
extern uiControlOSVtable *uiprivControlOSVtable(uiControl *c);
|
||||
|
||||
// utf8.c
|
||||
extern char *uiprivSanitizeUTF8(const char *str);
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
// 8 june 2019
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
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__))
|
||||
|
||||
id uiDarwinControlHandle(uiControl *c)
|
||||
{
|
||||
uiControlOSVtable *osVtable;
|
||||
|
||||
if (!uiprivCheckInitializedAndThread())
|
||||
return nil;
|
||||
if (c == NULL) {
|
||||
uiprivProgrammerErrorNullPointer("uiControl", uiprivFunc);
|
||||
return nil;
|
||||
}
|
||||
osVtable = uiprivControlOSVtable(c);
|
||||
return callVtable(osVtable->Handle, c, uiControlImplData(c));
|
||||
}
|
||||
|
|
|
@ -415,6 +415,13 @@ static void windowParentChanged(uiControl *c, void *implData, uiControl *newPare
|
|||
uiprivProgrammerErrorCannotHaveWindowsAsChildren();
|
||||
}
|
||||
|
||||
static id windowHandle(uiControl *c, void *implData)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) implData;
|
||||
|
||||
return wi->window;
|
||||
}
|
||||
|
||||
static const uiControlVtable windowVtable = {
|
||||
.Size = sizeof (uiControlVtable),
|
||||
.Init = windowInit,
|
||||
|
@ -425,6 +432,7 @@ static const uiControlVtable windowVtable = {
|
|||
|
||||
static const uiControlOSVtable windowOSVtable = {
|
||||
.Size = sizeof (uiControlOSVtable),
|
||||
.Handle = windowHandle,
|
||||
};
|
||||
|
||||
static uint32_t windowType = 0;
|
||||
|
|
|
@ -10,10 +10,11 @@ TODO
|
|||
|
||||
### `uiControlOSVtable`
|
||||
|
||||
```c
|
||||
```objective-c
|
||||
typedef struct uiControlOSVtable uiControlOSVtable;
|
||||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
id (*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 `uiDarwinControl` 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 `uiDarwinControl` 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 `uiDarwinControlHandle()`.
|
||||
|
||||
### `uiDarwinControlHandle()`
|
||||
|
||||
```objective-c
|
||||
uiprivExtern NSView *uiDarwinControlHandle(uiControl *c);
|
||||
```
|
||||
|
||||
`uiDarwinControlHandle()` returns the Objective-C object that underpins `c`, or `nil` 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 string 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.
|
||||
|
||||
`uiWindow`s have a single handle of type `NSWindow` 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.
|
||||
|
||||
For all other `uiControl`s defined by libui, the returned object is of the appropriate `NSView` subclass:
|
||||
|
||||
* TODO
|
||||
|
||||
TODO invalid value for c
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
// 10 june 2019
|
||||
#import "test_darwin.h"
|
||||
|
||||
static id osVtableNopHandle(uiControl *c, void *implData)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
static const uiControlOSVtable osVtable = {
|
||||
.Size = sizeof (uiControlOSVtable),
|
||||
.Handle = osVtableNopHandle,
|
||||
};
|
||||
|
||||
const uiControlOSVtable *testOSVtable(void)
|
||||
|
@ -23,3 +29,17 @@ Test(WrongControlOSVtableSizeIsProgrammerError)
|
|||
uiRegisterControlType("name", &vtable, &osvt, 0);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
||||
Test(ControlOSVtableWithMissingHandleMethodIsProgrammerError)
|
||||
{
|
||||
uiControlVtable vtable;
|
||||
uiControlOSVtable osvt;
|
||||
void *ctx;
|
||||
|
||||
testControlLoadNopVtable(&vtable);
|
||||
ctx = beginCheckProgrammerError("uiRegisterControlType(): required uiControlOSVtable method Handle() missing for uiControl type name");
|
||||
osvt = osVtable;
|
||||
osvt.Handle = NULL;
|
||||
uiRegisterControlType("name", &vtable, &osvt, 0);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ if libui_OS == 'windows'
|
|||
elif libui_OS == 'darwin'
|
||||
libui_test_sources += files([
|
||||
'controls_darwin.m',
|
||||
'window_darwin.m',
|
||||
])
|
||||
elif libui_OS == 'haiku'
|
||||
libui_test_sources += files([
|
||||
|
@ -50,6 +51,7 @@ libui_test_deps = [
|
|||
dependency('threads',
|
||||
required: true),
|
||||
]
|
||||
# TODO deduplicate these
|
||||
if libui_OS == 'windows'
|
||||
# static mode already gives us these dependencies
|
||||
if libui_mode != 'static'
|
||||
|
@ -60,6 +62,17 @@ if libui_OS == 'windows'
|
|||
required: true),
|
||||
]
|
||||
endif
|
||||
elif libui_OS == 'darwin'
|
||||
# static mode already gives us these dependencies
|
||||
if libui_mode != 'static'
|
||||
libui_test_deps += [
|
||||
meson.get_compiler('objc').find_library('objc',
|
||||
required: true),
|
||||
dependency('appleframeworks',
|
||||
modules: ['Foundation', 'AppKit'],
|
||||
required: true),
|
||||
]
|
||||
endif
|
||||
endif
|
||||
|
||||
pymod = import('python')
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// 10 june 2019
|
||||
// TODO proper macros and headers
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#define libuiOSHeader "../ui_darwin.h"
|
||||
#include "test.h"
|
||||
#import "test.h"
|
||||
|
|
|
@ -80,5 +80,3 @@ Test(SetWindowTitle_Invalid)
|
|||
{
|
||||
testSetWindowTitleImpl(testUTF8InvalidInput, testUTF8InvalidOutput);
|
||||
}
|
||||
|
||||
// TODO for all the above, check that the underlying OS-level title was also set appropriately
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// 24 may 2020
|
||||
#import "test_darwin.h"
|
||||
|
||||
Test(WindowHasHandleFromStart)
|
||||
{
|
||||
uiWindow *a;
|
||||
|
||||
a = uiNewWindow();
|
||||
if (uiDarwinControlHandle(uiControl(a)) == nil)
|
||||
TestErrorf("uiDarwinControlHandle(brand new uiWindow) is nil; should not be");
|
||||
uiControlFree(uiControl(a));
|
||||
}
|
||||
|
||||
Test(InitialWindowTitleIsEmptyString_OSLevel)
|
||||
{
|
||||
uiWindow *w;
|
||||
NSWindow *nsw;
|
||||
const char *title;
|
||||
|
||||
w = uiNewWindow();
|
||||
nsw = (NSWindow *) uiDarwinControlHandle(uiControl(w));
|
||||
title = [[nsw title] UTF8String];
|
||||
if (!utf8equal(title, testUTF8Empty))
|
||||
utf8diffError("brand new uiWindow has wrong title", title, testUTF8Empty);
|
||||
uiControlFree(uiControl(w));
|
||||
}
|
||||
|
||||
static void testSetWindowTitleImplFull(const char *file, long line, const char *title, const char *want)
|
||||
{
|
||||
uiWindow *w;
|
||||
NSWindow *nsw;
|
||||
const char *got;
|
||||
|
||||
w = uiNewWindow();
|
||||
uiWindowSetTitle(w, title);
|
||||
nsw = (NSWindow *) uiDarwinControlHandle(uiControl(w));
|
||||
got = [[nsw title] UTF8String];
|
||||
if (!utf8equal(got, want))
|
||||
utf8diffErrorFull(file, line, "uiWindowTitle() reported wrong title after uiWindowSetTitle()", got, want);
|
||||
uiControlFree(uiControl(w));
|
||||
}
|
||||
|
||||
#define testSetWindowTitleImpl(title, want) testSetWindowTitleImplFull(__FILE__, __LINE__, title, want)
|
||||
|
||||
Test(SetWindowTitle_OSLevel_Empty)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8Empty, testUTF8Empty);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_ASCIIOnly)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8ASCIIOnly, testUTF8ASCIIOnly);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_WithTwoByte)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8WithTwoByte, testUTF8WithTwoByte);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_WithThreeByte)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8WithThreeByte, testUTF8WithThreeByte);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_WithFourByte)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8WithFourByte, testUTF8WithFourByte);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_Combined)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8Combined, testUTF8Combined);
|
||||
}
|
||||
|
||||
Test(SetWindowTitle_OSLevel_Invalid)
|
||||
{
|
||||
testSetWindowTitleImpl(testUTF8InvalidInput, testUTF8InvalidOutput);
|
||||
}
|
1
ui.h
1
ui.h
|
@ -69,6 +69,7 @@ uiprivExtern void *uiControlImplData(uiControl *c);
|
|||
typedef uiControl uiWindow;
|
||||
uiprivExtern uint32_t uiWindowType(void);
|
||||
#define uiWindow(obj) ((uiWindow *) uiCheckControlType((obj), uiWindowType()))
|
||||
// TODO provide events for window close button clicked
|
||||
|
||||
uiprivExtern uiWindow *uiNewWindow(void);
|
||||
uiprivExtern const char *uiWindowTitle(uiWindow *w);
|
||||
|
|
|
@ -13,8 +13,12 @@ extern "C" {
|
|||
|
||||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
id (*Handle)(uiControl *c, void *implData);
|
||||
// TODO provide events for handle creation and destruction
|
||||
};
|
||||
|
||||
uiprivExtern id uiDarwinControlHandle(uiControl *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue