func NewComboBox(parent Container) (*ComboBox, error) { cb, err := newComboBoxWithStyle(parent, win.CBS_DROPDOWN) if err != nil { return nil, err } editHwnd := win.GetWindow(cb.hWnd, win.GW_CHILD) win.SetWindowLongPtr(editHwnd, win.GWLP_USERDATA, uintptr(unsafe.Pointer(cb))) cb.editOrigWndProcPtr = win.SetWindowLongPtr(editHwnd, win.GWLP_WNDPROC, comboBoxEditWndProcPtr) return cb, nil }
// NewNotifyIcon creates and returns a new NotifyIcon. // // The NotifyIcon is initially not visible. func NewNotifyIcon() (*NotifyIcon, error) { // Create the message-only window for the NotifyIcon. hWnd := win.CreateWindowEx( 0, syscall.StringToUTF16Ptr(notifyIconWindowClass), nil, 0, 0, 0, 0, 0, win.HWND_MESSAGE, 0, 0, nil) if hWnd == 0 { return nil, lastError("CreateWindowEx") } // Add our notify icon to the status area and make sure it is hidden. nid := win.NOTIFYICONDATA{ HWnd: hWnd, UFlags: win.NIF_MESSAGE | win.NIF_STATE, DwState: win.NIS_HIDDEN, DwStateMask: win.NIS_HIDDEN, UCallbackMessage: notifyIconMessageId, } nid.CbSize = uint32(unsafe.Sizeof(nid)) if !win.Shell_NotifyIcon(win.NIM_ADD, &nid) { return nil, newError("Shell_NotifyIcon") } // We want XP-compatible message behavior. nid.UVersion = win.NOTIFYICON_VERSION if !win.Shell_NotifyIcon(win.NIM_SETVERSION, &nid) { return nil, newError("Shell_NotifyIcon") } // Create and initialize the NotifyIcon already. menu, err := NewMenu() if err != nil { return nil, err } ni := &NotifyIcon{ id: nid.UID, hWnd: hWnd, contextMenu: menu, } // Set our *NotifyIcon as user data for the message window. win.SetWindowLongPtr(hWnd, win.GWLP_USERDATA, uintptr(unsafe.Pointer(ni))) return ni, nil }
// InitWindow initializes a window. // // Widgets should be initialized using InitWidget instead. func InitWindow(window, parent Window, className string, style, exStyle uint32) error { wb := window.AsWindowBase() wb.window = window wb.enabled = true wb.visible = true wb.name2Property = make(map[string]Property) var hwndParent win.HWND if parent != nil { hwndParent = parent.Handle() if widget, ok := window.(Widget); ok { if container, ok := parent.(Container); ok { widget.AsWidgetBase().parent = container } } } wb.hWnd = win.CreateWindowEx( exStyle, syscall.StringToUTF16Ptr(className), nil, style|win.WS_CLIPSIBLINGS, win.CW_USEDEFAULT, win.CW_USEDEFAULT, win.CW_USEDEFAULT, win.CW_USEDEFAULT, hwndParent, 0, 0, nil) if wb.hWnd == 0 { return lastError("CreateWindowEx") } succeeded := false defer func() { if !succeeded { wb.Dispose() } }() hwnd2WindowBase[wb.hWnd] = wb if !registeredWindowClasses[className] { // We subclass all windows of system classes. wb.origWndProcPtr = win.SetWindowLongPtr(wb.hWnd, win.GWLP_WNDPROC, defaultWndProcPtr) if wb.origWndProcPtr == 0 { return lastError("SetWindowLongPtr") } } setWindowFont(wb.hWnd, defaultFont) if form, ok := window.(Form); ok { if fb := form.AsFormBase(); fb != nil { if err := fb.init(form); err != nil { return err } } } if widget, ok := window.(Widget); ok { if wb := widget.AsWidgetBase(); wb != nil { if err := wb.init(widget); err != nil { return err } } } wb.enabledProperty = NewBoolProperty( func() bool { return wb.window.Enabled() }, func(b bool) error { wb.window.SetEnabled(b) return nil }, wb.enabledChangedPublisher.Event()) wb.visibleProperty = NewBoolProperty( func() bool { return window.Visible() }, func(b bool) error { wb.window.SetVisible(b) return nil }, wb.visibleChangedPublisher.Event()) wb.MustRegisterProperty("Enabled", wb.enabledProperty) wb.MustRegisterProperty("Visible", wb.visibleProperty) succeeded = true return nil }
// 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) }