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:
Pietro Gagliardi 2014-08-04 19:46:49 -04:00
parent 88c01bf695
commit 9ed4ec5259
6 changed files with 148 additions and 33 deletions

84
redo/container_windows.c Normal file
View File

@ -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;
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)
}
}