-
-
Notifications
You must be signed in to change notification settings - Fork 455
Expand file tree
/
Copy pathwry_web_view_parent.rs
More file actions
142 lines (126 loc) · 5.06 KB
/
wry_web_view_parent.rs
File metadata and controls
142 lines (126 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2020-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
#[cfg(target_os = "macos")]
use objc2::DefinedClass;
use objc2::{define_class, msg_send, rc::Retained, MainThreadOnly};
#[cfg(target_os = "macos")]
use objc2_app_kit::{
NSApplication, NSEvent, NSEventModifierFlags, NSView, NSWindow, NSWindowButton,
};
use objc2_foundation::MainThreadMarker;
#[cfg(target_os = "macos")]
use objc2_foundation::{NSArray, NSRect};
#[cfg(target_os = "ios")]
use objc2_ui_kit::UIView as NSView;
pub struct WryWebViewParentIvars {
#[cfg(target_os = "macos")]
traffic_light_inset: std::cell::Cell<Option<(f64, f64)>>,
}
define_class!(
#[unsafe(super(NSView))]
#[ivars = WryWebViewParentIvars]
pub struct WryWebViewParent;
/// Overridden NSView methods.
impl WryWebViewParent {
#[cfg(target_os = "macos")]
#[unsafe(method(keyDown:))]
fn key_down(&self, event: &NSEvent) {
let flags = unsafe { event.modifierFlags() };
// Only attempt menu key equivalents when Command or Control modifiers
// are held. Without this guard, ALL keyDown events (including bare
// number keys, symbols, and arrow keys) are sent to
// `performKeyEquivalent` which silently swallows them when no menu
// item matches, preventing the events from ever reaching the
// WKWebView content — especially problematic for iframe-based apps.
//
// Note: Option (Alt) is intentionally excluded — Option+key
// combinations are used for special character input (e.g.,
// Option+e for accent marks) and routing them to
// performKeyEquivalent would break dead-key / compose input.
//
// Refs: https://github.com/tauri-apps/wry/issues/1175
// https://github.com/tauri-apps/wry/issues/1177
if flags.intersects(NSEventModifierFlags::Command | NSEventModifierFlags::Control) {
let mtm = MainThreadMarker::new().unwrap();
let app = NSApplication::sharedApplication(mtm);
unsafe {
if let Some(menu) = app.mainMenu() {
if menu.performKeyEquivalent(event) {
return;
}
}
}
}
// Events reaching here were not handled by the WKWebView (first
// responder) or matched a menu shortcut. We call interpretKeyEvents
// on self (the parent NSView) purely to suppress the NSBeep that
// super.keyDown would produce (see PR #742). The parent has no
// NSTextInputClient, so this is effectively a no-op sink for
// unhandled keys.
unsafe {
self.interpretKeyEvents(&NSArray::from_slice(&[event]));
}
}
#[cfg(target_os = "macos")]
#[unsafe(method(drawRect:))]
fn draw(&self, _dirty_rect: NSRect) {
if let Some((x, y)) = self.ivars().traffic_light_inset.get() {
unsafe { inset_traffic_lights(&self.window().unwrap(), x, y) };
}
}
}
);
impl WryWebViewParent {
#[allow(dead_code)]
pub fn new(mtm: MainThreadMarker) -> Retained<Self> {
let delegate = WryWebViewParent::alloc(mtm).set_ivars(WryWebViewParentIvars {
#[cfg(target_os = "macos")]
traffic_light_inset: Default::default(),
});
unsafe { msg_send![super(delegate), init] }
}
#[cfg(target_os = "macos")]
pub fn set_traffic_light_inset(&self, ns_window: &NSWindow, position: dpi::Position) {
let scale_factor = NSWindow::backingScaleFactor(ns_window);
let position = position.to_logical(scale_factor);
self
.ivars()
.traffic_light_inset
.replace(Some((position.x, position.y)));
unsafe {
inset_traffic_lights(ns_window, position.x, position.y);
}
}
}
#[cfg(target_os = "macos")]
pub unsafe fn inset_traffic_lights(window: &NSWindow, x: f64, y: f64) {
let Some(close) = window.standardWindowButton(NSWindowButton::CloseButton) else {
#[cfg(feature = "tracing")]
tracing::warn!("skipping inset_traffic_lights, close button not found");
return;
};
let Some(miniaturize) = window.standardWindowButton(NSWindowButton::MiniaturizeButton) else {
#[cfg(feature = "tracing")]
tracing::warn!("skipping inset_traffic_lights, miniaturize button not found");
return;
};
let zoom = window.standardWindowButton(NSWindowButton::ZoomButton);
let title_bar_container_view = close.superview().unwrap().superview().unwrap();
let close_rect = NSView::frame(&close);
let title_bar_frame_height = close_rect.size.height + y;
let mut title_bar_rect = NSView::frame(&title_bar_container_view);
title_bar_rect.size.height = title_bar_frame_height;
title_bar_rect.origin.y = window.frame().size.height - title_bar_frame_height;
title_bar_container_view.setFrame(title_bar_rect);
let space_between = NSView::frame(&miniaturize).origin.x - close_rect.origin.x;
let mut window_buttons = vec![close, miniaturize];
if let Some(zoom) = zoom {
window_buttons.push(zoom);
}
for (i, button) in window_buttons.into_iter().enumerate() {
let mut rect = NSView::frame(&button);
rect.origin.x = x + (i as f64 * space_between);
button.setFrameOrigin(rect.origin);
}
}