Exemple #1
0
// WndProc is the window procedure of the window.
//
// When implementing your own WndProc to add or modify behavior, call the
// WndProc of the embedded window for messages you don't handle yourself.
func (wb *WindowBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
	window := windowFromHandle(hwnd)

	switch msg {
	case win.WM_ERASEBKGND:
		if wb.background == nil {
			break
		}

		canvas, err := newCanvasFromHDC(win.HDC(wParam))
		if err != nil {
			break
		}
		defer canvas.Dispose()

		if err := canvas.FillRectangle(wb.background, wb.ClientBounds()); err != nil {
			break
		}

		return 1

	case win.WM_HSCROLL, win.WM_VSCROLL:
		if window := windowFromHandle(win.HWND(lParam)); window != nil {
			// The window that sent the notification shall handle it itself.
			return window.WndProc(hwnd, msg, wParam, lParam)
		}

	case win.WM_LBUTTONDOWN, win.WM_MBUTTONDOWN, win.WM_RBUTTONDOWN:
		if msg == win.WM_LBUTTONDOWN && wb.origWndProcPtr == 0 {
			// Only call SetCapture if this is no subclassed control.
			// (Otherwise e.g. WM_COMMAND(BN_CLICKED) would no longer
			// be generated for PushButton.)
			win.SetCapture(wb.hWnd)
		}
		wb.publishMouseEvent(&wb.mouseDownPublisher, wParam, lParam)

	case win.WM_LBUTTONUP, win.WM_MBUTTONUP, win.WM_RBUTTONUP:
		if msg == win.WM_LBUTTONUP && wb.origWndProcPtr == 0 {
			// See WM_LBUTTONDOWN for why we require origWndProcPtr == 0 here.
			if !win.ReleaseCapture() {
				lastError("ReleaseCapture")
			}
		}
		wb.publishMouseEvent(&wb.mouseUpPublisher, wParam, lParam)

	case win.WM_MOUSEMOVE:
		wb.publishMouseEvent(&wb.mouseMovePublisher, wParam, lParam)

	case win.WM_MOUSEWHEEL:
		wb.publishMouseWheelEvent(&wb.mouseWheelPublisher, wParam, lParam)

	case win.WM_SETFOCUS, win.WM_KILLFOCUS:
		wb.focusedChangedPublisher.Publish()

	case win.WM_SETCURSOR:
		if wb.cursor != nil {
			win.SetCursor(wb.cursor.handle())
			return 0
		}

	case win.WM_CONTEXTMENU:
		sourceWindow := windowFromHandle(win.HWND(wParam))
		if sourceWindow == nil {
			break
		}

		x := win.GET_X_LPARAM(lParam)
		y := win.GET_Y_LPARAM(lParam)

		contextMenu := sourceWindow.ContextMenu()

		var handle win.HWND
		if widget, ok := sourceWindow.(Widget); ok {
			handle = ancestor(widget).Handle()
		} else {
			handle = sourceWindow.Handle()
		}

		if contextMenu != nil {
			win.TrackPopupMenuEx(
				contextMenu.hMenu,
				win.TPM_NOANIMATION,
				x,
				y,
				handle,
				nil)
			return 0
		}

	case win.WM_KEYDOWN:
		wb.handleKeyDown(wParam, lParam)

	case win.WM_KEYUP:
		wb.handleKeyUp(wParam, lParam)

	case win.WM_DROPFILES:
		wb.dropFilesPublisher.Publish(win.HDROP(wParam))

	case win.WM_SIZE, win.WM_SIZING:
		wb.sizeChangedPublisher.Publish()

	case win.WM_DESTROY:
		if wb.origWndProcPtr != 0 {
			// As we subclass all windows of system classes, we prevented the
			// clean-up code in the WM_NCDESTROY handlers of some windows from
			// being called. To fix this, we restore the original window
			// procedure here.
			win.SetWindowLongPtr(wb.hWnd, win.GWLP_WNDPROC, wb.origWndProcPtr)
		}

		delete(hwnd2WindowBase, hwnd)

		wb.window.Dispose()
		wb.hWnd = 0
	}

	if window != nil {
		if wndProc := window.AsWindowBase().origWndProcPtr; wndProc != 0 {
			return win.CallWindowProc(wndProc, hwnd, msg, wParam, lParam)
		}
	}

	return win.DefWindowProc(hwnd, msg, wParam, lParam)
}
Exemple #2
0
// WndProc is the window procedure of the window.
//
// When implementing your own WndProc to add or modify behavior, call the
// WndProc of the embedded window for messages you don't handle yourself.
func (wb *WindowBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
	switch msg {
	case win.WM_ERASEBKGND:
		if wb.background == nil {
			break
		}

		canvas, err := newCanvasFromHDC(win.HDC(wParam))
		if err != nil {
			break
		}
		defer canvas.Dispose()

		if err := canvas.FillRectangle(wb.background, wb.ClientBounds()); err != nil {
			break
		}

		return 1

	case win.WM_LBUTTONDOWN, win.WM_MBUTTONDOWN, win.WM_RBUTTONDOWN:
		if msg == win.WM_LBUTTONDOWN && wb.origWndProcPtr == 0 {
			// Only call SetCapture if this is no subclassed control.
			// (Otherwise e.g. WM_COMMAND(BN_CLICKED) would no longer
			// be generated for PushButton.)
			win.SetCapture(wb.hWnd)
		}
		wb.publishMouseEvent(&wb.mouseDownPublisher, wParam, lParam)

	case win.WM_LBUTTONUP, win.WM_MBUTTONUP, win.WM_RBUTTONUP:
		if msg == win.WM_LBUTTONUP && wb.origWndProcPtr == 0 {
			// See WM_LBUTTONDOWN for why we require origWndProcPtr == 0 here.
			if !win.ReleaseCapture() {
				lastError("ReleaseCapture")
			}
		}
		wb.publishMouseEvent(&wb.mouseUpPublisher, wParam, lParam)

	case win.WM_MOUSEMOVE:
		wb.publishMouseEvent(&wb.mouseMovePublisher, wParam, lParam)

	case win.WM_SETCURSOR:
		if wb.cursor != nil {
			win.SetCursor(wb.cursor.handle())
			return 0
		}

	case win.WM_CONTEXTMENU:
		sourceWindow := windowFromHandle(win.HWND(wParam))
		if sourceWindow == nil {
			break
		}

		x := win.GET_X_LPARAM(lParam)
		y := win.GET_Y_LPARAM(lParam)

		contextMenu := sourceWindow.ContextMenu()

		var handle win.HWND
		if widget, ok := sourceWindow.(Widget); ok {
			handle = ancestor(widget).Handle()
		} else {
			handle = sourceWindow.Handle()
		}

		if contextMenu != nil {
			win.TrackPopupMenuEx(
				contextMenu.hMenu,
				win.TPM_NOANIMATION,
				x,
				y,
				handle,
				nil)
			return 0
		}

	case win.WM_KEYDOWN:
		wb.handleKeyDown(wParam, lParam)

	case win.WM_KEYUP:
		wb.handleKeyUp(wParam, lParam)

	case win.WM_SIZE, win.WM_SIZING:
		wb.sizeChangedPublisher.Publish()

	case win.WM_DESTROY:
		switch w := wb.window.(type) {
		case *ToolTip:
		case Widget:
			globalToolTip.RemoveTool(w)
		}

		delete(hwnd2WindowBase, hwnd)

		wb.hWnd = 0
		wb.window.Dispose()
	}

	if window := windowFromHandle(hwnd); window != nil {
		origWndProcPtr := window.AsWindowBase().origWndProcPtr
		if origWndProcPtr != 0 {
			return win.CallWindowProc(origWndProcPtr, hwnd, msg, wParam, lParam)
		}
	}

	return win.DefWindowProc(hwnd, msg, wParam, lParam)
}
Exemple #3
0
func (cw *CustomWidget) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
	switch msg {
	case win.WM_PAINT:
		if cw.paint == nil {
			newError("paint func is nil")
			break
		}

		var ps win.PAINTSTRUCT

		var hdc win.HDC
		if wParam == 0 {
			hdc = win.BeginPaint(cw.hWnd, &ps)
		} else {
			hdc = win.HDC(wParam)
		}
		if hdc == 0 {
			newError("BeginPaint failed")
			break
		}
		defer func() {
			if wParam == 0 {
				win.EndPaint(cw.hWnd, &ps)
			}
		}()

		canvas, err := newCanvasFromHDC(hdc)
		if err != nil {
			newError("newCanvasFromHDC failed")
			break
		}
		defer canvas.Dispose()

		r := &ps.RcPaint
		bounds := Rectangle{
			int(r.Left),
			int(r.Top),
			int(r.Right - r.Left),
			int(r.Bottom - r.Top),
		}
		if cw.paintMode == PaintBuffered {
			err = cw.bufferedPaint(canvas, bounds)
		} else {
			err = cw.paint(canvas, bounds)
		}

		if err != nil {
			newError("paint failed")
			break
		}

		return 0

	case win.WM_ERASEBKGND:
		if cw.paintMode != PaintNormal {
			return 1
		}

	case win.WM_PRINTCLIENT:
		win.SendMessage(hwnd, win.WM_PAINT, wParam, lParam)

	case win.WM_SIZE, win.WM_SIZING:
		if cw.invalidatesOnResize {
			cw.Invalidate()
		}
	}

	return cw.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
}