diff --git a/cef/browser_window.go b/cef/browser_window.go index 1eabc6c5..6c4d8bb7 100644 --- a/cef/browser_window.go +++ b/cef/browser_window.go @@ -161,8 +161,6 @@ type ILCLBrowserWindow interface { EnableHelp() //启用标题栏帮助 NewTray() ITray //创建LCL的系统托盘 SetRoundRectRgn(rgn int) //窗口无边框时圆角设置 - FramelessForLine() //无边框四边一条细线样式 - Frameless() //无边框 ChromiumCreate(config *TCefChromiumConfig, defaultUrl string) //chromium实例为空时创建 chromium BroderDirectionAdjustments() et.BroderDirectionAdjustments //返回可以调整窗口大小的边框方向, 默认所有方向 SetBroderDirectionAdjustments(val et.BroderDirectionAdjustments) // 设置可以调整窗口大小的边框方向, 默认所有方向 diff --git a/cef/browser_window_hook_other.go b/cef/browser_window_hook_other.go new file mode 100644 index 00000000..1bf6dad8 --- /dev/null +++ b/cef/browser_window_hook_other.go @@ -0,0 +1,20 @@ +//---------------------------------------- +// +// Copyright © yanghy. All Rights Reserved. +// +// Licensed under Apache License Version 2.0, January 2004 +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +//---------------------------------------- + +//go:build !windows +// +build !windows + +package cef + +func (m *LCLBrowserWindow) _HookWndProcMessage() { +} + +func (m *LCLBrowserWindow) _RestoreWndProc() { +} diff --git a/cef/browser_window_hook_windows.go b/cef/browser_window_hook_windows.go new file mode 100644 index 00000000..aa1790f7 --- /dev/null +++ b/cef/browser_window_hook_windows.go @@ -0,0 +1,74 @@ +//---------------------------------------- +// +// Copyright © yanghy. All Rights Reserved. +// +// Licensed under Apache License Version 2.0, January 2004 +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +//---------------------------------------- + +//go:build windows +// +build windows + +package cef + +import ( + "github.com/energye/golcl/lcl/types" + "github.com/energye/golcl/lcl/types/messages" + "github.com/energye/golcl/lcl/win" + "syscall" + "unsafe" +) + +var ( + dwmAPI = syscall.NewLazyDLL("dwmapi.dll") + _DwmExtendFrameIntoClientArea = dwmAPI.NewProc("DwmExtendFrameIntoClientArea") +) + +type margins struct { + CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32 +} + +func extendFrameIntoClientArea(hwnd uintptr, margins margins) { + _, _, _ = _DwmExtendFrameIntoClientArea.Call(hwnd, uintptr(unsafe.Pointer(&margins))) +} + +func (m *LCLBrowserWindow) wndProc(hwnd types.HWND, message uint32, wParam, lParam uintptr) uintptr { + if m.WindowProperty().EnableHideCaption { + switch message { + case messages.WM_ACTIVATE: + // If we want to have a frameless window but with the default frame decorations, extend the DWM client area. + // This Option is not affected by returning 0 in WM_NCCALCSIZE. + // As a result we have hidden the titlebar but still have the default window frame styling. + // See: https://docs.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmextendframeintoclientarea#remarks + extendFrameIntoClientArea(m.Handle(), margins{CxLeftWidth: 1, CxRightWidth: 1, CyTopHeight: 1, CyBottomHeight: 1}) + case messages.WM_NCCALCSIZE: + // Disable the standard frame by allowing the client area to take the full + // window size. + // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize#remarks + // This hides the titlebar and also disables the resizing from user interaction because the standard frame is not + // shown. We still need the WS_THICKFRAME style to enable resizing from the frontend. + if wParam != 0 { + //cycaption := win.GetSystemMetrics(4) + //rect := (*types.TRect)(unsafe.Pointer(lParam)) + //rect.Bottom += -1 + //rect.Right += -1 + return 0 + } + } + } + return win.CallWindowProc(m.oldWndPrc, hwnd, message, wParam, lParam) +} + +func (m *LCLBrowserWindow) _HookWndProcMessage() { + wndProcCallback := syscall.NewCallback(m.wndProc) + m.oldWndPrc = win.SetWindowLongPtr(m.Handle(), win.GWL_WNDPROC, wndProcCallback) +} + +func (m *LCLBrowserWindow) _RestoreWndProc() { + if m.oldWndPrc != 0 { + win.SetWindowLongPtr(m.Handle(), win.GWL_WNDPROC, m.oldWndPrc) + m.oldWndPrc = 0 + } +} diff --git a/cef/browser_window_lcl.go b/cef/browser_window_lcl.go index 28c56b99..37fde6d9 100644 --- a/cef/browser_window_lcl.go +++ b/cef/browser_window_lcl.go @@ -38,21 +38,22 @@ import ( // // 该窗口使用CEF和LCL组件实现,CEF<=1.106.xx版本 在windows、MacOSX可正常使用, Linux无法输入中文, CEF>=2.107.xx版本linux强制使用 ViewsFrameworkBrowserWindow 窗口组件 type LCLBrowserWindow struct { - *lcl.TForm //window form - isFormCreate bool //是否创建完成 WindowForm - chromiumBrowser ICEFChromiumBrowser //浏览器 - windowProperty *WindowProperty //窗口属性 - windowId int32 //窗口ID - windowType consts.WINDOW_TYPE //窗口类型 - isClosing bool // - canClose bool // - onResize []TNotifyEvent //扩展事件 向后链试循环调用 - windowResize TNotifyEvent //扩展事件 - onActivate TNotifyEvent //扩展事件 - onShow []TNotifyEvent //扩展事件 向后链试循环调用 - onClose []TCloseEvent //扩展事件 向后链试循环调用 - onCloseQuery TCloseQueryEvent //扩展事件 - onActivateAfter lcl.TNotifyEvent //扩展事件 + *lcl.TForm //window form + isFormCreate bool //是否创建完成 WindowForm + chromiumBrowser ICEFChromiumBrowser //浏览器 + windowProperty *WindowProperty //窗口属性 + windowId int32 //窗口ID + windowType consts.WINDOW_TYPE //窗口类型 + isClosing bool // + canClose bool // + onResize []TNotifyEvent //扩展事件 向后链试循环调用 + windowResize TNotifyEvent //扩展事件 + onActivate TNotifyEvent //扩展事件 + onShow []TNotifyEvent //扩展事件 向后链试循环调用 + onClose []TCloseEvent //扩展事件 向后链试循环调用 + onCloseQuery TCloseQueryEvent //扩展事件 + onActivateAfter lcl.TNotifyEvent //扩展事件 + onDestroy lcl.TNotifyEvent onWndProc []lcl.TWndProcEvent //扩展事件 向后链试循环调用 onPaint []lcl.TNotifyEvent //扩展事件 向后链试循环调用 auxTools IAuxTools //辅助工具 @@ -65,6 +66,7 @@ type LCLBrowserWindow struct { wmWindowPosChangedMessage wmWindowPosChanged // screen IScreen //屏幕 rgn int //窗口四边圆角 + oldWndPrc uintptr } // NewLCLBrowserWindow 创建一个 LCL 带有 chromium 窗口 @@ -194,7 +196,7 @@ func (m *LCLBrowserWindow) SetProperty() { m.SetFormStyle(types.FsSystemStayOnTop) } if wp.EnableHideCaption { - m.HideTitle() + //m.HideTitle() } else { if !wp.EnableMinimize { m.DisableMinimize() @@ -615,16 +617,17 @@ func (m *LCLBrowserWindow) FormCreate() { m.isFormCreate = true m.SetName(fmt.Sprintf("energy_window_name_%d", time.Now().UnixNano()/1e6)) m.onFormMessages() - m.taskMenu() } // defaultWindowEvent 默认窗口活动/关闭处理事件 func (m *LCLBrowserWindow) defaultWindowEvent() { + m._HookWndProcMessage() if m.WindowType() != consts.WT_DEV_TOOLS { m.TForm.SetOnActivate(m.activate) } m.TForm.SetOnResize(m.resize) m.TForm.SetOnShow(m.show) + m.TForm.SetOnDestroy(m.destroy) } // defaultWindowCloseEvent 默认的窗口关闭事件 @@ -803,6 +806,7 @@ func (m *LCLBrowserWindow) IsLCL() bool { // show 内部调用 func (m *LCLBrowserWindow) show(sender lcl.IObject) { + m.SetBoundsRect(m.BoundsRect()) // trigger WM_NCCALCSIZE hook msg if m.onShow != nil { for _, fn := range m.onShow { fn(sender) @@ -810,6 +814,13 @@ func (m *LCLBrowserWindow) show(sender lcl.IObject) { } } +func (m *LCLBrowserWindow) destroy(sender lcl.IObject) { + m._RestoreWndProc() + if m.onDestroy != nil { + m.onDestroy(sender) + } +} + // SetCreateBrowserExtraInfo // // 设置 Chromium 创建浏览器时设置的扩展信息 @@ -1178,6 +1189,10 @@ func (m *LCLBrowserWindow) SetOnWMWindowPosChanged(fn wmWindowPosChanged) { m.wmWindowPosChangedMessage = fn } +func (m *LCLBrowserWindow) SetOnDestroy(fn lcl.TNotifyEvent) { + m.onDestroy = fn +} + func init() { lcl.RegisterExtEventCallback(func(fn interface{}, getVal func(idx int) uintptr) bool { getPtr := func(i int) unsafe.Pointer { diff --git a/cef/browser_window_lcl_windows.go b/cef/browser_window_lcl_windows.go index 896b89d2..f73bcdb4 100644 --- a/cef/browser_window_lcl_windows.go +++ b/cef/browser_window_lcl_windows.go @@ -41,18 +41,11 @@ const ( // ShowTitle 显示标题栏 func (m *LCLBrowserWindow) ShowTitle() { m.WindowProperty().EnableHideCaption = false - //win.SetWindowLong(m.Handle(), win.GWL_STYLE, uintptr(win.GetWindowLong(m.Handle(), win.GWL_STYLE)|win.WS_CAPTION)) - //win.SetWindowPos(m.Handle(), m.Handle(), 0, 0, 0, 0, win.SWP_NOSIZE|win.SWP_NOMOVE|win.SWP_NOZORDER|win.SWP_NOACTIVATE|win.SWP_FRAMECHANGED) - m.EnabledMaximize(m.WindowProperty().EnableMaximize) - m.EnabledMinimize(m.WindowProperty().EnableMinimize) - m.SetBorderStyle(types.BsSizeable) } // HideTitle 隐藏标题栏 无边框样式 func (m *LCLBrowserWindow) HideTitle() { m.WindowProperty().EnableHideCaption = true - m.SetBorderStyle(types.BsNone) - //m.Frameless() } // SetRoundRectRgn 窗口无边框时圆角设置 @@ -68,44 +61,6 @@ func (m *LCLBrowserWindow) SetRoundRectRgn(rgn int) { } } -// FramelessForDefault 窗口四边框系统默认样式 -// -// TODO 窗口顶部有条线, -func (m *LCLBrowserWindow) FramelessForDefault() { - gwlStyle := win.GetWindowLong(m.Handle(), win.GWL_STYLE) - win.SetWindowLong(m.Handle(), win.GWL_STYLE, uintptr(gwlStyle&^win.WS_CAPTION&^win.WS_BORDER|win.WS_THICKFRAME)) - win.SetWindowPos(m.Handle(), 0, 0, 0, 0, 0, uint32(win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_FRAMECHANGED)) - - //winapi.SetClassLongPtr(this.Handle, GCL_STYLE, GetClassLong(this.Handle, GCL_STYLE)|CS_DropSHADOW) - //gclStyle := winapi.GetClassLongPtr(et.HWND(m.Handle()), messages.GCL_STYLE) - //winapi.WinSetClassLongPtr().SetClassLongPtr(et.HWND(m.Handle()), messages.GCL_STYLE, gclStyle|messages.CS_DROPSHADOW) -} - -// FramelessForLine 窗口四边框是一条细线 -func (m *LCLBrowserWindow) FramelessForLine() { - gwlStyle := win.GetWindowLong(m.Handle(), win.GWL_STYLE) - win.SetWindowLong(m.Handle(), win.GWL_STYLE, uintptr(gwlStyle&^win.WS_CAPTION&^win.WS_THICKFRAME|win.WS_BORDER)) - win.SetWindowPos(m.Handle(), 0, 0, 0, 0, 0, uint32(win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_FRAMECHANGED)) -} - -// Frameless 无边框 -func (m *LCLBrowserWindow) Frameless() { - gwlStyle := win.GetWindowLong(m.Handle(), win.GWL_STYLE) - win.SetWindowLong(m.Handle(), win.GWL_STYLE, uintptr(gwlStyle&^win.WS_CAPTION&^win.WS_THICKFRAME)) - win.SetWindowPos(m.Handle(), 0, 0, 0, 0, 0, uint32(win.SWP_NOMOVE|win.SWP_NOSIZE|win.SWP_FRAMECHANGED)) -} - -// windows无边框窗口任务栏处理 -func (m *LCLBrowserWindow) taskMenu() { - m.SetOnShow(func(sender lcl.IObject) bool { - if m.WindowProperty().EnableHideCaption { - gwlStyle := win.GetWindowLong(m.Handle(), win.GWL_STYLE) - win.SetWindowLong(m.Handle(), win.GWL_STYLE, uintptr(gwlStyle|win.WS_SYSMENU|win.WS_MINIMIZEBOX)) - } - return false - }) -} - // SetFocus // // 在窗口 (Visible = true) 显示之后设置窗口焦点 @@ -114,7 +69,7 @@ func (m *LCLBrowserWindow) taskMenu() { func (m *LCLBrowserWindow) SetFocus() { if m.TForm != nil { m.Visible() - //窗口\激活在Z序中的下个顶层窗口 + //窗口激活在Z序中的下个顶层窗口 m.Minimize() //激活窗口出现在前景 m.Restore() @@ -198,47 +153,6 @@ func (m *LCLBrowserWindow) doOnRenderCompMsg(chromiumBrowser ICEFChromiumBrowser handled := m.cwcap.onCanBorder(chromiumBrowser, x, y, &rect) if handled { - // 鼠标在边框范围 - // 当是CEF组件消息,判断一次组件四边距离窗口四边间距,如果大于边框范围则取消操作 - // TODO 暂时不使用 - //if messageType == cmtCEF { - // windowRect := m.BoundsRect() - // switch m.cwcap.borderHT { - // case messages.HTTOP: // 上 - // if rect.Top > borderRange { - // return - // } - // case messages.HTBOTTOM: // 下 - // if (windowRect.Height() - rect.Bottom) > borderRange { - // return - // } - // case messages.HTLEFT: // 左 - // if rect.Left > borderRange { - // return - // } - // case messages.HTRIGHT: // 右 - // if (windowRect.Width() - rect.Right) > borderRange { - // return - // } - // case messages.HTTOPRIGHT: // 右上 - // if (windowRect.Width()-rect.Right) > borderRange || rect.Top > borderRange { - // return - // } - // case messages.HTBOTTOMRIGHT: // 右下 - // if (windowRect.Width()-rect.Right) > borderRange || (windowRect.Height()-rect.Bottom) > borderRange { - // return - // } - // case messages.HTTOPLEFT: // 左上 - // if rect.Left > borderRange || rect.Top > borderRange { - // return - // } - // case messages.HTBOTTOMLEFT: // 左下 - // if rect.Left > borderRange || (windowRect.Height()-rect.Bottom) > borderRange { - // return - // } - // } - //} - // 鼠标在边框位置 *lResult = types.LRESULT(m.cwcap.borderHT) *aHandled = true