Changed Areas on WIndows so that they all use the same window class, rather than having one per Area.
This commit is contained in:
parent
855a09656a
commit
2e0914e575
245
area_windows.go
245
area_windows.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"sync"
|
|
||||||
"image"
|
"image"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,12 +15,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
areaWndClassFormat = "gouiarea%X"
|
areaWndClass = "gouiarea"
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
areaWndClassNum uintptr
|
|
||||||
areaWndClassNumLock sync.Mutex
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getScrollPos(hwnd _HWND) (xpos int32, ypos int32) {
|
func getScrollPos(hwnd _HWND) (xpos int32, ypos int32) {
|
||||||
|
@ -604,143 +598,128 @@ var (
|
||||||
_setFocus = user32.NewProc("SetFocus")
|
_setFocus = user32.NewProc("SetFocus")
|
||||||
)
|
)
|
||||||
|
|
||||||
func areaWndProc(unused *sysData) func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT {
|
func areaWndProc(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT {
|
||||||
return func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM) _LRESULT {
|
s := getSysData(hwnd)
|
||||||
s := getSysData(hwnd)
|
if s == nil { // not yet saved
|
||||||
if s == nil { // not yet saved
|
return storeSysData(hwnd, uMsg, wParam, lParam)
|
||||||
return storeSysData(hwnd, uMsg, wParam, lParam)
|
|
||||||
}
|
|
||||||
switch uMsg {
|
|
||||||
case _WM_PAINT:
|
|
||||||
paintArea(s)
|
|
||||||
return 0
|
|
||||||
case _WM_ERASEBKGND:
|
|
||||||
// don't draw a background; we'll do so when painting
|
|
||||||
// this is to make things flicker-free; see http://msdn.microsoft.com/en-us/library/ms969905.aspx
|
|
||||||
return 1
|
|
||||||
case _WM_HSCROLL:
|
|
||||||
// TODO make this unnecessary
|
|
||||||
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
|
||||||
scrollArea(s, wParam, _SB_HORZ)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
case _WM_VSCROLL:
|
|
||||||
// TODO make this unnecessary
|
|
||||||
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
|
||||||
scrollArea(s, wParam, _SB_VERT)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
case _WM_SIZE:
|
|
||||||
// TODO make this unnecessary
|
|
||||||
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
|
||||||
adjustAreaScrollbars(s)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
case _WM_ACTIVATE:
|
|
||||||
// don't keep the double-click timer running if the user switched programs in between clicks
|
|
||||||
s.clickCounter.reset()
|
|
||||||
return 0
|
|
||||||
case _WM_MOUSEACTIVATE:
|
|
||||||
// this happens on every mouse click (apparently), so DON'T reset the click counter, otherwise it will always be reset (not an issue, as MSDN says WM_ACTIVATE is sent alongside WM_MOUSEACTIVATE when necessary)
|
|
||||||
// transfer keyboard focus to our Area on an activating click
|
|
||||||
// (see http://www.catch22.net/tuts/custom-controls)
|
|
||||||
r1, _, err := _setFocus.Call(uintptr(s.hwnd))
|
|
||||||
if r1 == 0 { // failure
|
|
||||||
panic(fmt.Errorf("error giving Area keyboard focus: %v", err))
|
|
||||||
return _MA_ACTIVATE // TODO eat the click?
|
|
||||||
}
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
case _WM_MOUSEMOVE:
|
|
||||||
areaMouseEvent(s, 0, false, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_LBUTTONDOWN:
|
|
||||||
areaMouseEvent(s, 1, false, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_LBUTTONUP:
|
|
||||||
areaMouseEvent(s, 1, true, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_MBUTTONDOWN:
|
|
||||||
areaMouseEvent(s, 2, false, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_MBUTTONUP:
|
|
||||||
areaMouseEvent(s, 2, true, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_RBUTTONDOWN:
|
|
||||||
areaMouseEvent(s, 3, false, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_RBUTTONUP:
|
|
||||||
areaMouseEvent(s, 3, true, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_XBUTTONDOWN:
|
|
||||||
which := uint((wParam >> 16) & 0xFFFF) + 3 // values start at 1; we want them to start at 4
|
|
||||||
areaMouseEvent(s, which, false, wParam, lParam)
|
|
||||||
return _LRESULT(_TRUE) // XBUTTON messages are different!
|
|
||||||
case _WM_XBUTTONUP:
|
|
||||||
which := uint((wParam >> 16) & 0xFFFF) + 3
|
|
||||||
areaMouseEvent(s, which, true, wParam, lParam)
|
|
||||||
return _LRESULT(_TRUE)
|
|
||||||
case _WM_KEYDOWN:
|
|
||||||
areaKeyEvent(s, false, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
case _WM_KEYUP:
|
|
||||||
areaKeyEvent(s, true, wParam, lParam)
|
|
||||||
return 0
|
|
||||||
// Alt+[anything] and F10 send these instead
|
|
||||||
case _WM_SYSKEYDOWN:
|
|
||||||
handled := areaKeyEvent(s, false, wParam, lParam)
|
|
||||||
if handled {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
case _WM_SYSKEYUP:
|
|
||||||
handled := areaKeyEvent(s, true, wParam, lParam)
|
|
||||||
if handled {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
case msgSetAreaSize:
|
|
||||||
s.areawidth = int(wParam) // see setAreaSize() in sysdata_windows.go
|
|
||||||
s.areaheight = int(lParam)
|
|
||||||
adjustAreaScrollbars(s)
|
|
||||||
repaintArea(s) // this calls for an update
|
|
||||||
return 0
|
|
||||||
default:
|
|
||||||
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
|
||||||
}
|
|
||||||
panic(fmt.Sprintf("areaWndProc message %d did not return: internal bug in ui library", uMsg))
|
|
||||||
}
|
}
|
||||||
|
switch uMsg {
|
||||||
|
case _WM_PAINT:
|
||||||
|
paintArea(s)
|
||||||
|
return 0
|
||||||
|
case _WM_ERASEBKGND:
|
||||||
|
// don't draw a background; we'll do so when painting
|
||||||
|
// this is to make things flicker-free; see http://msdn.microsoft.com/en-us/library/ms969905.aspx
|
||||||
|
return 1
|
||||||
|
case _WM_HSCROLL:
|
||||||
|
// TODO make this unnecessary
|
||||||
|
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
||||||
|
scrollArea(s, wParam, _SB_HORZ)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case _WM_VSCROLL:
|
||||||
|
// TODO make this unnecessary
|
||||||
|
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
||||||
|
scrollArea(s, wParam, _SB_VERT)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
case _WM_SIZE:
|
||||||
|
// TODO make this unnecessary
|
||||||
|
if s != nil && s.hwnd != 0 { // this message can be sent before s is assigned properly
|
||||||
|
adjustAreaScrollbars(s)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
case _WM_ACTIVATE:
|
||||||
|
// don't keep the double-click timer running if the user switched programs in between clicks
|
||||||
|
s.clickCounter.reset()
|
||||||
|
return 0
|
||||||
|
case _WM_MOUSEACTIVATE:
|
||||||
|
// this happens on every mouse click (apparently), so DON'T reset the click counter, otherwise it will always be reset (not an issue, as MSDN says WM_ACTIVATE is sent alongside WM_MOUSEACTIVATE when necessary)
|
||||||
|
// transfer keyboard focus to our Area on an activating click
|
||||||
|
// (see http://www.catch22.net/tuts/custom-controls)
|
||||||
|
r1, _, err := _setFocus.Call(uintptr(s.hwnd))
|
||||||
|
if r1 == 0 { // failure
|
||||||
|
panic(fmt.Errorf("error giving Area keyboard focus: %v", err))
|
||||||
|
return _MA_ACTIVATE // TODO eat the click?
|
||||||
|
}
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
case _WM_MOUSEMOVE:
|
||||||
|
areaMouseEvent(s, 0, false, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_LBUTTONDOWN:
|
||||||
|
areaMouseEvent(s, 1, false, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_LBUTTONUP:
|
||||||
|
areaMouseEvent(s, 1, true, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_MBUTTONDOWN:
|
||||||
|
areaMouseEvent(s, 2, false, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_MBUTTONUP:
|
||||||
|
areaMouseEvent(s, 2, true, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_RBUTTONDOWN:
|
||||||
|
areaMouseEvent(s, 3, false, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_RBUTTONUP:
|
||||||
|
areaMouseEvent(s, 3, true, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_XBUTTONDOWN:
|
||||||
|
which := uint((wParam >> 16) & 0xFFFF) + 3 // values start at 1; we want them to start at 4
|
||||||
|
areaMouseEvent(s, which, false, wParam, lParam)
|
||||||
|
return _LRESULT(_TRUE) // XBUTTON messages are different!
|
||||||
|
case _WM_XBUTTONUP:
|
||||||
|
which := uint((wParam >> 16) & 0xFFFF) + 3
|
||||||
|
areaMouseEvent(s, which, true, wParam, lParam)
|
||||||
|
return _LRESULT(_TRUE)
|
||||||
|
case _WM_KEYDOWN:
|
||||||
|
areaKeyEvent(s, false, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
case _WM_KEYUP:
|
||||||
|
areaKeyEvent(s, true, wParam, lParam)
|
||||||
|
return 0
|
||||||
|
// Alt+[anything] and F10 send these instead
|
||||||
|
case _WM_SYSKEYDOWN:
|
||||||
|
handled := areaKeyEvent(s, false, wParam, lParam)
|
||||||
|
if handled {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
case _WM_SYSKEYUP:
|
||||||
|
handled := areaKeyEvent(s, true, wParam, lParam)
|
||||||
|
if handled {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
case msgSetAreaSize:
|
||||||
|
s.areawidth = int(wParam) // see setAreaSize() in sysdata_windows.go
|
||||||
|
s.areaheight = int(lParam)
|
||||||
|
adjustAreaScrollbars(s)
|
||||||
|
repaintArea(s) // this calls for an update
|
||||||
|
return 0
|
||||||
|
default:
|
||||||
|
return defWindowProc(hwnd, uMsg, wParam, lParam)
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("areaWndProc message %d did not return: internal bug in ui library", uMsg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerAreaWndClass(s *sysData) (newClassName string, err error) {
|
func registerAreaWndClass() (err error) {
|
||||||
areaWndClassNumLock.Lock()
|
|
||||||
newClassName = fmt.Sprintf(areaWndClassFormat, areaWndClassNum)
|
|
||||||
areaWndClassNum++
|
|
||||||
areaWndClassNumLock.Unlock()
|
|
||||||
|
|
||||||
wc := &_WNDCLASS{
|
wc := &_WNDCLASS{
|
||||||
style: _CS_HREDRAW | _CS_VREDRAW, // no CS_DBLCLKS because do that manually
|
style: _CS_HREDRAW | _CS_VREDRAW, // no CS_DBLCLKS because do that manually
|
||||||
lpszClassName: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(newClassName))),
|
lpszClassName: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(areaWndClass))),
|
||||||
lpfnWndProc: syscall.NewCallback(areaWndProc(s)),
|
lpfnWndProc: syscall.NewCallback(areaWndProc),
|
||||||
hInstance: hInstance,
|
hInstance: hInstance,
|
||||||
hIcon: icon,
|
hIcon: icon,
|
||||||
hCursor: cursor,
|
hCursor: cursor,
|
||||||
hbrBackground: _HBRUSH(_NULL), // no brush; we handle WM_ERASEBKGND
|
hbrBackground: _HBRUSH(_NULL), // no brush; we handle WM_ERASEBKGND
|
||||||
}
|
}
|
||||||
|
r1, _, err := _registerClass.Call(uintptr(unsafe.Pointer(wc)))
|
||||||
ret := make(chan uiret)
|
if r1 == 0 { // failure
|
||||||
defer close(ret)
|
return err
|
||||||
uitask <- &uimsg{
|
|
||||||
call: _registerClass,
|
|
||||||
p: []uintptr{uintptr(unsafe.Pointer(wc))},
|
|
||||||
ret: ret,
|
|
||||||
}
|
}
|
||||||
r := <-ret
|
return nil
|
||||||
if r.ret == 0 { // failure
|
|
||||||
return "", r.err
|
|
||||||
}
|
|
||||||
return newClassName, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type _BITMAPINFO struct {
|
type _BITMAPINFO struct {
|
||||||
|
|
|
@ -69,6 +69,10 @@ func doWindowsInit() (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error registering standard window class (for Window): %v", err)
|
return fmt.Errorf("error registering standard window class (for Window): %v", err)
|
||||||
}
|
}
|
||||||
|
err = registerAreaWndClass()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error registering Area window class: %v", err)
|
||||||
|
}
|
||||||
err = getStandardWindowFonts()
|
err = getStandardWindowFonts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting standard window fonts: %v", err)
|
return fmt.Errorf("error getting standard window fonts: %v", err)
|
||||||
|
|
|
@ -113,7 +113,7 @@ var classTypes = [nctypes]*classData{
|
||||||
doNotLoadFont: true,
|
doNotLoadFont: true,
|
||||||
},
|
},
|
||||||
c_area: &classData{
|
c_area: &classData{
|
||||||
register: registerAreaWndClass,
|
name: areaWndClass,
|
||||||
style: areastyle,
|
style: areastyle,
|
||||||
xstyle: areaxstyle,
|
xstyle: areaxstyle,
|
||||||
storeSysData: true,
|
storeSysData: true,
|
||||||
|
|
Loading…
Reference in New Issue