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
|
*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 {
|
func newLayout(title string, width int, height int, child C.BOOL, control Control) *layout {
|
||||||
l := &layout{
|
l := &layout{
|
||||||
// hwnd set in WM_CREATE handler
|
|
||||||
closing: newEvent(),
|
|
||||||
sizer: new(sizer),
|
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 {
|
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 = control
|
||||||
l.child.setParent(&controlParent{l.hwnd})
|
l.child.setParent(&controlParent{l.hwnd})
|
||||||
|
@ -39,24 +47,15 @@ func (l *layout) setParent(p *controlParent) {
|
||||||
C.controlSetParent(l.hwnd, p.hwnd)
|
C.controlSetParent(l.hwnd, p.hwnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export storeWindowHWND
|
//export storeContainerHWND
|
||||||
func storeWindowHWND(data unsafe.Pointer, hwnd C.HWND) {
|
func storeContainerHWND(data unsafe.Pointer, hwnd C.HWND) {
|
||||||
l := (*layout)(data)
|
l := (*layout)(data)
|
||||||
l.hwnd = hwnd
|
l.hwnd = hwnd
|
||||||
}
|
}
|
||||||
|
|
||||||
//export windowResize
|
//export containerResize
|
||||||
func windowResize(data unsafe.Pointer, r *C.RECT) {
|
func containerResize(data unsafe.Pointer, r *C.RECT) {
|
||||||
l := (*layout)(data)
|
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
|
// 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))
|
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 {
|
if err := makeWindowWindowClass(); err != nil {
|
||||||
return fmt.Errorf("error creating Window window class: %v", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ extern LONG controlTextLength(HWND, LPWSTR);
|
||||||
|
|
||||||
/* window_windows.c */
|
/* window_windows.c */
|
||||||
extern DWORD makeWindowWindowClass(char **);
|
extern DWORD makeWindowWindowClass(char **);
|
||||||
extern HWND newWindow(LPWSTR, int, int, BOOL, void *);
|
extern HWND newWindow(LPWSTR, int, int, void *);
|
||||||
extern void windowClose(HWND);
|
extern void windowClose(HWND);
|
||||||
|
|
||||||
/* common_windows.c */
|
/* common_windows.c */
|
||||||
|
@ -98,4 +98,8 @@ extern void tableAppendColumn(HWND, int, LPWSTR);
|
||||||
extern void tableUpdate(HWND, int);
|
extern void tableUpdate(HWND, int);
|
||||||
extern void tableAddExtendedStyles(HWND, LPARAM);
|
extern void tableAddExtendedStyles(HWND, LPARAM);
|
||||||
|
|
||||||
|
/* container_windows.c */
|
||||||
|
extern DWORD makeContainerWindowClass(char **);
|
||||||
|
extern HWND newContainer(void *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -60,29 +60,20 @@ DWORD makeWindowWindowClass(char **errmsg)
|
||||||
return 0;
|
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;
|
HWND hwnd;
|
||||||
DWORD style;
|
|
||||||
HWND parent;
|
|
||||||
|
|
||||||
style = WS_OVERLAPPEDWINDOW;
|
|
||||||
parent = NULL;
|
|
||||||
if (child) {
|
|
||||||
style = WS_CHILD | WS_VISIBLE;
|
|
||||||
parent = msgwin;
|
|
||||||
}
|
|
||||||
hwnd = CreateWindowExW(
|
hwnd = CreateWindowExW(
|
||||||
0,
|
0,
|
||||||
windowclass, title,
|
windowclass, title,
|
||||||
style,
|
WS_OVERLAPPEDWINDOW,
|
||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
width, height,
|
width, height,
|
||||||
parent, NULL, hInstance, data);
|
NULL, NULL, hInstance, data);
|
||||||
if (hwnd == NULL)
|
if (hwnd == NULL)
|
||||||
xpanic("Window creation failed", GetLastError());
|
xpanic("Window creation failed", GetLastError());
|
||||||
if (!child)
|
calculateBaseUnits(hwnd);
|
||||||
calculateBaseUnits(hwnd);
|
|
||||||
return hwnd;
|
return hwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,12 @@ import (
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type window struct {
|
type window struct {
|
||||||
*layout
|
hwnd C.HWND
|
||||||
shownbefore bool
|
shownbefore bool
|
||||||
|
|
||||||
|
closing *event
|
||||||
|
|
||||||
|
*layout
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeWindowWindowClass() error {
|
func makeWindowWindowClass() error {
|
||||||
|
@ -27,13 +31,20 @@ func makeWindowWindowClass() error {
|
||||||
|
|
||||||
func newWindow(title string, width int, height int, control Control) *window {
|
func newWindow(title string, width int, height int, control Control) *window {
|
||||||
w := &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?
|
// TODO keep?
|
||||||
hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE | C.ETDT_USETABTEXTURE)
|
hresult := C.EnableThemeDialogTexture(w.hwnd, C.ETDT_ENABLE | C.ETDT_USETABTEXTURE)
|
||||||
if hresult != C.S_OK {
|
if hresult != C.S_OK {
|
||||||
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
panic(fmt.Errorf("error setting tab background texture on Window; HRESULT: 0x%X", hresult))
|
||||||
}
|
}
|
||||||
|
w.layout.setParent(&controlParent{w.hwnd})
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,3 +77,26 @@ func (w *window) Close() {
|
||||||
func (w *window) OnClosing(e func() bool) {
|
func (w *window) OnClosing(e func() bool) {
|
||||||
w.closing.setbool(e)
|
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