And implemented uiWindow stuff on Haiku.
This commit is contained in:
parent
218439c215
commit
860eb0fae3
|
@ -0,0 +1,45 @@
|
|||
<!-- 10 june 2019 -->
|
||||
|
||||
# Controls on Haiku
|
||||
|
||||
## Overview
|
||||
|
||||
TODO
|
||||
|
||||
## Reference
|
||||
|
||||
### `uiControlOSVtable`
|
||||
|
||||
```objective-c
|
||||
typedef struct uiControlOSVtable uiControlOSVtable;
|
||||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
void *(*Handle)(uiControl *c, void *implData);
|
||||
};
|
||||
```
|
||||
|
||||
`uiControlOSVtable` describes the set of functions that control implementations on Haiku need to implement. When registering your control type, you pass this in as a parameter to `uiRegisterControlType()`. Each method here is required.
|
||||
|
||||
You are responsible for allocating and initializing this struct. To do so, you simply zero the memory for this struct and set its `Size` field to `sizeof (uiControlOSVtable)`. (TODO put this in a common place)
|
||||
|
||||
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 `uiHaikuControl` 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 `uiHaikuControlHandle()`.
|
||||
|
||||
### `uiHaikuControlHandle()`
|
||||
|
||||
```objective-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.
|
||||
|
||||
`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.
|
||||
|
||||
For all other `uiControl`s defined by libui, the returned object is of the appropriate class:
|
||||
|
||||
* TODO
|
||||
|
||||
It is a programmer error to pass `NULL` for `c`. TODO a non-`uiControl`?
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
TODO
|
||||
|
||||
TODO talk about how each uiControl on Unix should have one GTK+ widget and that GTK+ composite widgets should be used directly for anything more complex
|
||||
|
||||
## Reference
|
||||
|
||||
### `uiControlOSVtable`
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
// 18 january 2020
|
||||
#include "uipriv_haiku.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__))
|
||||
|
||||
void *uiHaikuControlHandle(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));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
libui_sources += [
|
||||
'haiku/controls.cpp',
|
||||
'haiku/main.cpp',
|
||||
'haiku/window.cpp',
|
||||
]
|
||||
|
||||
libui_deps += [
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
// 31 may 2020
|
||||
#include "uipriv_haiku.hpp"
|
||||
|
||||
struct windowImplData {
|
||||
BWindow *window;
|
||||
char *title;
|
||||
};
|
||||
|
||||
static bool windowInit(uiControl *c, void *implData, void *initData)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) implData;
|
||||
|
||||
// TODO figure out what the correct BRect is
|
||||
wi->window = new BWindow(BRect(0, 0, 0, 0), "",
|
||||
B_TITLED_WINDOW,
|
||||
// TODO B_AUTO_UPDATE_SIZE_LIMITS?
|
||||
B_ASYNCHRONOUS_CONTROLS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void windowFree(uiControl *c, void *implData)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) implData;
|
||||
|
||||
if (wi->title != NULL) {
|
||||
uiprivFreeUTF8(wi->title);
|
||||
wi->title = NULL;
|
||||
}
|
||||
delete wi->window;
|
||||
}
|
||||
|
||||
static void windowParentChanging(uiControl *c, void *implData, uiControl *oldParent)
|
||||
{
|
||||
uiprivProgrammerErrorCannotHaveWindowsAsChildren();
|
||||
}
|
||||
|
||||
static void windowParentChanged(uiControl *c, void *implData, uiControl *newParent)
|
||||
{
|
||||
uiprivProgrammerErrorCannotHaveWindowsAsChildren();
|
||||
}
|
||||
|
||||
static void *windowHandle(uiControl *c, void *implData)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) implData;
|
||||
|
||||
return wi->window;
|
||||
}
|
||||
|
||||
// gotta do this because of lack of C99-style initializers in C++11
|
||||
static void windowVtable(uiControlVtable *vt)
|
||||
{
|
||||
vt->Size = sizeof (uiControlVtable);
|
||||
vt->Init = windowInit;
|
||||
vt->Free = windowFree;
|
||||
vt->ParentChanging = windowParentChanging;
|
||||
vt->ParentChanged = windowParentChanged;
|
||||
}
|
||||
|
||||
static void windowOSVtable(uiControlOSVtable *osvt)
|
||||
{
|
||||
osvt->Size = sizeof (uiControlOSVtable);
|
||||
osvt->Handle = windowHandle;
|
||||
}
|
||||
|
||||
static uint32_t windowType = 0;
|
||||
|
||||
uint32_t uiprivSysWindowType(void)
|
||||
{
|
||||
if (windowType == 0) {
|
||||
uiControlVtable vt;
|
||||
uiControlOSVtable osvt;
|
||||
|
||||
windowVtable(&vt);
|
||||
windowOSVtable(&osvt);
|
||||
windowType = uiRegisterControlType("uiWindow", &vt, &osvt, sizeof (struct windowImplData));
|
||||
}
|
||||
return windowType;
|
||||
}
|
||||
|
||||
uiWindow *uiprivSysNewWindow(void)
|
||||
{
|
||||
return (uiWindow *) uiNewControl(uiWindowType(), NULL);
|
||||
}
|
||||
|
||||
const char *uiprivSysWindowTitle(uiWindow *w)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) uiControlImplData(uiControl(w));
|
||||
|
||||
if (wi->title == NULL)
|
||||
// TODO replace this with a dedicated UTF-8 empty string object
|
||||
return "";
|
||||
return wi->title;
|
||||
}
|
||||
|
||||
void uiprivSysWindowSetTitle(uiWindow *w, const char *title)
|
||||
{
|
||||
struct windowImplData *wi = (struct windowImplData *) uiControlImplData(uiControl(w));
|
||||
|
||||
if (wi->title != NULL)
|
||||
uiprivFreeUTF8(wi->title);
|
||||
wi->title = uiprivSanitizeUTF8(title);
|
||||
wi->window->SetTitle(wi->title);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
// 18 january 2020
|
||||
#include "test_haiku.h"
|
||||
|
||||
static const uiControlOSVtable osVtable = {
|
||||
.Size = sizeof (uiControlOSVtable),
|
||||
};
|
||||
|
||||
const uiControlOSVtable *testOSVtable(void)
|
||||
{
|
||||
return &osVtable;
|
||||
}
|
||||
|
||||
Test(WrongControlOSVtableSizeIsProgrammerError)
|
||||
{
|
||||
uiControlVtable vtable;
|
||||
uiControlOSVtable osvt;
|
||||
void *ctx;
|
||||
|
||||
testControlLoadNopVtable(&vtable);
|
||||
ctx = beginCheckProgrammerError("uiRegisterControlType(): wrong size 1 for uiControlOSVtable");
|
||||
memset(&osvt, 0, sizeof (uiControlOSVtable));
|
||||
osvt.Size = 1;
|
||||
uiRegisterControlType("name", &vtable, &osvt, 0);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// 18 january 2020
|
||||
#include "test_haiku.hpp"
|
||||
|
||||
static void *osVtableNopHandle(uiControl *c, void *implData)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uiControlOSVtable osVtable;
|
||||
// gotta do this and not have osVtable be const because C++11
|
||||
bool osVtableInitialized = false;
|
||||
|
||||
const uiControlOSVtable *testOSVtable(void)
|
||||
{
|
||||
if (!osVtableInitialized) {
|
||||
osVtableInitialized = false;
|
||||
osVtable.Size = sizeof (uiControlOSVtable);
|
||||
osVtable.Handle = osVtableNopHandle;
|
||||
}
|
||||
return &osVtable;
|
||||
}
|
||||
|
||||
Test(WrongControlOSVtableSizeIsProgrammerError)
|
||||
{
|
||||
uiControlVtable vtable;
|
||||
uiControlOSVtable osvt;
|
||||
void *ctx;
|
||||
|
||||
testControlLoadNopVtable(&vtable);
|
||||
ctx = beginCheckProgrammerError("uiRegisterControlType(): wrong size 1 for uiControlOSVtable");
|
||||
memset(&osvt, 0, sizeof (uiControlOSVtable));
|
||||
osvt.Size = 1;
|
||||
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");
|
||||
testOSVtable(); // TODO clean this up; it has to do with C++ initialization above
|
||||
osvt = osVtable;
|
||||
osvt.Handle = NULL;
|
||||
uiRegisterControlType("name", &vtable, &osvt, 0);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
||||
|
||||
Test(GettingHaikuHandleOfNullControlIsProgrammerError)
|
||||
{
|
||||
void *ctx;
|
||||
|
||||
ctx = beginCheckProgrammerError("uiHaikuControlHandle(): invalid null pointer for uiControl");
|
||||
uiHaikuControlHandle(NULL);
|
||||
endCheckProgrammerError(ctx);
|
||||
}
|
|
@ -25,7 +25,8 @@ elif libui_OS == 'darwin'
|
|||
])
|
||||
elif libui_OS == 'haiku'
|
||||
libui_test_sources += files([
|
||||
'controls_haiku.c',
|
||||
'controls_haiku.cpp',
|
||||
'window_haiku.cpp',
|
||||
])
|
||||
else
|
||||
libui_test_sources += files([
|
||||
|
@ -79,7 +80,15 @@ elif libui_OS == 'darwin'
|
|||
]
|
||||
endif
|
||||
elif libui_OS == 'haiku'
|
||||
# TODO
|
||||
# static mode already gives us these dependencies
|
||||
if libui_mode != 'static'
|
||||
libui_test_deps += [
|
||||
meson.get_compiler('cpp').find_library('root',
|
||||
required: true),
|
||||
meson.get_compiler('cpp').find_library('be',
|
||||
required: true),
|
||||
]
|
||||
endif
|
||||
else
|
||||
# static mode already gives us these dependencies
|
||||
if libui_mode != 'static'
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// 18 january 2020
|
||||
#define libuiOSHeader "../ui_haiku.h"
|
||||
#include "test.h"
|
|
@ -0,0 +1,8 @@
|
|||
// 18 january 2020
|
||||
// TODO proper macros and headers
|
||||
#include <os/AppKit.h>
|
||||
#include <os/InterfaceKit.h>
|
||||
#include <os/KernelKit.h>
|
||||
#include <os/SupportKit.h>
|
||||
#define libuiOSHeader "../ui_haiku.h"
|
||||
#include "test.h"
|
|
@ -0,0 +1,78 @@
|
|||
// 24 may 2020
|
||||
#include "test_haiku.hpp"
|
||||
|
||||
Test(WindowHasHandleFromStart)
|
||||
{
|
||||
uiWindow *a;
|
||||
|
||||
a = uiNewWindow();
|
||||
if (uiHaikuControlHandle(uiControl(a)) == NULL)
|
||||
TestErrorf("uiUnixControlHandle(brand new uiWindow) is NULL; should not be");
|
||||
uiControlFree(uiControl(a));
|
||||
}
|
||||
|
||||
Test(InitialWindowTitleIsEmptyString_OSLevel)
|
||||
{
|
||||
uiWindow *w;
|
||||
BWindow *bw;
|
||||
const char *title;
|
||||
|
||||
w = uiNewWindow();
|
||||
bw = (BWindow *) uiHaikuControlHandle(uiControl(w));
|
||||
title = bw->Title();
|
||||
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;
|
||||
BWindow *bw;
|
||||
const char *got;
|
||||
|
||||
w = uiNewWindow();
|
||||
uiWindowSetTitle(w, title);
|
||||
bw = (BWindow *) uiHaikuControlHandle(uiControl(w));
|
||||
got = bw->Title();
|
||||
if (!utf8equal(got, want))
|
||||
utf8diffErrorFull(file, line, "gtk_window_get_title() 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,7 +1,7 @@
|
|||
// 12 january 2020
|
||||
|
||||
/*
|
||||
This file assumes that you have included TODO_insert_appropriate_Haiku_headers and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls in Windows.
|
||||
This file assumes that you have included TODO_insert_appropriate_Haiku_headers and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls in Haiku.
|
||||
*/
|
||||
|
||||
#ifndef uiprivIncludeGuard_ui_haiku_h
|
||||
|
@ -13,8 +13,12 @@ extern "C" {
|
|||
|
||||
struct uiControlOSVtable {
|
||||
size_t Size;
|
||||
void *(*Handle)(uiControl *c, void *implData);
|
||||
};
|
||||
|
||||
// TODO return BHandler instead? and NSResponder on Darwin? this depends on how the implementation of this pans out over time
|
||||
uiprivExtern void *uiHaikuControlHandle(uiControl *c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 7 april 2015
|
||||
|
||||
/*
|
||||
This file assumes that you have included <gtk/gtk.h> and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X).
|
||||
This file assumes that you have included <gtk/gtk.h> and "ui.h" beforehand. It provides API-specific functions for interfacing with foreign controls on Unix systems that use GTK+ to provide their UI (currently all except Mac OS X and Haiku).
|
||||
*/
|
||||
|
||||
#ifndef uiprivIncludeGuard_ui_unix_h
|
||||
|
|
Loading…
Reference in New Issue