@yufengtadian/freedom-cli 1.12.12 → 1.12.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +17 -3
  2. package/bin/freedom.js +8 -3
  3. package/lib/build.js +64 -13
  4. package/lib/cli.js +129 -82
  5. package/lib/config.js +0 -7
  6. package/lib/shell.js +170 -33
  7. package/lib/theme.js +105 -0
  8. package/lib/tui.js +27 -3
  9. package/lib/update.js +109 -0
  10. package/lib/utils.js +14 -1
  11. package/package.json +1 -1
  12. package/shell/darwin-arm64/freedom-shell +0 -0
  13. package/shell/linux-x64/freedom-shell +0 -0
  14. package/shell/win-x64/freedom-shell.exe +0 -0
  15. package/templates/go/main.go +2 -1
  16. package/templates/go/pkg/freedom/assets/freedom.js +10 -4
  17. package/templates/go/pkg/freedom/backend_proc.go +7 -4
  18. package/templates/go/pkg/freedom/center_windows.go +44 -5
  19. package/templates/go/pkg/freedom/configfile.go +12 -5
  20. package/templates/go/pkg/freedom/freedom.go +303 -273
  21. package/templates/go/pkg/freedom/window_other.go +6 -2
  22. package/templates/go/webview_go/libs/webview/include/webview.h +31 -0
  23. package/templates/go/webview_go/webview.go +32 -6
  24. package/templates/project/src/main.js +12 -5
  25. package/templates/go/build_out.txt +0 -0
  26. package/templates/go/err.txt +0 -2
  27. package/templates/go/err10.txt +0 -0
  28. package/templates/go/err11.txt +0 -0
  29. package/templates/go/err2.txt +0 -0
  30. package/templates/go/err3.txt +0 -0
  31. package/templates/go/err4.txt +0 -1
  32. package/templates/go/err5.txt +0 -0
  33. package/templates/go/err6.txt +0 -0
  34. package/templates/go/err7.txt +0 -0
  35. package/templates/go/err8.txt +0 -0
  36. package/templates/go/err9.txt +0 -0
  37. package/templates/go/go.mod.bak_gbk +0 -11
  38. package/templates/go/tidy.txt +0 -0
  39. package/templates/go/vet_out.txt +0 -0
@@ -293,6 +293,7 @@ typedef enum webview_window_action {
293
293
  * @param action The action to execute (see webview_window_action_t).
294
294
  */
295
295
  WEBVIEW_API int webview_window_control(webview_t w, webview_window_action_t action);
296
+ WEBVIEW_API int webview_window_begin_move_drag(webview_t w);
296
297
 
297
298
  /**
298
299
  * Navigates webview to the given URL. URL may be a properly encoded data URI.
@@ -1041,6 +1042,7 @@ if (status === 0) {\
1041
1042
  // 供前端自绘标题栏三按钮使用。action 取值见 webview_window_action_t。
1042
1043
  // 返回 0 表示成功;-1 表示该平台/动作不支持;isMaximized 返回 1/0。
1043
1044
  int window_control(int action) { return window_control_impl(action); }
1045
+ int begin_move_drag() { return begin_move_drag_impl(); }
1044
1046
 
1045
1047
  void set_size(int width, int height, webview_hint_t hints) {
1046
1048
  set_size_impl(width, height, hints);
@@ -1062,6 +1064,7 @@ protected:
1062
1064
  virtual void set_size_impl(int width, int height, webview_hint_t hints) = 0;
1063
1065
  virtual void set_decorated_impl(bool decorated) = 0;
1064
1066
  virtual int window_control_impl(int action) = 0;
1067
+ virtual int begin_move_drag_impl() = 0;
1065
1068
  virtual void set_html_impl(const std::string &html) = 0;
1066
1069
  virtual void init_impl(const std::string &js) = 0;
1067
1070
  virtual void eval_impl(const std::string &js) = 0;
@@ -1418,6 +1421,14 @@ public:
1418
1421
  }
1419
1422
  }
1420
1423
 
1424
+ // 无边框窗口拖动:root_x/root_y=-1 表示用当前指针位置,由窗口管理器接管拖动。
1425
+ // 与 Windows 的 WM_NCLBUTTONDOWN+HTCAPTION 语义等价,保留页面双击/右键事件。
1426
+ int begin_move_drag_impl() override {
1427
+ gtk_window_begin_move_drag(GTK_WINDOW(m_window), GDK_BUTTON_PRESS, -1, -1,
1428
+ gtk_get_current_event_time());
1429
+ return 0;
1430
+ }
1431
+
1421
1432
  void set_size_impl(int width, int height, webview_hint_t hints) override {
1422
1433
  gtk_window_set_resizable(GTK_WINDOW(m_window), hints != WEBVIEW_HINT_FIXED);
1423
1434
  if (hints == WEBVIEW_HINT_NONE) {
@@ -1824,6 +1835,21 @@ public:
1824
1835
  return -1;
1825
1836
  }
1826
1837
  }
1838
+
1839
+ // 无边框窗口拖动:用当前鼠标屏幕位置合成 NSLeftMouseDragged 事件,
1840
+ // 调 performWindowDragWithEvent: 进入 AppKit 原生窗口拖动循环。
1841
+ int begin_move_drag_impl() override {
1842
+ objc::autoreleasepool arp;
1843
+ auto loc = objc::msg_send<CGPoint>("NSEvent"_cls, "mouseLocation"_sel);
1844
+ auto wnum = objc::msg_send<NSInteger>(m_window, "windowNumber"_sel);
1845
+ auto evt = objc::msg_send<id>(
1846
+ "NSEvent"_cls,
1847
+ "mouseEventWithType:location:modifierFlags:timestamp:windowNumber:context:eventNumber:clickCount:pressure:"_sel,
1848
+ (NSUInteger)1 /*NSLeftMouseDragged*/, loc, (NSUInteger)0, (double)0.0,
1849
+ wnum, (id)nullptr, (NSInteger)0, (NSInteger)1, (float)1.0);
1850
+ objc::msg_send<void>(m_window, "performWindowDragWithEvent:"_sel, evt);
1851
+ return 0;
1852
+ }
1827
1853
  void navigate_impl(const std::string &url) override {
1828
1854
  objc::autoreleasepool arp;
1829
1855
 
@@ -3495,6 +3521,7 @@ public:
3495
3521
  // Windows 窗口控制(min/max/close)由 freedom 壳层 window_windows.go
3496
3522
  // 直接调 user32 处理,webview 层不参与。
3497
3523
  int window_control_impl(int action) override { (void)action; return -1; }
3524
+ int begin_move_drag_impl() override { return -1; }
3498
3525
 
3499
3526
  void set_size_impl(int width, int height, webview_hint_t hints) override {
3500
3527
  auto style = GetWindowLong(m_window, GWL_STYLE);
@@ -3794,6 +3821,10 @@ WEBVIEW_API int webview_window_control(webview_t w, webview_window_action_t acti
3794
3821
  static_cast<int>(action));
3795
3822
  }
3796
3823
 
3824
+ WEBVIEW_API int webview_window_begin_move_drag(webview_t w) {
3825
+ return static_cast<webview::webview *>(w)->begin_move_drag();
3826
+ }
3827
+
3797
3828
  WEBVIEW_API void webview_navigate(webview_t w, const char *url) {
3798
3829
  static_cast<webview::webview *>(w)->navigate(url);
3799
3830
  }
@@ -118,6 +118,10 @@ type WebView interface {
118
118
  // 供前端自绘标题栏三按钮调用。Windows 上由 freedom 壳层处理,此处返回 -1。
119
119
  WindowControl(action WindowAction) int
120
120
 
121
+ // BeginMoveDrag 发起无边框窗口的原生拖动(macOS/Linux)。
122
+ // Windows 由 freedom 壳层用 WM_NCLBUTTONDOWN 处理,此处返回 -1。
123
+ BeginMoveDrag() int
124
+
121
125
  // SetSize updates native window size. See Hint constants.
122
126
  SetSize(w int, h int, hint Hint)
123
127
 
@@ -161,10 +165,11 @@ type webview struct {
161
165
  }
162
166
 
163
167
  var (
164
- m sync.Mutex
165
- index uintptr
166
- dispatch = map[uintptr]func(){}
167
- bindings = map[uintptr]func(id, req string) (interface{}, error){}
168
+ m sync.Mutex
169
+ index uintptr
170
+ dispatch = map[uintptr]func(){}
171
+ bindings = map[uintptr]func(id, req string) (interface{}, error){}
172
+ bindNames = map[string]uintptr{} // name -> index,供 Unbind 清理 bindings 条目
168
173
  )
169
174
 
170
175
  func boolToInt(b bool) C.int {
@@ -232,6 +237,10 @@ func (w *webview) WindowControl(action WindowAction) int {
232
237
  return int(C.webview_window_control(w.w, C.webview_window_action_t(action)))
233
238
  }
234
239
 
240
+ func (w *webview) BeginMoveDrag() int {
241
+ return int(C.webview_window_begin_move_drag(w.w))
242
+ }
243
+
235
244
  func (w *webview) SetSize(width int, height int, hint Hint) {
236
245
  C.webview_set_size(w.w, C.int(width), C.int(height), C.webview_hint_t(hint))
237
246
  }
@@ -253,8 +262,12 @@ func (w *webview) Dispatch(f func()) {
253
262
  for ; dispatch[index] != nil; index++ {
254
263
  }
255
264
  dispatch[index] = f
265
+ // 在锁内保存局部副本再解锁:解锁后读取共享 index 属数据竞争
266
+ //(另一 goroutine 可能在 Lock 内推进 index),race detector 会报,
267
+ // 且极端时序下可能把未就绪的 index 传给 C 层导致回调失配。
268
+ idx := index
256
269
  m.Unlock()
257
- C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
270
+ C.CgoWebViewDispatch(w.w, C.uintptr_t(idx))
258
271
  }
259
272
 
260
273
  //export _webviewDispatchGoCallback
@@ -356,14 +369,27 @@ func (w *webview) Bind(name string, f interface{}) error {
356
369
  for ; bindings[index] != nil; index++ {
357
370
  }
358
371
  bindings[index] = binding
372
+ bindNames[name] = index
373
+ // 锁内保存副本,避免解锁后读取共享 index(与 Dispatch 同类数据竞争)
374
+ idx := index
359
375
  m.Unlock()
360
376
  cname := C.CString(name)
361
377
  defer C.free(unsafe.Pointer(cname))
362
- C.CgoWebViewBind(w.w, cname, C.uintptr_t(index))
378
+ C.CgoWebViewBind(w.w, cname, C.uintptr_t(idx))
363
379
  return nil
364
380
  }
365
381
 
366
382
  func (w *webview) Unbind(name string) error {
383
+ // 清理 Go 侧 bindings / bindNames 条目,避免 Unbind 后永久泄漏。
384
+ // C 侧 binding_context(glue.c calloc,每 Bind 约 16B)在 C++ unbind 中
385
+ // 仅 erase map 不 free,会小幅泄漏;但框架内 Bind 次数固定(3~4 个)、
386
+ // 进程生命周期内不会反复 Bind/Unbind,实际影响可忽略,故不额外改 C 层。
387
+ m.Lock()
388
+ if idx, ok := bindNames[name]; ok {
389
+ delete(bindings, idx)
390
+ delete(bindNames, name)
391
+ }
392
+ m.Unlock()
367
393
  cname := C.CString(name)
368
394
  defer C.free(unsafe.Pointer(cname))
369
395
  C.CgoWebViewUnbind(w.w, cname)
@@ -6,8 +6,8 @@
6
6
 
7
7
  // 无边框模式:显示自绘标题栏并绑定按钮。
8
8
  // 壳桥接(__freedom_window)注入时机与页面脚本加载先后不定,早期调用可能被 reject 吞掉导致标题栏不显示,
9
- // 因此先轮询等待桥接就绪(最多 100 次 × 100ms)再初始化。
10
- function waitForBridge(tries = 100, interval = 100) {
9
+ // 因此先轮询等待桥接就绪(最多 150 次 × 100ms = 15s)再初始化;超时后明确告警而非静默失效。
10
+ function waitForBridge(tries = 150, interval = 100) {
11
11
  return new Promise((resolve) => {
12
12
  const check = () => {
13
13
  if (window.freedom && window.freedom.window && typeof window.__freedom_window === 'function') {
@@ -47,7 +47,11 @@ async function syncMaxState(w) {
47
47
  }
48
48
 
49
49
  async function initFrameless() {
50
- if (!(await waitForBridge())) return;
50
+ const ready = await waitForBridge();
51
+ if (!ready) {
52
+ console.warn('[freedom] 桥接 15s 未就绪,无边框标题栏未初始化(窗口仍可正常使用)。');
53
+ return;
54
+ }
51
55
  try {
52
56
  const frameless = await window.freedom.window.isFrameless();
53
57
  if (!frameless) return;
@@ -148,11 +152,14 @@ function initTitlebarMenu() {
148
152
  initTitlebarMenu();
149
153
  initFrameless();
150
154
 
151
- // 桥接自检。
155
+ // 桥接自检:__freedom__ping 是壳注入的全局函数,优先直调;
156
+ // 低版本壳不存在时回退经 bridge 路由(壳层 bridge 对 ping 特判兼容)。
152
157
  document.getElementById('pingBtn').addEventListener('click', async () => {
153
158
  const el = document.getElementById('result');
154
159
  try {
155
- const r = await window.freedom.call('__freedom__ping');
160
+ const r = (typeof window.__freedom__ping === 'function')
161
+ ? await window.__freedom__ping()
162
+ : await window.freedom.call('__freedom__ping');
156
163
  el.textContent = '桥接正常:' + r;
157
164
  } catch (e) {
158
165
  el.textContent = '桥接异常:' + e.message;
File without changes
@@ -1,2 +0,0 @@
1
- # freedom-cli-shell/pkg/freedom
2
- pkg\freedom\freedom.go:212:16: cannot use a.backend.Handle(method, params) (value of type interface{}) as json.RawMessage value in assignment: need type assertion
File without changes
File without changes
File without changes
File without changes
@@ -1 +0,0 @@
1
- github.com/webview/webview_go: build constraints exclude all Go files in D:\dev\自研desktop exe打包框架\freedom-cli\templates\go\webview_go
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,11 +0,0 @@
1
- module freedom-cli-shell
2
-
3
- go 1.22
4
-
5
- require github.com/webview/webview_go v0.0.0-20240831120633-6173450d4dd6
6
-
7
- require golang.org/x/sys v0.28.0
8
-
9
- // Freedom fork: 使用随包分发的本地 webview_go(标题栏图标与 exe 图标一致等定制),
10
- // 避免拉取上游被覆盖。
11
- replace github.com/webview/webview_go => ./webview_go
File without changes
File without changes