Added a flag to AreaHandler.Key()/Mouse() to indicate that a repaint is needed after that event has been handled. (Having Repaint() as a method deadlocked for the same reason resizing deadlocked before.)

This commit is contained in:
Pietro Gagliardi 2014-03-27 20:31:23 -04:00
parent 9dc4f8694c
commit ab6e7121e4
5 changed files with 43 additions and 28 deletions

25
area.go
View File

@ -52,13 +52,15 @@ type AreaHandler interface {
// Mouse is called when the Area receives a mouse event.
// You are allowed to do nothing in this handler (to ignore mouse events).
// See MouseEvent for details.
Mouse(e MouseEvent)
// If repaint is true, the Area is marked as needing to be redrawn.
Mouse(e MouseEvent) (repaint bool)
// Key is called when the Area receives a keyboard event.
// You are allowed to do nothing except return false in this handler (to ignore keyboard events).
// Do not do nothing but return true; this may have unintended consequences.
// You are allowed to do nothing except return false for handled in this handler (to ignore keyboard events).
// Do not do nothing but return true for handled; this may have unintended consequences.
// See KeyEvent for details.
Key(e KeyEvent) bool
// If repaint is true, the Area is marked as needing to be redrawn.
Key(e KeyEvent) (handled bool, repaint bool)
}
// MouseEvent contains all the information for a mous event sent by Area.Mouse.
@ -116,16 +118,17 @@ func (e MouseEvent) HeldBits() (h uintptr) {
//
// When you are finished processing the incoming event,
// return whether or not you did something in response
// to the given keystroke from your Key() implementation.
// If you send false, you indicate that you did not handle
// the keypress, and that the system should handle it instead.
// (Some systems will stop processing the keyboard event at all
// if you return true unconditionally, which may result in unwanted
// behavior like global task-switching keystrokes not being processed.)
// to the given keystroke as the handled return of your
// AreaHandler's Key() implementation. If you send false,
// you indicate that you did not handle the keypress, and that
// the system should handle it instead. (Some systems will stop
// processing the keyboard event at all if you return true
// unconditionally, which may result in unwanted behavior like
// global task-switching keystrokes not being processed.)
//
// If a key is pressed that is not supported by ASCII, ExtKey,
// or Modifiers, no KeyEvent will be produced, and package
// ui will act as if false was returned.
// ui will act as if false was returned for handled.
type KeyEvent struct {
// ASCII is a byte representing the character pressed.
// Despite my best efforts, this cannot be trivialized

View File

@ -103,7 +103,7 @@ func makeModifiers(state C.guint, m Modifiers) Modifiers {
}
// shared code for finishing up and sending a mouse event
func finishMouseEvent(data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) {
func finishMouseEvent(widget *C.GtkWidget, data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.gdouble, state C.guint, gdkwindow *C.GdkWindow) {
s := (*sysData)(unsafe.Pointer(data))
state = translateModifiers(state, gdkwindow)
me.Modifiers = makeModifiers(state, 0)
@ -125,7 +125,10 @@ func finishMouseEvent(data C.gpointer, me MouseEvent, mb uint, x C.gdouble, y C.
me.Held = append(me.Held, 5)
}
me.Pos = image.Pt(int(x), int(y))
s.handler.Mouse(me)
repaint := s.handler.Mouse(me)
if repaint {
C.gtk_widget_queue_draw(widget)
}
}
//export our_area_button_press_event_callback
@ -143,7 +146,7 @@ func our_area_button_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent
default: // ignore triple-clicks and beyond; we don't handle those
return C.FALSE // TODO really false?
}
finishMouseEvent(data, me, me.Down, e.x, e.y, e.state, e.window)
finishMouseEvent(widget, data, me, me.Down, e.x, e.y, e.state, e.window)
return C.FALSE // TODO really false?
}
@ -156,7 +159,7 @@ func our_area_button_release_event_callback(widget *C.GtkWidget, event *C.GdkEve
// GDK button ID == our button ID
Up: uint(e.button),
}
finishMouseEvent(data, me, me.Up, e.x, e.y, e.state, e.window)
finishMouseEvent(widget, data, me, me.Up, e.x, e.y, e.state, e.window)
return C.FALSE // TODO really false?
}
@ -166,14 +169,14 @@ var area_button_release_event_callback = C.GCallback(C.our_area_button_release_e
func our_area_motion_notify_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
e := (*C.GdkEventMotion)(unsafe.Pointer(event))
me := MouseEvent{}
finishMouseEvent(data, me, 0, e.x, e.y, e.state, e.window)
finishMouseEvent(widget, data, me, 0, e.x, e.y, e.state, e.window)
return C.FALSE // TODO really false?
}
var area_motion_notify_event_callback = C.GCallback(C.our_area_motion_notify_event_callback)
// shared code for doing a key event
func doKeyEvent(event *C.GdkEvent, data C.gpointer, up bool) bool {
func doKeyEvent(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer, up bool) bool {
var ke KeyEvent
e := (*C.GdkEventKey)(unsafe.Pointer(event))
@ -202,7 +205,11 @@ fmt.Println("$$", up, e.hardware_keycode)
state := translateModifiers(e.state, e.window)
ke.Modifiers = makeModifiers(state, ke.Modifiers)
ke.Up = up
return s.handler.Key(ke)
handled, repaint := s.handler.Key(ke)
if repaint {
C.gtk_widget_queue_draw(widget)
}
return handled
}
//export our_area_key_press_event_callback
@ -218,7 +225,7 @@ func our_area_key_press_event_callback(widget *C.GtkWidget, event *C.GdkEvent, d
fmt.Printf("%d/GDK_KEY_a:\n", C.GDK_KEY_a)
pk(C.GDK_KEY_a, e.window)
*/
ret := doKeyEvent(event, data, false)
ret := doKeyEvent(widget, event, data, false)
_ = ret
return C.FALSE // TODO really false? should probably return !ret (since true indicates stop processing)
}
@ -227,7 +234,7 @@ var area_key_press_event_callback = C.GCallback(C.our_area_key_press_event_callb
//export our_area_key_release_event_callback
func our_area_key_release_event_callback(widget *C.GtkWidget, event *C.GdkEvent, data C.gpointer) C.gboolean {
ret := doKeyEvent(event, data, true)
ret := doKeyEvent(widget, event, data, true)
_ = ret
return C.FALSE // TODO really false? should probably return !ret (since true indicates stop processing)
}

View File

@ -329,6 +329,7 @@ func getModifiers() (m Modifiers) {
return m
}
// TODO mark repaint
func areaMouseEvent(s *sysData, button uint, up bool, count uint, wparam _WPARAM, lparam _LPARAM) {
var me MouseEvent
@ -403,6 +404,7 @@ func areaWndProc(s *sysData) func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lPara
areaMouseEvent(s, 3, true, 0, wParam, lParam)
return 0
// TODO XBUTTONs?
// TODO mark repaint in key events
default:
r1, _, _ := defWindowProc.Call(
uintptr(hwnd),

View File

@ -34,7 +34,9 @@ func (a *keyboardArea) Paint(cliprect image.Rectangle) *image.NRGBA {
return a.kbd.SubImage(cliprect).(*image.NRGBA)
}
func (a *keyboardArea) Mouse(MouseEvent) {}
func (a *keyboardArea) Mouse(MouseEvent) (repaint bool) {
return false
}
func markkey(dest *image.NRGBA, keypt image.Point, m Modifiers) {
xr := keyrect(m).Add(keypt)
@ -42,7 +44,7 @@ func markkey(dest *image.NRGBA, keypt image.Point, m Modifiers) {
draw.Draw(dest, xr, xi, image.ZP, draw.Over)
}
func (a *keyboardArea) Key(e KeyEvent) bool {
func (a *keyboardArea) Key(e KeyEvent) (handled bool, repaint bool) {
a.lock.Lock()
defer a.lock.Unlock()
@ -68,9 +70,9 @@ func (a *keyboardArea) Key(e KeyEvent) bool {
// markkey(a.kbd, modpoints[Super], m &^ Super)
// }
default:
return false
return false, false
}
return true
return true, true
}
var doKeyboard = flag.Bool("kb", false, "run keyboard test")

View File

@ -131,13 +131,14 @@ func (a *areaHandler) Paint(rect image.Rectangle) *image.NRGBA {
*/
return a.img.SubImage(rect).(*image.NRGBA)
}
func (a *areaHandler) Mouse(e MouseEvent) {
fmt.Printf("%#v\n", e)
}
func (a *areaHandler) Key(e KeyEvent) bool {
func (a *areaHandler) Mouse(e MouseEvent) bool {
fmt.Printf("%#v\n", e)
return false
}
func (a *areaHandler) Key(e KeyEvent) (bool, bool) {
fmt.Printf("%#v\n", e)
return false, false
}
var doArea = flag.Bool("area", false, "run area test instead (overrides -kb)")
func areaTest() {