diff --git a/backends/x/event.go b/backends/x/event.go
index 5f6b773..d5da4ad 100644
--- a/backends/x/event.go
+++ b/backends/x/event.go
@@ -14,7 +14,7 @@ type scrollSum struct {
 
 const scrollDistance = 16
 
-func (sum *scrollSum) add (button xproto.Button, window *Window, state uint16) {
+func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
 	shift := 
 		(state & xproto.ModMaskShift)                    > 0 ||
 		(state & window.backend.modifierMasks.shiftLock) > 0
@@ -44,7 +44,7 @@ func (sum *scrollSum) add (button xproto.Button, window *Window, state uint16) {
 
 }
 
-func (window *Window) handleExpose (
+func (window *window) handleExpose (
 	connection *xgbutil.XUtil,
 	event xevent.ExposeEvent,
 ) {
@@ -52,7 +52,7 @@ func (window *Window) handleExpose (
 	window.pushRegion(region)
 }
 
-func (window *Window) handleConfigureNotify (
+func (window *window) handleConfigureNotify (
 	connection *xgbutil.XUtil,
 	event xevent.ConfigureNotifyEvent,
 ) {
@@ -81,7 +81,7 @@ func (window *Window) handleConfigureNotify (
 	}
 }
 
-func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {	
+func (window *window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {	
 	nextEvents := xevent.Peek(window.backend.connection)
 	if len(nextEvents) > 0 {
 		untypedEvent := nextEvents[0]
@@ -97,7 +97,7 @@ func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo
 	return false
 }
 
-func (window *Window) modifiersFromState (
+func (window *window) modifiersFromState (
 	state uint16,
 ) (
 	modifiers input.Modifiers,
@@ -114,7 +114,7 @@ func (window *Window) modifiersFromState (
 	}
 }
 
-func (window *Window) handleKeyPress (
+func (window *window) handleKeyPress (
 	connection *xgbutil.XUtil,
 	event xevent.KeyPressEvent,
 ) {
@@ -141,7 +141,7 @@ func (window *Window) handleKeyPress (
 	}
 }
 
-func (window *Window) handleKeyRelease (
+func (window *window) handleKeyRelease (
 	connection *xgbutil.XUtil,
 	event xevent.KeyReleaseEvent,
 ) {
@@ -175,23 +175,25 @@ func (window *Window) handleKeyRelease (
 	}
 }
 
-func (window *Window) handleButtonPress (
+func (window *window) handleButtonPress (
 	connection *xgbutil.XUtil,
 	event xevent.ButtonPressEvent,
 ) {
 	if window.child == nil { return }
 	
-	if child, ok := window.child.(elements.MouseTarget); ok {
-		buttonEvent := *event.ButtonPressEvent
-		if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
+	buttonEvent := *event.ButtonPressEvent
+	if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
+		if child, ok := window.child.(elements.ScrollTarget); ok {
 			sum := scrollSum { }
 			sum.add(buttonEvent.Detail, window, buttonEvent.State)
 			window.compressScrollSum(buttonEvent, &sum)
-			child.HandleMouseScroll (
+			child.HandleScroll (
 				int(buttonEvent.EventX),
 				int(buttonEvent.EventY),
 				float64(sum.x), float64(sum.y))
-		} else {
+		}
+	} else {
+		if child, ok := window.child.(elements.MouseTarget); ok {
 			child.HandleMouseDown (
 				int(buttonEvent.EventX),
 				int(buttonEvent.EventY),
@@ -201,7 +203,7 @@ func (window *Window) handleButtonPress (
 	
 }
 
-func (window *Window) handleButtonRelease (
+func (window *window) handleButtonRelease (
 	connection *xgbutil.XUtil,
 	event xevent.ButtonReleaseEvent,
 ) {
@@ -217,21 +219,21 @@ func (window *Window) handleButtonRelease (
 	}
 }
 
-func (window *Window) handleMotionNotify (
+func (window *window) handleMotionNotify (
 	connection *xgbutil.XUtil,
 	event xevent.MotionNotifyEvent,
 ) {
 	if window.child == nil { return }
 	
-	if child, ok := window.child.(elements.MouseTarget); ok {
+	if child, ok := window.child.(elements.MotionTarget); ok {
 		motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
-		child.HandleMouseMove (
+		child.HandleMotion (
 			int(motionEvent.EventX),
 			int(motionEvent.EventY))
 	}
 }
 
-func (window *Window) compressExpose (
+func (window *window) compressExpose (
 	firstEvent xproto.ExposeEvent,
 ) (
 	lastEvent xproto.ExposeEvent,
@@ -268,7 +270,7 @@ func (window *Window) compressExpose (
 	return
 }
 
-func (window *Window) compressConfigureNotify (
+func (window *window) compressConfigureNotify (
 	firstEvent xproto.ConfigureNotifyEvent,
 ) (
 	lastEvent xproto.ConfigureNotifyEvent,
@@ -296,7 +298,7 @@ func (window *Window) compressConfigureNotify (
 	return
 }
 
-func (window *Window) compressScrollSum (
+func (window *window) compressScrollSum (
 	firstEvent xproto.ButtonPressEvent,
 	sum *scrollSum,
 ) {
@@ -323,7 +325,7 @@ func (window *Window) compressScrollSum (
 	return
 }
 
-func (window *Window) compressMotionNotify (
+func (window *window) compressMotionNotify (
 	firstEvent xproto.MotionNotifyEvent,
 ) (
 	lastEvent xproto.MotionNotifyEvent,
diff --git a/backends/x/window.go b/backends/x/window.go
index 67d352a..ecd4e86 100644
--- a/backends/x/window.go
+++ b/backends/x/window.go
@@ -14,7 +14,7 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
 import "git.tebibyte.media/sashakoshka/tomo/elements"
 // import "runtime/debug"
 
-type Window struct {
+type window struct {
 	backend *Backend
 	xWindow *xwindow.Window
 	xCanvas *xgraphics.Image
@@ -40,7 +40,7 @@ func (backend *Backend) NewWindow (
 ) {
 	if backend == nil { panic("nil backend") }
 
-	window := &Window { backend: backend }
+	window := &window { backend: backend }
 
 	window.xWindow, err = xwindow.Generate(backend.connection)
 	if err != nil { return }
@@ -90,18 +90,15 @@ func (backend *Backend) NewWindow (
 	return
 }
 
-func (window *Window) Adopt (child elements.Element) {
+func (window *window) NotifyMinimumSizeChange (child elements.Element) {
+	window.childMinimumSizeChangeCallback(child.MinimumSize())
+}
+
+func (window *window) Adopt (child elements.Element) {
 	// disown previous child
 	if window.child != nil {
-		window.child.OnDamage(nil)
-		window.child.OnMinimumSizeChange(nil)
-	}
-	if previousChild, ok := window.child.(elements.Focusable); ok {
-		previousChild.OnFocusRequest(nil)
-		previousChild.OnFocusMotionRequest(nil)
-		if previousChild.Focused() {
-			previousChild.HandleUnfocus()
-		}
+		window.child.SetParent(nil)
+		window.child.DrawTo(nil, image.Rectangle { }, nil)
 	}
 	
 	// adopt new child
@@ -112,15 +109,7 @@ func (window *Window) Adopt (child elements.Element) {
 	if newChild, ok := child.(elements.Configurable); ok {
 		newChild.SetConfig(window.config)
 	}
-	if newChild, ok := child.(elements.Focusable); ok {
-		newChild.OnFocusRequest(window.childSelectionRequestCallback)
-	}
 	if child != nil {
-		child.OnDamage(window.childDrawCallback)
-		child.OnMinimumSizeChange (func () {
-			window.childMinimumSizeChangeCallback (
-				child.MinimumSize())
-		})
 		if !window.childMinimumSizeChangeCallback(child.MinimumSize()) {
 			window.resizeChildToFit()
 			window.redrawChildEntirely()
@@ -128,19 +117,19 @@ func (window *Window) Adopt (child elements.Element) {
 	}
 }
 
-func (window *Window) Child () (child elements.Element) {
+func (window *window) Child () (child elements.Element) {
 	child = window.child
 	return
 }
 
-func (window *Window) SetTitle (title string) {
+func (window *window) SetTitle (title string) {
 	ewmh.WmNameSet (
 		window.backend.connection,
 		window.xWindow.Id,
 		title)
 }
 
-func (window *Window) SetIcon (sizes []image.Image) {
+func (window *window) SetIcon (sizes []image.Image) {
 	wmIcons := []ewmh.WmIcon { }
 	
 	for _, icon := range sizes {
@@ -179,7 +168,7 @@ func (window *Window) SetIcon (sizes []image.Image) {
 		wmIcons)
 }
 
-func (window *Window) Show () {
+func (window *window) Show () {
 	if window.child == nil {
 		window.xCanvas.For (func (x, y int) xgraphics.BGRA {
 			return xgraphics.BGRA { }
@@ -191,35 +180,35 @@ func (window *Window) Show () {
 	window.xWindow.Map()
 }
 
-func (window *Window) Hide () {
+func (window *window) Hide () {
 	window.xWindow.Unmap()
 }
 
-func (window *Window) Close () {
+func (window *window) Close () {
 	if window.onClose != nil { window.onClose() }
 	delete(window.backend.windows, window.xWindow.Id)
 	window.xWindow.Destroy()
 }
 
-func (window *Window) OnClose (callback func ()) {
+func (window *window) OnClose (callback func ()) {
 	window.onClose = callback
 }
 
-func (window *Window) SetTheme (theme theme.Theme) {
+func (window *window) SetTheme (theme theme.Theme) {
 	window.theme = theme
 	if child, ok := window.child.(elements.Themeable); ok {
 		child.SetTheme(theme)
 	}
 }
 
-func (window *Window) SetConfig (config config.Config) {
+func (window *window) SetConfig (config config.Config) {
 	window.config = config
 	if child, ok := window.child.(elements.Configurable); ok {
 		child.SetConfig(config)
 	}
 }
 
-func (window *Window) reallocateCanvas () {
+func (window *window) reallocateCanvas () {
 	window.canvas.Reallocate(window.metrics.width, window.metrics.height)
 
 	previousWidth, previousHeight := 0, 0
@@ -250,23 +239,28 @@ func (window *Window) reallocateCanvas () {
 	
 }
 
-func (window *Window) redrawChildEntirely () {
-	window.pushRegion(window.paste(window.canvas))
-	
+func (window *window) redrawChildEntirely () {
+	window.paste(window.canvas.Bounds())
+	window.pushRegion(window.canvas.Bounds())
 }
 
-func (window *Window) resizeChildToFit () {
+func (window *window) resizeChildToFit () {
 	window.skipChildDrawCallback = true
-	window.child.DrawTo(window.canvas, window.canvas.Bounds())
+	window.child.DrawTo (
+		window.canvas,
+		window.canvas.Bounds(),
+		window.childDrawCallback)
 	window.skipChildDrawCallback = false
 }
 
-func (window *Window) childDrawCallback (region canvas.Canvas) {
+func (window *window) childDrawCallback (region image.Rectangle) {
 	if window.skipChildDrawCallback { return }
-	window.pushRegion(window.paste(region))
+	window.paste(region)
+	window.pushRegion(region)
 }
 
-func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) {
+func (window *window) paste (region image.Rectangle) {
+	canvas := canvas.Cut(window.canvas, region)
 	data, stride := canvas.Buffer()
 	bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds())
 
@@ -286,11 +280,9 @@ func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangl
 			dstData[index + 3] = rgba.A
 		}
 	}
-
-	return bounds
 }
 
-func (window *Window) childMinimumSizeChangeCallback (width, height int) (resized bool) {
+func (window *window) childMinimumSizeChangeCallback (width, height int) (resized bool) {
 	icccm.WmNormalHintsSet (
 		window.backend.connection,
 		window.xWindow.Id,
@@ -312,14 +304,14 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) (resize
 	return false
 }
 
-func (window *Window) childSelectionRequestCallback () (granted bool) {
+func (window *window) childSelectionRequestCallback () (granted bool) {
 	if _, ok := window.child.(elements.Focusable); ok {
 		return true
 	}
 	return false
 }
 
-func (window *Window) childSelectionMotionRequestCallback (
+func (window *window) childSelectionMotionRequestCallback (
 	direction input.KeynavDirection,
 ) (
 	granted bool,
@@ -333,7 +325,7 @@ func (window *Window) childSelectionMotionRequestCallback (
 	return true
 }
 
-func (window *Window) pushRegion (region image.Rectangle) {
+func (window *window) pushRegion (region image.Rectangle) {
 	if window.xCanvas == nil { panic("whoopsie!!!!!!!!!!!!!!") }
 	image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image)
 	if ok {
diff --git a/backends/x/x.go b/backends/x/x.go
index eefd914..d72ce1f 100644
--- a/backends/x/x.go
+++ b/backends/x/x.go
@@ -30,7 +30,7 @@ type Backend struct {
 	theme  theme.Theme
 	config config.Config
 
-	windows map[xproto.Window] *Window
+	windows map[xproto.Window] *window
 
 	open bool
 }
@@ -38,7 +38,7 @@ type Backend struct {
 // NewBackend instantiates an X backend.
 func NewBackend () (output tomo.Backend, err error) {
 	backend := &Backend {
-		windows: map[xproto.Window] *Window { },
+		windows: map[xproto.Window] *window { },
 		doChannel: make(chan func (), 0),
 		theme:  theme.Default  { },
 		config: config.Default { },
@@ -79,7 +79,7 @@ func (backend *Backend) Stop () {
 	if !backend.open { return }
 	backend.open = false
 	
-	toClose := []*Window { }
+	toClose := []*window { }
 	for _, window := range backend.windows {
 		toClose = append(toClose, window)
 	}