U: frameless for windows LCL, Border style reflects,

R: function's, FramelessForLine, Frameless
This commit is contained in:
杨红岩 2024-08-06 17:31:15 +08:00
parent f2e33dddab
commit 00fdcd0a8a
5 changed files with 127 additions and 106 deletions

View File

@ -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) // 设置可以调整窗口大小的边框方向, 默认所有方向

View File

@ -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() {
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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