Split layout and Window on Windows to use two separate window classes. This is the first half of the two-part migration of the Windows backend to use container.
This commit is contained in:
parent
88c01bf695
commit
9ed4ec5259
|
@ -0,0 +1,84 @@
|
|||
/* 17 july 2014 */
|
||||
|
||||
#include "winapi_windows.h"
|
||||
#include "_cgo_export.h"
|
||||
|
||||
/*
|
||||
This could all just be part of Window, but doing so just makes things complex.
|
||||
In this case, I chose to waste a window handle rather than keep things super complex.
|
||||
If this is seriously an issue in the future, I can roll it back.
|
||||
*/
|
||||
|
||||
#define containerclass L"gouicontainer"
|
||||
|
||||
static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
void *data;
|
||||
RECT r;
|
||||
|
||||
data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||
if (data == NULL) {
|
||||
/* the lpParam is available during WM_NCCREATE and WM_CREATE */
|
||||
if (uMsg == WM_NCCREATE) {
|
||||
storelpParam(hwnd, lParam);
|
||||
data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||
storeContainerHWND(data, hwnd);
|
||||
}
|
||||
/* act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway) */
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_COMMAND:
|
||||
return forwardCommand(hwnd, uMsg, wParam, lParam);
|
||||
case WM_NOTIFY:
|
||||
return forwardNotify(hwnd, uMsg, wParam, lParam);
|
||||
case WM_SIZE:
|
||||
if (GetClientRect(hwnd, &r) == 0)
|
||||
xpanic("error getting client rect for Window in WM_SIZE", GetLastError());
|
||||
containerResize(data, &r);
|
||||
return 0;
|
||||
default:
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
xmissedmsg("container", "containerWndProc()", uMsg);
|
||||
return 0; /* unreached */
|
||||
}
|
||||
|
||||
DWORD makeContainerWindowClass(char **errmsg)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
|
||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||
wc.lpfnWndProc = containerWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = hDefaultIcon;
|
||||
wc.hCursor = hArrowCursor;
|
||||
wc.hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
|
||||
if (wc.hbrBackground == NULL) {
|
||||
*errmsg = "error getting hollow brush for container window class";
|
||||
return GetLastError();
|
||||
}
|
||||
wc.lpszClassName = containerclass;
|
||||
if (RegisterClassW(&wc) == 0) {
|
||||
*errmsg = "error registering container window class";
|
||||
return GetLastError();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWND newContainer(void *data)
|
||||
{
|
||||
HWND hwnd;
|
||||
|
||||
hwnd = CreateWindowExW(
|
||||
0,
|
||||
containerclass, L"",
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
100, 100,
|
||||
msgwin, NULL, hInstance, data);
|
||||
if (hwnd == NULL)
|
||||
xpanic("container creation failed", GetLastError());
|
||||
return hwnd;
|
||||
}
|
|
@ -20,15 +20,23 @@ type layout struct {
|
|||
*sizer
|
||||
}
|
||||
|
||||
func makeContainerWindowClass() error {
|
||||
var errmsg *C.char
|
||||
|
||||
err := C.makeContainerWindowClass(&errmsg)
|
||||
if err != 0 || errmsg != nil {
|
||||
return fmt.Errorf("%s: %v", C.GoString(errmsg), syscall.Errno(err))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newLayout(title string, width int, height int, child C.BOOL, control Control) *layout {
|
||||
l := &layout{
|
||||
// hwnd set in WM_CREATE handler
|
||||
closing: newEvent(),
|
||||
sizer: new(sizer),
|
||||
}
|
||||
hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), child, unsafe.Pointer(l))
|
||||
hwnd := C.newContainer(unsafe.Pointer(l))
|
||||
if hwnd != l.hwnd {
|
||||
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in window/layout (%p) differ", hwnd, l.hwnd))
|
||||
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in container (%p) differ", hwnd, l.hwnd))
|
||||
}
|
||||
l.child = control
|
||||
l.child.setParent(&controlParent{l.hwnd})
|
||||
|
@ -39,24 +47,15 @@ func (l *layout) setParent(p *controlParent) {
|
|||
C.controlSetParent(l.hwnd, p.hwnd)
|
||||
}
|
||||
|
||||
//export storeWindowHWND
|
||||
func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
|
||||
//export storeContainerHWND
|
||||
func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
|
||||
l := (*layout)(data)
|
||||
l.hwnd = hwnd
|
||||
}
|
||||
|
||||
//export windowResize
|
||||
func windowResize(data unsafe.Pointer, r *C.RECT) {
|
||||
//export containerResize
|
||||
func containerResize(data unsafe.Pointer, r *C.RECT) {
|
||||
l := (*layout)(data)
|
||||
// the origin of the window's content area is always (0, 0), but let's use the values from the RECT just to be safe
|
||||
l.resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top))
|
||||
}
|
||||
|
||||
//export windowClosing
|
||||
func windowClosing(data unsafe.Pointer) {
|
||||
l := (*layout)(data)
|
||||
close := l.closing.fire()
|
||||
if close {
|
||||
C.windowClose(l.hwnd)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ func uiinit() error {
|
|||
if err := makeWindowWindowClass(); err != nil {
|
||||
return fmt.Errorf("error creating Window window class: %v", err)
|
||||
}
|
||||
if err := makeContainerWindowClass(); err != nil {
|
||||
return fmt.Errorf("error creating container window class: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ extern LONG controlTextLength(HWND, LPWSTR);
|
|||
|
||||
/* window_windows.c */
|
||||
extern DWORD makeWindowWindowClass(char **);
|
||||
extern HWND newWindow(LPWSTR, int, int, BOOL, void *);
|
||||
extern HWND newWindow(LPWSTR, int, int, void *);
|
||||
extern void windowClose(HWND);
|
||||
|
||||
/* common_windows.c */
|
||||
|
@ -98,4 +98,8 @@ extern void tableAppendColumn(HWND, int, LPWSTR);
|
|||
extern void tableUpdate(HWND, int);
|
||||
extern void tableAddExtendedStyles(HWND, LPARAM);
|
||||
|
||||
/* container_windows.c */
|
||||
extern DWORD makeContainerWindowClass(char **);
|
||||
extern HWND newContainer(void *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -60,29 +60,20 @@ DWORD makeWindowWindowClass(char **errmsg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
HWND newWindow(LPWSTR title, int width, int height, BOOL child, void *data)
|
||||
HWND newWindow(LPWSTR title, int width, int height, void *data)
|
||||
{
|
||||
HWND hwnd;
|
||||
DWORD style;
|
||||
HWND parent;
|
||||
|
||||
style = WS_OVERLAPPEDWINDOW;
|
||||
parent = NULL;
|
||||
if (child) {
|
||||
style = WS_CHILD | WS_VISIBLE;
|
||||
parent = msgwin;
|
||||
}
|
||||
hwnd = CreateWindowExW(
|
||||
0,
|
||||
windowclass, title,
|
||||
style,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
width, height,
|
||||
parent, NULL, hInstance, data);
|
||||
NULL, NULL, hInstance, data);
|
||||
if (hwnd == NULL)
|
||||
xpanic("Window creation failed", GetLastError());
|
||||
if (!child)
|
||||
calculateBaseUnits(hwnd);
|
||||
calculateBaseUnits(hwnd);
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,12 @@ import (
|
|||
import "C"
|
||||
|
||||
type window struct {
|
||||
*layout
|
||||
hwnd C.HWND
|
||||
shownbefore bool
|
||||
|
||||
closing *event
|
||||
|
||||
*layout
|
||||
}
|
||||
|
||||
func makeWindowWindowClass() error {
|
||||
|
@ -27,13 +31,20 @@ func makeWindowWindowClass() error {
|
|||
|
||||
func newWindow(title string, width int, height int, control Control) *window {
|
||||
w := &window{
|
||||
layout: newLayout(title, width, height, C.FALSE, control),
|
||||
// hwnd set in WM_CREATE handler
|
||||
closing: newEvent(),
|
||||
layout: newLayout(control),
|
||||
}
|
||||
hwnd := C.newWindow(toUTF16(title), C.int(width), C.int(height), unsafe.Pointer(w))
|
||||
if hwnd != l.hwnd {
|
||||
panic(fmt.Errorf("inconsistency: hwnd returned by CreateWindowEx() (%p) and hwnd stored in Window (%p) differ", hwnd, w.hwnd))
|
||||
}
|
||||
// TODO keep?
|
||||
hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE | C.ETDT_USETABTEXTURE)
|
||||
if hresult != C.S_OK {
|
||||
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
||||
}
|
||||
w.layout.setParent(&controlParent{w.hwnd})
|
||||
return w
|
||||
}
|
||||
|
||||
|
@ -66,3 +77,26 @@ func (w *window) Close() {
|
|||
func (w *window) OnClosing(e func() bool) {
|
||||
w.closing.setbool(e)
|
||||
}
|
||||
|
||||
//export storeWindowHWND
|
||||
func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
|
||||
w := (*wiindow)(data)
|
||||
w.hwnd = hwnd
|
||||
}
|
||||
|
||||
//export windowResize
|
||||
func windowResize(data unsafe.Pointer, r *C.RECT) {
|
||||
w := (*window)(data)
|
||||
// the origin of the window's content area is always (0, 0), but let's use the values from the RECT just to be safe
|
||||
// TODO
|
||||
C.moveWindow(w.layout.hwnd, int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top))
|
||||
}
|
||||
|
||||
//export windowClosing
|
||||
func windowClosing(data unsafe.Pointer) {
|
||||
l := (*layout)(data)
|
||||
close := l.closing.fire()
|
||||
if close {
|
||||
C.windowClose(l.hwnd)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue