Made sysdata_windows.go send func()s to uitask and not uimsgs. This is also more correct, as multi-step processes happen in one homogenous blob instead of in steps spread across two goroutines.

This commit is contained in:
Pietro Gagliardi 2014-06-12 11:46:51 -04:00
parent c159bb2018
commit af2e8c4b13
1 changed files with 275 additions and 371 deletions

View File

@ -144,26 +144,25 @@ var (
) )
func (s *sysData) make(window *sysData) (err error) { func (s *sysData) make(window *sysData) (err error) {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
ct := classTypes[s.ctype] uitask <- func() {
cid := _HMENU(0) ct := classTypes[s.ctype]
pwin := uintptr(_NULL) cid := _HMENU(0)
if window != nil { // this is a child control pwin := uintptr(_NULL)
cid = window.addChild(s) if window != nil { // this is a child control
pwin = uintptr(window.hwnd) cid = window.addChild(s)
} pwin = uintptr(window.hwnd)
style := uintptr(ct.style) }
if s.alternate { style := uintptr(ct.style)
style = uintptr(ct.altStyle) if s.alternate {
} style = uintptr(ct.altStyle)
lpParam := uintptr(_NULL) }
if ct.storeSysData { lpParam := uintptr(_NULL)
lpParam = uintptr(unsafe.Pointer(s)) if ct.storeSysData {
} lpParam = uintptr(unsafe.Pointer(s))
uitask <- &uimsg{ }
call: _createWindowEx, r1, _, err := _createWindowEx.Call(
p: []uintptr{
uintptr(ct.xstyle), uintptr(ct.xstyle),
utf16ToArg(ct.name), utf16ToArg(ct.name),
blankString, // we set the window text later blankString, // we set the window text later
@ -175,35 +174,28 @@ func (s *sysData) make(window *sysData) (err error) {
pwin, pwin,
uintptr(cid), uintptr(cid),
uintptr(hInstance), uintptr(hInstance),
lpParam, lpParam)
}, if r1 == 0 { // failure
ret: ret, if window != nil {
} window.delChild(cid)
r := <-ret }
if r.ret == 0 { // failure panic(fmt.Errorf("error actually creating window/control: %v", err))
if window != nil {
window.delChild(cid)
} }
return fmt.Errorf("error actually creating window/control: %v", r.err) if !ct.storeSysData { // regular control; store s.hwnd ourselves
} s.hwnd = _HWND(r1)
if !ct.storeSysData { // regular control; store s.hwnd ourselves } else if s.hwnd != _HWND(r1) { // we store sysData in storeSysData(); sanity check
s.hwnd = _HWND(r.ret) panic(fmt.Errorf("hwnd mismatch creating window/control: storeSysData() stored 0x%X but CreateWindowEx() returned 0x%X", s.hwnd, r1))
} else if s.hwnd != _HWND(r.ret) { // we store sysData in storeSysData(); sanity check }
panic(fmt.Errorf("hwnd mismatch creating window/control: storeSysData() stored 0x%X but CreateWindowEx() returned 0x%X", s.hwnd, ret)) if !ct.doNotLoadFont {
} _sendMessage.Call(
if !ct.doNotLoadFont {
uitask <- &uimsg{
call: _sendMessage,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_WM_SETFONT), uintptr(_WM_SETFONT),
uintptr(_WPARAM(controlFont)), uintptr(_WPARAM(controlFont)),
uintptr(_LPARAM(_TRUE)), uintptr(_LPARAM(_TRUE)))
},
ret: ret,
} }
<-ret ret <- struct{}{}
} }
<-ret
return nil return nil
} }
@ -215,75 +207,63 @@ var (
// ShowWindow(hwnd, nCmdShow); // ShowWindow(hwnd, nCmdShow);
// UpdateWindow(hwnd); // UpdateWindow(hwnd);
func (s *sysData) firstShow() error { func (s *sysData) firstShow() error {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _showWindow, _showWindow.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(nCmdShow), uintptr(nCmdShow))
}, r1, _, err := _updateWindow.Call(uintptr(s.hwnd))
ret: ret, if r1 == 0 { // failure
panic(fmt.Errorf("error updating window for the first time: %v", err))
}
ret <- struct{}{}
} }
<-ret <-ret
uitask <- &uimsg{
call: _updateWindow,
p: []uintptr{uintptr(s.hwnd)},
ret: ret,
}
r := <-ret
if r.ret == 0 { // failure
return fmt.Errorf("error updating window for the first time: %v", r.err)
}
return nil return nil
} }
func (s *sysData) show() { func (s *sysData) show() {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _showWindow, _showWindow.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_SW_SHOW), uintptr(_SW_SHOW))
}, ret <- struct{}{}
ret: ret,
} }
<-ret <-ret
} }
func (s *sysData) hide() { func (s *sysData) hide() {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _showWindow, _showWindow.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_SW_HIDE), uintptr(_SW_HIDE))
}, ret <- struct{}{}
ret: ret,
} }
<-ret <-ret
} }
func (s *sysData) setText(text string) { func (s *sysData) setText(text string) {
ptext := toUTF16(text) ret := make(chan struct{})
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _setWindowText, ptext := toUTF16(text)
p: []uintptr{ r1, _, err := _setWindowText.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
utf16ToArg(ptext), utf16ToArg(ptext))
}, if r1 == 0 { // failure
ret: ret, panic(fmt.Errorf("error setting window/control text: %v", err))
} }
r := <-ret ret <- struct{}{}
if r.ret == 0 { // failure
panic(fmt.Errorf("error setting window/control text: %v", r.err))
} }
<-ret
} }
// runs on uitask
func (s *sysData) setRect(x int, y int, width int, height int, winheight int) error { func (s *sysData) setRect(x int, y int, width int, height int, winheight int) error {
r1, _, err := _moveWindow.Call( r1, _, err := _moveWindow.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
@ -299,277 +279,238 @@ func (s *sysData) setRect(x int, y int, width int, height int, winheight int) er
} }
func (s *sysData) isChecked() bool { func (s *sysData) isChecked() bool {
ret := make(chan uiret) ret := make(chan bool)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, r1, _, _ := _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_BM_GETCHECK), uintptr(_BM_GETCHECK),
uintptr(0), uintptr(0),
uintptr(0), uintptr(0))
}, ret <- r1 == _BST_CHECKED
ret: ret,
} }
r := <-ret return <-ret
return r.ret == _BST_CHECKED
} }
func (s *sysData) text() (str string) { func (s *sysData) text() (str string) {
var tc []uint16 ret := make(chan string)
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, var tc []uint16
p: []uintptr{
r1, _, _ := _sendMessage.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_WM_GETTEXTLENGTH), uintptr(_WM_GETTEXTLENGTH),
uintptr(0), uintptr(0),
uintptr(0), uintptr(0))
}, length := r1 + 1 // terminating null
ret: ret, tc = make([]uint16, length)
} _sendMessage.Call(
r := <-ret
length := r.ret + 1 // terminating null
tc = make([]uint16, length)
uitask <- &uimsg{
call: _sendMessage,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_WM_GETTEXT), uintptr(_WM_GETTEXT),
uintptr(_WPARAM(length)), uintptr(_WPARAM(length)),
uintptr(_LPARAM(unsafe.Pointer(&tc[0]))), uintptr(_LPARAM(unsafe.Pointer(&tc[0]))))
}, ret <- syscall.UTF16ToString(tc)
ret: ret,
} }
<-ret return <-ret
return syscall.UTF16ToString(tc)
} }
func (s *sysData) append(what string) { func (s *sysData) append(what string) {
pwhat := toUTF16(what) ret := make(chan struct{})
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, pwhat := toUTF16(what)
p: []uintptr{ r1, _, err := _sendMessage.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(classTypes[s.ctype].appendMsg), uintptr(classTypes[s.ctype].appendMsg),
uintptr(_WPARAM(0)), uintptr(_WPARAM(0)),
utf16ToLPARAM(pwhat), utf16ToLPARAM(pwhat))
}, if r1 == uintptr(classTypes[s.ctype].addSpaceErr) {
ret: ret, panic(fmt.Errorf("out of space adding item to combobox/listbox (last error: %v)", err))
} } else if r1 == uintptr(classTypes[s.ctype].selectedIndexErr) {
r := <-ret panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", err))
if r.ret == uintptr(classTypes[s.ctype].addSpaceErr) { }
panic(fmt.Errorf("out of space adding item to combobox/listbox (last error: %v)", r.err)) ret <- struct{}{}
} else if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) {
panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", r.err))
} }
<-ret
} }
func (s *sysData) insertBefore(what string, index int) { func (s *sysData) insertBefore(what string, index int) {
pwhat := toUTF16(what) ret := make(chan struct{})
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, pwhat := toUTF16(what)
p: []uintptr{ r1, _, err := _sendMessage.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(classTypes[s.ctype].insertBeforeMsg), uintptr(classTypes[s.ctype].insertBeforeMsg),
uintptr(_WPARAM(index)), uintptr(_WPARAM(index)),
utf16ToLPARAM(pwhat), utf16ToLPARAM(pwhat))
}, if r1 == uintptr(classTypes[s.ctype].addSpaceErr) {
ret: ret, panic(fmt.Errorf("out of space adding item to combobox/listbox (last error: %v)", err))
} else if r1 == uintptr(classTypes[s.ctype].selectedIndexErr) {
panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", err))
}
ret <- struct{}{}
} }
r := <-ret <-ret
if r.ret == uintptr(classTypes[s.ctype].addSpaceErr) { }
panic(fmt.Errorf("out of space adding item to combobox/listbox (last error: %v)", r.err))
} else if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) { // runs on uitask
panic(fmt.Errorf("failed to add item to combobox/listbox (last error: %v)", r.err)) func (s *sysData) doSelectedIndex() int {
r1, _, _ := _sendMessage.Call(
uintptr(s.hwnd),
uintptr(classTypes[s.ctype].selectedIndexMsg),
uintptr(_WPARAM(0)),
uintptr(_LPARAM(0)))
if r1 == uintptr(classTypes[s.ctype].selectedIndexErr) { // no selection or manually entered text (apparently, for the latter)
return -1
} }
return int(r1)
} }
func (s *sysData) selectedIndex() int { func (s *sysData) selectedIndex() int {
ret := make(chan uiret) ret := make(chan int)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, ret <- s.doSelectedIndex()
p: []uintptr{
uintptr(s.hwnd),
uintptr(classTypes[s.ctype].selectedIndexMsg),
uintptr(_WPARAM(0)),
uintptr(_LPARAM(0)),
},
ret: ret,
} }
r := <-ret return <-ret
if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) { // no selection or manually entered text (apparently, for the latter)
return -1
}
return int(r.ret)
} }
func (s *sysData) selectedIndices() []int { // runs on uitask
func (s *sysData) doSelectedIndices() []int {
if !s.alternate { // single-selection list box; use single-selection method if !s.alternate { // single-selection list box; use single-selection method
index := s.selectedIndex() index := s.doSelectedIndex()
if index == -1 { if index == -1 {
return nil return nil
} }
return []int{index} return []int{index}
} }
ret := make(chan uiret) r1, _, err := _sendMessage.Call(
defer close(ret) uintptr(s.hwnd),
uitask <- &uimsg{ uintptr(_LB_GETSELCOUNT),
call: _sendMessage, uintptr(0),
p: []uintptr{ uintptr(0))
uintptr(s.hwnd), if r1 == negConst(_LB_ERR) {
uintptr(_LB_GETSELCOUNT), panic(fmt.Errorf("error: LB_ERR from LB_GETSELCOUNT in what we know is a multi-selection listbox: %v", err))
uintptr(0),
uintptr(0),
},
ret: ret,
} }
r := <-ret if r1 == 0 { // nothing selected
if r.ret == negConst(_LB_ERR) {
panic("UI library internal error: LB_ERR from LB_GETSELCOUNT in what we know is a multi-selection listbox")
}
if r.ret == 0 { // nothing selected
return nil return nil
} }
indices := make([]int, r.ret) indices := make([]int, r1)
uitask <- &uimsg{ r1, _, err = _sendMessage.Call(
call: _sendMessage, uintptr(s.hwnd),
p: []uintptr{ uintptr(_LB_GETSELITEMS),
uintptr(s.hwnd), uintptr(_WPARAM(r1)),
uintptr(_LB_GETSELITEMS), uintptr(_LPARAM(unsafe.Pointer(&indices[0]))))
uintptr(_WPARAM(r.ret)), if r1 == negConst(_LB_ERR) {
uintptr(_LPARAM(unsafe.Pointer(&indices[0]))), panic(fmt.Errorf("error: LB_ERR from LB_GETSELITEMS in what we know is a multi-selection listbox: %v", err))
},
ret: ret,
}
r = <-ret
if r.ret == negConst(_LB_ERR) {
panic("UI library internal error: LB_ERR from LB_GETSELITEMS in what we know is a multi-selection listbox")
} }
return indices return indices
} }
func (s *sysData) selectedTexts() []string { func (s *sysData) selectedIndices() []int {
indices := s.selectedIndices() ret := make(chan []int)
ret := make(chan uiret)
defer close(ret) defer close(ret)
strings := make([]string, len(indices)) uitask <- func() {
for i, v := range indices { ret <- s.doSelectedIndices()
uitask <- &uimsg{ }
call: _sendMessage, return <-ret
p: []uintptr{ }
func (s *sysData) selectedTexts() []string {
ret := make(chan []string)
defer close(ret)
uitask <- func() {
indices := s.doSelectedIndices()
strings := make([]string, len(indices))
for i, v := range indices {
r1, _, err := _sendMessage.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_LB_GETTEXTLEN), uintptr(_LB_GETTEXTLEN),
uintptr(_WPARAM(v)), uintptr(_WPARAM(v)),
uintptr(0), uintptr(0))
}, if r1 == negConst(_LB_ERR) {
ret: ret, panic(fmt.Errorf("error: LB_ERR from LB_GETTEXTLEN in what we know is a valid listbox index (came from LB_GETSELITEMS): %v", err))
} }
r := <-ret str := make([]uint16, r1)
if r.ret == negConst(_LB_ERR) { r1, _, err = _sendMessage.Call(
panic("UI library internal error: LB_ERR from LB_GETTEXTLEN in what we know is a valid listbox index (came from LB_GETSELITEMS)")
}
str := make([]uint16, r.ret)
uitask <- &uimsg{
call: _sendMessage,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_LB_GETTEXT), uintptr(_LB_GETTEXT),
uintptr(_WPARAM(v)), uintptr(_WPARAM(v)),
uintptr(_LPARAM(unsafe.Pointer(&str[0]))), uintptr(_LPARAM(unsafe.Pointer(&str[0]))))
}, if r1 == negConst(_LB_ERR) {
ret: ret, panic(fmt.Errorf("error: LB_ERR from LB_GETTEXT in what we know is a valid listbox index (came from LB_GETSELITEMS): %v", err))
}
strings[i] = syscall.UTF16ToString(str)
} }
r = <-ret ret <- strings
if r.ret == negConst(_LB_ERR) {
panic("UI library internal error: LB_ERR from LB_GETTEXT in what we know is a valid listbox index (came from LB_GETSELITEMS)")
}
strings[i] = syscall.UTF16ToString(str)
} }
return strings return <-ret
} }
func (s *sysData) setWindowSize(width int, height int) error { func (s *sysData) setWindowSize(width int, height int) error {
var rect _RECT ret := make(chan struct{})
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _getClientRect, var rect _RECT
p: []uintptr{
r1, _, err := _getClientRect.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(unsafe.Pointer(&rect)), uintptr(unsafe.Pointer(&rect)))
}, if r1 == 0 {
ret: ret, panic(fmt.Errorf("error getting upper-left of window for resize: %v", err))
} }
r := <-ret // TODO AdjustWindowRect() on the result
if r.ret == 0 { // 0 because (0,0) is top-left so no winheight
return fmt.Errorf("error getting upper-left of window for resize: %v", r.err) err = s.setRect(int(rect.left), int(rect.top), width, height, 0)
} if err != nil {
// 0 because (0,0) is top-left so no winheight panic(fmt.Errorf("error actually resizing window: %v", err))
// TODO this needs to be run on uitask! }
err := s.setRect(int(rect.left), int(rect.top), width, height, 0) ret <- struct{}{}
if err != nil {
return fmt.Errorf("error actually resizing window: %v", err)
} }
<-ret
return nil return nil
} }
func (s *sysData) delete(index int) { func (s *sysData) delete(index int) {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, r1, _, err := _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(classTypes[s.ctype].deleteMsg), uintptr(classTypes[s.ctype].deleteMsg),
uintptr(_WPARAM(index)), uintptr(_WPARAM(index)),
uintptr(0), uintptr(0))
}, if r1 == uintptr(classTypes[s.ctype].selectedIndexErr) {
ret: ret, panic(fmt.Errorf("failed to delete item from combobox/listbox (last error: %v)", err))
} }
r := <-ret ret <- struct{}{}
if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) {
panic(fmt.Errorf("failed to delete item from combobox/listbox (last error: %v)", r.err))
} }
<-ret
} }
func (s *sysData) setIndeterminate() { func (s *sysData) setIndeterminate() {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _setWindowLongPtr, r1, _, err := _setWindowLongPtr.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
negConst(_GWL_STYLE), negConst(_GWL_STYLE),
uintptr(classTypes[s.ctype].style | _PBS_MARQUEE), uintptr(classTypes[s.ctype].style | _PBS_MARQUEE))
}, if r1 == 0 {
ret: ret, panic(fmt.Errorf("error setting progress bar style to enter indeterminate mode: %v", err))
} }
r := <-ret _sendMessage.Call(
if r.ret == 0 {
panic(fmt.Errorf("error setting progress bar style to enter indeterminate mode: %v", r.err))
}
uitask <- &uimsg{
call: _sendMessage,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_PBM_SETMARQUEE), uintptr(_PBM_SETMARQUEE),
uintptr(_WPARAM(_TRUE)), uintptr(_WPARAM(_TRUE)),
uintptr(0), uintptr(0))
}, s.isMarquee = true
ret: ret, ret <- struct{}{}
} }
<-ret <-ret
s.isMarquee = true
} }
func (s *sysData) setProgress(percent int) { func (s *sysData) setProgress(percent int) {
@ -577,153 +518,116 @@ func (s *sysData) setProgress(percent int) {
s.setIndeterminate() s.setIndeterminate()
return return
} }
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
if s.isMarquee { uitask <- func() {
// turn off marquee before switching back if s.isMarquee {
uitask <- &uimsg{ // turn off marquee before switching back
call: _sendMessage, _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(_PBM_SETMARQUEE), uintptr(_PBM_SETMARQUEE),
uintptr(_WPARAM(_FALSE)), uintptr(_WPARAM(_FALSE)),
uintptr(0), uintptr(0))
}, r1, _, err := _setWindowLongPtr.Call(
ret: ret,
}
<-ret
uitask <- &uimsg{
call: _setWindowLongPtr,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
negConst(_GWL_STYLE), negConst(_GWL_STYLE),
uintptr(classTypes[s.ctype].style), uintptr(classTypes[s.ctype].style))
}, if r1 == 0 {
ret: ret, panic(fmt.Errorf("error setting progress bar style to leave indeterminate mode (percent %d): %v", percent, err))
}
s.isMarquee = false
} }
r := <-ret send := func(msg uintptr, n int, l _LPARAM) {
if r.ret == 0 { _sendMessage.Call(
panic(fmt.Errorf("error setting progress bar style to leave indeterminate mode (percent %d): %v", percent, r.err))
}
s.isMarquee = false
}
send := func(msg uintptr, n int, l _LPARAM) {
uitask <- &uimsg{
call: _sendMessage,
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
msg, msg,
uintptr(_WPARAM(n)), uintptr(_WPARAM(n)),
uintptr(l), uintptr(l))
},
ret: ret,
} }
<-ret // Windows 7 has a non-disableable slowly-animating progress bar increment
} // there isn't one for decrement, so we'll work around by going one higher and then lower again
// Windows 7 has a non-disableable slowly-animating progress bar increment // for the case where percent == 100, we need to increase the range temporarily
// there isn't one for decrement, so we'll work around by going one higher and then lower again // sources: http://social.msdn.microsoft.com/Forums/en-US/61350dc7-6584-4c4e-91b0-69d642c03dae/progressbar-disable-smooth-animation http://stackoverflow.com/questions/2217688/windows-7-aero-theme-progress-bar-bug http://discuss.joelonsoftware.com/default.asp?dotnet.12.600456.2 http://stackoverflow.com/questions/22469876/progressbar-lag-when-setting-position-with-pbm-setpos http://stackoverflow.com/questions/6128287/tprogressbar-never-fills-up-all-the-way-seems-to-be-updating-too-fast
// for the case where percent == 100, we need to increase the range temporarily if percent == 100 {
// this kind of thing is why I want to move away from uimsg and toward having uitask take func()s like on the other platforms send(_PBM_SETRANGE32, 0, 101)
// sources: http://social.msdn.microsoft.com/Forums/en-US/61350dc7-6584-4c4e-91b0-69d642c03dae/progressbar-disable-smooth-animation http://stackoverflow.com/questions/2217688/windows-7-aero-theme-progress-bar-bug http://discuss.joelonsoftware.com/default.asp?dotnet.12.600456.2 http://stackoverflow.com/questions/22469876/progressbar-lag-when-setting-position-with-pbm-setpos http://stackoverflow.com/questions/6128287/tprogressbar-never-fills-up-all-the-way-seems-to-be-updating-too-fast }
if percent == 100 { send(_PBM_SETPOS, percent+1, 0)
send(_PBM_SETRANGE32, 0, 101) send(_PBM_SETPOS, percent, 0)
} if percent == 100 {
send(_PBM_SETPOS, percent+1, 0) send(_PBM_SETRANGE32, 0, 100)
send(_PBM_SETPOS, percent, 0) }
if percent == 100 { ret <- struct{}{}
send(_PBM_SETRANGE32, 0, 100)
} }
<-ret
} }
func (s *sysData) len() int { func (s *sysData) len() int {
ret := make(chan uiret) ret := make(chan int)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, r1, _, err := _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(classTypes[s.ctype].lenMsg), uintptr(classTypes[s.ctype].lenMsg),
uintptr(_WPARAM(0)), uintptr(_WPARAM(0)),
uintptr(_LPARAM(0)), uintptr(_LPARAM(0)))
}, if r1 == uintptr(classTypes[s.ctype].selectedIndexErr) {
ret: ret, panic(fmt.Errorf("unexpected error return from sysData.len(); GetLastError() says %v", err))
}
ret <- int(r1)
} }
r := <-ret return <-ret
if r.ret == uintptr(classTypes[s.ctype].selectedIndexErr) {
panic(fmt.Errorf("unexpected error return from sysData.len(); GetLastError() says %v", r.err))
}
return int(r.ret)
} }
func (s *sysData) setAreaSize(width int, height int) { func (s *sysData) setAreaSize(width int, height int) {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(msgSetAreaSize), uintptr(msgSetAreaSize),
uintptr(width), // WPARAM is UINT_PTR on Windows XP and newer at least, so we're good with this uintptr(width), // WPARAM is UINT_PTR on Windows XP and newer at least, so we're good with this
uintptr(height), uintptr(height))
}, ret <- struct{}{}
ret: ret,
} }
<-ret <-ret
} }
func (s *sysData) repaintAll() { func (s *sysData) repaintAll() {
ret := make(chan uiret) ret := make(chan struct{})
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _sendMessage, _sendMessage.Call(
p: []uintptr{
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(msgRepaintAll), uintptr(msgRepaintAll),
uintptr(0), uintptr(0),
uintptr(0), uintptr(0))
}, ret <- struct{}{}
ret: ret,
} }
<-ret <-ret
} }
func (s *sysData) center() { func (s *sysData) center() {
var ws _RECT ret := make(chan struct{})
ret := make(chan uiret)
defer close(ret) defer close(ret)
uitask <- &uimsg{ uitask <- func() {
call: _getWindowRect, var ws _RECT
p: []uintptr{
r1, _, err := _getWindowRect.Call(
uintptr(s.hwnd), uintptr(s.hwnd),
uintptr(unsafe.Pointer(&ws)), uintptr(unsafe.Pointer(&ws)))
}, if r1 == 0 {
ret: ret, panic(fmt.Errorf("error getting window rect for sysData.center(): %v", err))
}
// TODO should this be using the monitor functions instead? http://blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx
// error returns from GetSystemMetrics() is meaningless because the return value, 0, is still valid
dw, _, _ := _getSystemMetrics.Call(uintptr(_SM_CXFULLSCREEN))
dh, _, _ := _getSystemMetrics.Call(uintptr(_SM_CYFULLSCREEN))
ww := ws.right - ws.left
wh := ws.bottom - ws.top
wx := (int32(dw) / 2) - (ww / 2)
wy := (int32(dh) / 2) - (wh / 2)
s.setRect(int(wx), int(wy), int(ww), int(wh), 0)
ret <- struct{}{}
} }
r := <-ret <-ret
if r.ret == 0 {
panic(fmt.Errorf("error getting window rect for sysData.center(): %v", r.err))
}
// TODO should this be using the monitor functions instead? http://blogs.msdn.com/b/oldnewthing/archive/2005/05/05/414910.aspx
// error returns from GetSystemMetrics() is meaningless because the return value, 0, is still valid
uitask <- &uimsg{
call: _getSystemMetrics,
p: []uintptr{uintptr(_SM_CXFULLSCREEN)},
ret: ret,
}
r = <-ret
dw := r.ret
uitask <- &uimsg{
call: _getSystemMetrics,
p: []uintptr{uintptr(_SM_CYFULLSCREEN)},
ret: ret,
}
r = <-ret
dh := r.ret
ww := ws.right - ws.left
wh := ws.bottom - ws.top
wx := (int32(dw) / 2) - (ww / 2)
wy := (int32(dh) / 2) - (wh / 2)
// TODO this needs to be run on uitask!
s.setRect(int(wx), int(wy), int(ww), int(wh), 0)
} }