mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Compare commits
1 Commits
notgull/wi
...
madsmtm/dp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d94b067e0c |
15
Cargo.toml
15
Cargo.toml
@@ -25,6 +25,7 @@ version = "0.30.5"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = [
|
||||
"rwh_06",
|
||||
"serde",
|
||||
"mint",
|
||||
# Enabled to get docs to compile
|
||||
@@ -54,8 +55,9 @@ targets = [
|
||||
[features]
|
||||
android-game-activity = ["android-activity/game-activity"]
|
||||
android-native-activity = ["android-activity/native-activity"]
|
||||
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
|
||||
default = ["rwh_06", "x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
|
||||
mint = ["dpi/mint"]
|
||||
rwh_06 = ["dep:rwh_06", "ndk/rwh_06"]
|
||||
serde = ["dep:serde", "cursor-icon/serde", "smol_str/serde", "dpi/serde", "bitflags/serde"]
|
||||
wayland = [
|
||||
"wayland-client",
|
||||
@@ -79,7 +81,7 @@ cfg_aliases = "0.2.1"
|
||||
bitflags = "2"
|
||||
cursor-icon = "1.1.0"
|
||||
dpi = { version = "0.1.1", path = "dpi" }
|
||||
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"] }
|
||||
rwh_06 = { package = "raw-window-handle", version = "0.6", features = ["std"], optional = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
smol_str = "0.2.0"
|
||||
tracing = { version = "0.1.40", default-features = false }
|
||||
@@ -100,7 +102,7 @@ softbuffer = { version = "0.4.6", default-features = false, features = [
|
||||
# Android
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android-activity = "0.6.0"
|
||||
ndk = { version = "0.9.0", features = ["rwh_06"], default-features = false }
|
||||
ndk = { version = "0.9.0", default-features = false }
|
||||
|
||||
# AppKit or UIKit
|
||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||
@@ -134,7 +136,6 @@ objc2-app-kit = { version = "0.2.2", features = [
|
||||
"NSScreen",
|
||||
"NSTextInputClient",
|
||||
"NSTextInputContext",
|
||||
"NSToolbar",
|
||||
"NSView",
|
||||
"NSWindow",
|
||||
"NSWindowScripting",
|
||||
@@ -149,7 +150,6 @@ objc2-foundation = { version = "0.2.2", features = [
|
||||
"NSDictionary",
|
||||
"NSDistributedNotificationCenter",
|
||||
"NSEnumerator",
|
||||
"NSGeometry",
|
||||
"NSKeyValueObserving",
|
||||
"NSNotification",
|
||||
"NSObjCRuntime",
|
||||
@@ -212,10 +212,8 @@ windows-sys = { version = "0.52.0", features = [
|
||||
"Win32_Media",
|
||||
"Win32_System_Com_StructuredStorage",
|
||||
"Win32_System_Com",
|
||||
"Win32_System_Diagnostics_ToolHelp",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Ole",
|
||||
"Win32_Security",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Threading",
|
||||
@@ -298,7 +296,6 @@ web_sys = { package = "web-sys", version = "0.3.70", features = [
|
||||
"FocusEvent",
|
||||
"HtmlCanvasElement",
|
||||
"HtmlElement",
|
||||
"HtmlHtmlElement",
|
||||
"HtmlImageElement",
|
||||
"ImageBitmap",
|
||||
"ImageBitmapOptions",
|
||||
@@ -346,9 +343,11 @@ wasm-bindgen-test = "0.3"
|
||||
[[example]]
|
||||
doc-scrape-examples = true
|
||||
name = "window"
|
||||
required-features = ["rwh_06"]
|
||||
|
||||
[[example]]
|
||||
name = "child_window"
|
||||
required-features = ["rwh_06"]
|
||||
|
||||
[workspace]
|
||||
members = ["dpi"]
|
||||
|
||||
12
deny.toml
12
deny.toml
@@ -26,12 +26,12 @@ targets = [
|
||||
|
||||
[licenses]
|
||||
allow = [
|
||||
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
|
||||
"BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
|
||||
"BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
|
||||
"ISC", # https://tldrlegal.com/license/isc-license
|
||||
"MIT", # https://tldrlegal.com/license/mit-license
|
||||
"Unicode-3.0", # https://spdx.org/licenses/Unicode-3.0.html
|
||||
"Apache-2.0", # https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)
|
||||
"BSD-2-Clause", # https://tldrlegal.com/license/bsd-2-clause-license-(freebsd)
|
||||
"BSD-3-Clause", # https://tldrlegal.com/license/bsd-3-clause-license-(revised)
|
||||
"ISC", # https://tldrlegal.com/license/-isc-license
|
||||
"MIT", # https://tldrlegal.com/license/mit-license
|
||||
"Unicode-DFS-2016", # https://spdx.org/licenses/Unicode-DFS-2016.html
|
||||
]
|
||||
confidence-threshold = 1.0
|
||||
private = { ignore = true }
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0" version="24.8.6" pages="2">
|
||||
<diagram name="desktop" id="3DDum1nDijUk3y7wIDRm">
|
||||
<mxGraphModel dx="1080" dy="707" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1000" pageHeight="500" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-1" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#E8E8E8;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="80" width="480" height="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-4" value="" style="rounded=1;whiteSpace=wrap;html=1;shadow=0;fillColor=#d5e8d4;strokeColor=#666666;" parent="1" vertex="1">
|
||||
<mxGeometry x="260" y="340" width="360" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-2" value="" style="rounded=1;whiteSpace=wrap;html=1;shadow=0;fillColor=#dae8fc;strokeColor=#666666;" parent="1" vertex="1">
|
||||
<mxGeometry x="260" y="140" width="360" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-3" value="" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#DBDBDB;strokeColor=#666666;fontColor=#333333;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="60" width="480" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-5" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;fillColor=#d5e8d4;" parent="1" vertex="1">
|
||||
<mxGeometry x="260" y="180" width="360" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-6" value="" style="endArrow=none;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#666666;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-4" target="cRYnzpdCW-J0f_YpP3mc-2" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="10" y="310" as="sourcePoint" />
|
||||
<mxPoint x="60" y="260" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-7" value="" style="endArrow=none;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#666666;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-4" target="cRYnzpdCW-J0f_YpP3mc-2" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="770" y="570" as="sourcePoint" />
|
||||
<mxPoint x="770" y="210" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-8" value="" style="endArrow=none;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0;entryDx=0;entryDy=0;strokeColor=#666666;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-2" target="cRYnzpdCW-J0f_YpP3mc-5" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="220.00000000000023" y="179.69" as="sourcePoint" />
|
||||
<mxPoint x="740.0000000000002" y="179.69" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-9" value="<font>outer_position</font>" style="endArrow=blockThin;html=1;strokeWidth=3;rounded=0;exitX=0;exitY=0;exitDx=0;exitDy=0;dashed=1;align=right;fontSize=20;fontFamily=monospace;fontColor=#6C8EBF;labelBackgroundColor=none;spacingLeft=0;spacingRight=15;spacing=0;fillColor=#dae8fc;strokeColor=#6C8EBF;endFill=1;startArrow=oval;startFill=1;endSize=6;targetPerimeterSpacing=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-3" edge="1" target="cRYnzpdCW-J0f_YpP3mc-2">
|
||||
<mxGeometry x="-0.36" y="-24" width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="80" y="160" as="sourcePoint" />
|
||||
<mxPoint x="240" y="160" as="targetPoint" />
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-10" value="<font>outer_size</font>" style="endArrow=none;html=1;strokeWidth=3;rounded=0;dashed=1;align=left;fontSize=20;fontFamily=monospace;fontColor=#6C8EBF;labelBackgroundColor=none;spacingLeft=15;spacingRight=0;spacing=0;exitX=1;exitY=0;exitDx=0;exitDy=0;fillColor=#dae8fc;strokeColor=#6c8ebf;entryX=1;entryY=1;entryDx=0;entryDy=0;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-2" edge="1" target="cRYnzpdCW-J0f_YpP3mc-4">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="850" y="170" as="sourcePoint" />
|
||||
<mxPoint x="760" y="420" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="860" y="140" />
|
||||
<mxPoint x="860" y="380" />
|
||||
</Array>
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-11" value="<font>surface_size</font>" style="endArrow=none;html=1;strokeWidth=3;rounded=0;dashed=1;align=left;fontSize=20;fontFamily=monospace;fontColor=#82B366;labelBackgroundColor=none;spacingLeft=15;spacingRight=0;spacing=0;entryX=1;entryY=1;entryDx=0;entryDy=0;fillColor=#d5e8d4;strokeColor=#82B366;" parent="1" target="cRYnzpdCW-J0f_YpP3mc-4" edge="1">
|
||||
<mxGeometry x="0.0526" width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="600" y="180" as="sourcePoint" />
|
||||
<mxPoint x="760" y="420" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="700" y="180" />
|
||||
<mxPoint x="700" y="380" />
|
||||
</Array>
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cRYnzpdCW-J0f_YpP3mc-12" value="<font>surface_position</font>" style="endArrow=blockThin;html=1;strokeWidth=3;rounded=0;dashed=1;align=right;fontSize=20;fontFamily=monospace;fontColor=#82B366;labelBackgroundColor=none;spacingLeft=0;spacingRight=15;spacing=0;fillColor=#d5e8d4;strokeColor=#82b366;exitX=0;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;curved=1;startArrow=oval;startFill=1;endFill=1;" parent="1" source="cRYnzpdCW-J0f_YpP3mc-2" target="cRYnzpdCW-J0f_YpP3mc-5" edge="1">
|
||||
<mxGeometry y="-50" width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="140" y="140" as="sourcePoint" />
|
||||
<mxPoint x="160" y="200" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="250" y="160" />
|
||||
</Array>
|
||||
<mxPoint x="-5" y="-22" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram name="mobile" id="D5mAeJSS4Z33KEKjPCBt">
|
||||
<mxGraphModel dx="1710" dy="1120" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="720" pageHeight="720" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-1" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E8E8E8;fontColor=#333333;strokeColor=#666666;" parent="1" vertex="1">
|
||||
<mxGeometry x="200" y="40" width="320" height="640" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-2" value="" style="rounded=1;whiteSpace=wrap;html=1;shadow=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
|
||||
<mxGeometry x="210" y="50" width="300" height="620" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-4" value="" style="rounded=0;whiteSpace=wrap;html=1;shadow=0;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="210" y="90" width="300" height="540" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-20" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBDBDB;strokeColor=#666666;fontColor=#333333;" parent="1" vertex="1">
|
||||
<mxGeometry x="290" y="640" width="140" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-3" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#DBDBDB;strokeColor=#666666;fontColor=#333333;" parent="1" vertex="1">
|
||||
<mxGeometry x="300" y="50" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="RxwCrVmIsQwV7z5iJ9nY-12" value="<font>surface_size</font>" style="endArrow=none;html=1;strokeWidth=3;rounded=0;dashed=1;align=left;fontSize=20;fontFamily=monospace;fontColor=#82B366;labelBackgroundColor=none;spacingLeft=15;spacingRight=15;spacing=0;fillColor=#d5e8d4;strokeColor=#82b366;exitX=1;exitY=0;exitDx=0;exitDy=0;" parent="1" source="RxwCrVmIsQwV7z5iJ9nY-2" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="210" y="50" as="sourcePoint" />
|
||||
<mxPoint x="510" y="670" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="560" y="50" />
|
||||
<mxPoint x="560" y="670" />
|
||||
</Array>
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NrHAzeOh65jb3hkBOxW9-1" value="<div>safe_area.top</div>" style="endArrow=blockThin;html=1;strokeWidth=3;rounded=0;align=right;fontSize=20;fontFamily=monospace;fontColor=#D79B00;labelBackgroundColor=none;spacingLeft=0;spacingRight=15;spacing=0;fillColor=#ffe6cc;strokeColor=#d79b00;startArrow=blockThin;startFill=1;endFill=1;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="180" y="50" as="sourcePoint" />
|
||||
<mxPoint x="180" y="90" as="targetPoint" />
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="NrHAzeOh65jb3hkBOxW9-5" value="<div>safe_area.bottom</div>" style="endArrow=blockThin;html=1;strokeWidth=3;rounded=0;align=right;fontSize=20;fontFamily=monospace;fontColor=#D79B00;labelBackgroundColor=none;spacingLeft=0;spacingRight=15;spacing=0;fillColor=#ffe6cc;strokeColor=#d79b00;startArrow=blockThin;startFill=1;endFill=1;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="180" y="670" as="sourcePoint" />
|
||||
<mxPoint x="180" y="630" as="targetPoint" />
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -9,10 +9,3 @@ by [Tomiĉo] (https://commons.wikimedia.org/wiki/User:Tomi%C4%89o). It was
|
||||
originally released under the [CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en)
|
||||
License. Minor modifications have been made by [John Nunley](https://github.com/notgull),
|
||||
which have been released under the same license as a derivative work.
|
||||
|
||||
## `coordinate-systems*`
|
||||
|
||||
These files are created by [Mads Marquart](https://github.com/madsmtm) using
|
||||
[draw.io](https://draw.io/), and compressed using [svgomg.net](https://svgomg.net/).
|
||||
|
||||
They are licensed under the [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 5.9 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="720" viewBox="-0.5 -0.5 720 720" class="ge-export-svg-auto"><defs><style><![CDATA[@media (prefers-color-scheme:dark){svg.ge-export-svg-auto svg:not(mjx-container>svg),svg.ge-export-svg-auto:not(mjx-container>svg){filter:invert(100%) hue-rotate(180deg)}}]]></style></defs><g data-cell-id="0"><g data-cell-id="1"><rect x="200" y="40" width="320" height="640" rx="48" ry="48" fill="#e8e8e8" stroke="#666" pointer-events="all" data-cell-id="RxwCrVmIsQwV7z5iJ9nY-1"/><rect x="210" y="50" width="300" height="620" rx="45" ry="45" fill="#d5e8d4" stroke="#82b366" pointer-events="all" data-cell-id="RxwCrVmIsQwV7z5iJ9nY-2"/><path fill="#ffe6cc" stroke="#d79b00" pointer-events="all" d="M210 90h300v540H210z" data-cell-id="RxwCrVmIsQwV7z5iJ9nY-4"/><rect x="290" y="640" width="140" height="10" rx="1.5" ry="1.5" fill="#dbdbdb" stroke="#666" pointer-events="all" data-cell-id="RxwCrVmIsQwV7z5iJ9nY-20"/><rect x="300" y="50" width="120" height="30" rx="4.5" ry="4.5" fill="#dbdbdb" stroke="#666" pointer-events="all" data-cell-id="RxwCrVmIsQwV7z5iJ9nY-3"/><g data-cell-id="RxwCrVmIsQwV7z5iJ9nY-12"><path d="M510 50h50v620h-50" fill="none" stroke="#82b366" stroke-width="3" stroke-miterlimit="10" stroke-dasharray="9 9" pointer-events="stroke"/><switch transform="translate(-.5 -.5)"><foreignObject style="overflow:visible;text-align:left" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe flex-start;width:1px;height:1px;padding-top:360px;margin-left:575px"><div style="box-sizing:border-box;font-size:0;text-align:left" data-drawio-colors="color: #82B366;"><div style="display:inline-block;font-size:20px;font-family:"monospace";color:#82b366;line-height:1.2;pointer-events:all;white-space:nowrap"><font>surface_size</font></div></div></div></foreignObject><text x="575" y="366" fill="#82B366" font-family=""monospace"" font-size="20">surfa...</text></switch></g><g data-cell-id="NrHAzeOh65jb3hkBOxW9-1"><path d="M180 62.35v15.3" fill="none" stroke="#d79b00" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="m180 53.35 3 9h-6ZM180 86.65l-3-9h6Z" fill="#d79b00" stroke="#d79b00" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><switch transform="translate(-.5 -.5)"><foreignObject style="overflow:visible;text-align:left" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe flex-end;width:1px;height:1px;padding-top:70px;margin-left:165px"><div style="box-sizing:border-box;font-size:0;text-align:right" data-drawio-colors="color: #D79B00;"><div style="display:inline-block;font-size:20px;font-family:"monospace";color:#d79b00;line-height:1.2;pointer-events:all;white-space:nowrap"><div>safe_area.top</div></div></div></div></foreignObject><text x="165" y="76" fill="#D79B00" font-family=""monospace"" font-size="20" text-anchor="end">safe_...</text></switch></g><g data-cell-id="NrHAzeOh65jb3hkBOxW9-5"><path d="M180 657.65v-15.3" fill="none" stroke="#d79b00" stroke-width="3" stroke-miterlimit="10" pointer-events="stroke"/><path d="m180 666.65-3-9h6ZM180 633.35l3 9h-6Z" fill="#d79b00" stroke="#d79b00" stroke-width="3" stroke-miterlimit="10" pointer-events="all"/><switch transform="translate(-.5 -.5)"><foreignObject style="overflow:visible;text-align:left" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display:flex;align-items:unsafe center;justify-content:unsafe flex-end;width:1px;height:1px;padding-top:650px;margin-left:165px"><div style="box-sizing:border-box;font-size:0;text-align:right" data-drawio-colors="color: #D79B00;"><div style="display:inline-block;font-size:20px;font-family:"monospace";color:#d79b00;line-height:1.2;pointer-events:all;white-space:nowrap"><div>safe_area.bottom</div></div></div></div></foreignObject><text x="165" y="656" fill="#D79B00" font-family=""monospace"" font-size="20" text-anchor="end">safe_...</text></switch></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -11,7 +11,7 @@ Unreleased` header.
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Added `Insets`, `LogicalInsets` and `PhysicalInsets` types.
|
||||
- Add `Rect`, `PhysicalRect` and `LogicalRect`.
|
||||
|
||||
## 0.1.1
|
||||
|
||||
|
||||
128
dpi/src/lib.rs
128
dpi/src/lib.rs
@@ -759,30 +759,24 @@ impl<P: Pixel> From<LogicalPosition<P>> for Position {
|
||||
}
|
||||
}
|
||||
|
||||
/// The logical distance between the edges of two rectangles.
|
||||
/// A rectangle represented in logical pixels.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct LogicalInsets<P> {
|
||||
/// The distance to the top edge.
|
||||
pub top: P,
|
||||
/// The distance to the left edge.
|
||||
pub left: P,
|
||||
/// The distance to the bottom edge.
|
||||
pub bottom: P,
|
||||
/// The distance to the right edge.
|
||||
pub right: P,
|
||||
pub struct LogicalRect<P> {
|
||||
pub origin: LogicalPosition<P>,
|
||||
pub size: LogicalSize<P>,
|
||||
}
|
||||
|
||||
impl<P> LogicalInsets<P> {
|
||||
impl<P> LogicalRect<P> {
|
||||
#[inline]
|
||||
pub const fn new(top: P, left: P, bottom: P, right: P) -> Self {
|
||||
Self { top, left, bottom, right }
|
||||
pub const fn new(origin: LogicalPosition<P>, size: LogicalSize<P>) -> Self {
|
||||
Self { origin, size }
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Pixel> LogicalInsets<P> {
|
||||
impl<P: Pixel> LogicalRect<P> {
|
||||
#[inline]
|
||||
pub fn from_physical<T: Into<PhysicalInsets<X>>, X: Pixel>(
|
||||
pub fn from_physical<T: Into<PhysicalRect<X>>, X: Pixel>(
|
||||
physical: T,
|
||||
scale_factor: f64,
|
||||
) -> Self {
|
||||
@@ -790,116 +784,92 @@ impl<P: Pixel> LogicalInsets<P> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalInsets<X> {
|
||||
assert!(validate_scale_factor(scale_factor));
|
||||
let top = self.top.into() * scale_factor;
|
||||
let left = self.left.into() * scale_factor;
|
||||
let bottom = self.bottom.into() * scale_factor;
|
||||
let right = self.right.into() * scale_factor;
|
||||
PhysicalInsets::new(top, left, bottom, right).cast()
|
||||
pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalRect<X> {
|
||||
let origin = self.origin.to_physical(scale_factor);
|
||||
let size = self.size.to_physical(scale_factor);
|
||||
PhysicalRect::new(origin, size)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cast<X: Pixel>(&self) -> LogicalInsets<X> {
|
||||
LogicalInsets {
|
||||
top: self.top.cast(),
|
||||
left: self.left.cast(),
|
||||
bottom: self.bottom.cast(),
|
||||
right: self.right.cast(),
|
||||
}
|
||||
pub fn cast<X: Pixel>(&self) -> LogicalRect<X> {
|
||||
LogicalRect { origin: self.origin.cast(), size: self.size.cast() }
|
||||
}
|
||||
}
|
||||
|
||||
/// The physical distance between the edges of two rectangles.
|
||||
/// A rectangle represented in physical pixels.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct PhysicalInsets<P> {
|
||||
/// The distance to the top edge.
|
||||
pub top: P,
|
||||
/// The distance to the left edge.
|
||||
pub left: P,
|
||||
/// The distance to the bottom edge.
|
||||
pub bottom: P,
|
||||
/// The distance to the right edge.
|
||||
pub right: P,
|
||||
pub struct PhysicalRect<P> {
|
||||
pub origin: PhysicalPosition<P>,
|
||||
pub size: PhysicalSize<P>,
|
||||
}
|
||||
|
||||
impl<P> PhysicalInsets<P> {
|
||||
impl<P> PhysicalRect<P> {
|
||||
#[inline]
|
||||
pub const fn new(top: P, left: P, bottom: P, right: P) -> Self {
|
||||
Self { top, left, bottom, right }
|
||||
pub const fn new(origin: PhysicalPosition<P>, size: PhysicalSize<P>) -> Self {
|
||||
Self { origin, size }
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Pixel> PhysicalInsets<P> {
|
||||
impl<P: Pixel> PhysicalRect<P> {
|
||||
#[inline]
|
||||
pub fn from_logical<T: Into<LogicalInsets<X>>, X: Pixel>(
|
||||
logical: T,
|
||||
scale_factor: f64,
|
||||
) -> Self {
|
||||
pub fn from_logical<T: Into<LogicalRect<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
|
||||
logical.into().to_physical(scale_factor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalInsets<X> {
|
||||
pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalRect<X> {
|
||||
assert!(validate_scale_factor(scale_factor));
|
||||
let top = self.top.into() / scale_factor;
|
||||
let left = self.left.into() / scale_factor;
|
||||
let bottom = self.bottom.into() / scale_factor;
|
||||
let right = self.right.into() / scale_factor;
|
||||
LogicalInsets::new(top, left, bottom, right).cast()
|
||||
let origin = self.origin.to_logical(scale_factor);
|
||||
let size = self.size.to_logical(scale_factor);
|
||||
LogicalRect::new(origin, size)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cast<X: Pixel>(&self) -> PhysicalInsets<X> {
|
||||
PhysicalInsets {
|
||||
top: self.top.cast(),
|
||||
left: self.left.cast(),
|
||||
bottom: self.bottom.cast(),
|
||||
right: self.right.cast(),
|
||||
}
|
||||
pub fn cast<X: Pixel>(&self) -> PhysicalRect<X> {
|
||||
PhysicalRect { origin: self.origin.cast(), size: self.size.cast() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Insets that are either physical or logical.
|
||||
/// A rectangle that's either physical or logical.
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Insets {
|
||||
Physical(PhysicalInsets<u32>),
|
||||
Logical(LogicalInsets<f64>),
|
||||
pub enum Rect {
|
||||
Physical(PhysicalRect<i32>),
|
||||
Logical(LogicalRect<f64>),
|
||||
}
|
||||
|
||||
impl Insets {
|
||||
pub fn new<S: Into<Self>>(insets: S) -> Self {
|
||||
insets.into()
|
||||
impl Rect {
|
||||
pub fn new<R: Into<Self>>(rect: R) -> Self {
|
||||
rect.into()
|
||||
}
|
||||
|
||||
pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalInsets<P> {
|
||||
pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalRect<P> {
|
||||
match *self {
|
||||
Self::Physical(insets) => insets.to_logical(scale_factor),
|
||||
Self::Logical(insets) => insets.cast(),
|
||||
Self::Physical(rect) => rect.to_logical(scale_factor),
|
||||
Self::Logical(rect) => rect.cast(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalInsets<P> {
|
||||
pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalRect<P> {
|
||||
match *self {
|
||||
Self::Physical(insets) => insets.cast(),
|
||||
Self::Logical(insets) => insets.to_physical(scale_factor),
|
||||
Self::Physical(rect) => rect.cast(),
|
||||
Self::Logical(rect) => rect.to_physical(scale_factor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Pixel> From<PhysicalInsets<P>> for Insets {
|
||||
impl<P: Pixel> From<PhysicalRect<P>> for Rect {
|
||||
#[inline]
|
||||
fn from(insets: PhysicalInsets<P>) -> Self {
|
||||
Self::Physical(insets.cast())
|
||||
fn from(rect: PhysicalRect<P>) -> Self {
|
||||
Self::Physical(rect.cast())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Pixel> From<LogicalInsets<P>> for Insets {
|
||||
impl<P: Pixel> From<LogicalRect<P>> for Rect {
|
||||
#[inline]
|
||||
fn from(insets: LogicalInsets<P>) -> Self {
|
||||
Self::Logical(insets.cast())
|
||||
fn from(rect: LogicalRect<P>) -> Self {
|
||||
Self::Logical(rect.cast())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
pub use platform::cleanup_window;
|
||||
pub use platform::fill_window;
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
#[cfg(all(feature = "rwh_06", not(any(target_os = "android", target_os = "ios"))))]
|
||||
mod platform {
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
@@ -106,7 +106,7 @@ mod platform {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
#[cfg(not(all(feature = "rwh_06", not(any(target_os = "android", target_os = "ios")))))]
|
||||
mod platform {
|
||||
pub fn fill_window(_window: &dyn winit::window::Window) {
|
||||
// No-op on mobile platforms.
|
||||
|
||||
@@ -31,8 +31,6 @@ use winit::platform::startup_notify::{
|
||||
};
|
||||
#[cfg(web_platform)]
|
||||
use winit::platform::web::{ActiveEventLoopExtWeb, CustomCursorExtWeb, WindowAttributesExtWeb};
|
||||
#[cfg(x11_platform)]
|
||||
use winit::platform::x11::WindowAttributesExtX11;
|
||||
use winit::window::{
|
||||
Cursor, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, Icon, ResizeDirection,
|
||||
Theme, Window, WindowAttributes, WindowId,
|
||||
@@ -151,28 +149,6 @@ impl Application {
|
||||
window_attributes = window_attributes.with_activation_token(token);
|
||||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
match std::env::var("X11_VISUAL_ID") {
|
||||
Ok(visual_id_str) => {
|
||||
info!("Using X11 visual id {visual_id_str}");
|
||||
let visual_id = visual_id_str.parse()?;
|
||||
window_attributes = window_attributes.with_x11_visual(visual_id);
|
||||
},
|
||||
Err(_) => info!("Set the X11_VISUAL_ID env variable to request specific X11 visual"),
|
||||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
match std::env::var("X11_SCREEN_ID") {
|
||||
Ok(screen_id_str) => {
|
||||
info!("Placing the window on X11 screen {screen_id_str}");
|
||||
let screen_id = screen_id_str.parse()?;
|
||||
window_attributes = window_attributes.with_x11_screen(screen_id);
|
||||
},
|
||||
Err(_) => info!(
|
||||
"Set the X11_SCREEN_ID env variable to place the window on non-default screen"
|
||||
),
|
||||
}
|
||||
|
||||
#[cfg(macos_platform)]
|
||||
if let Some(tab_id) = _tab_id {
|
||||
window_attributes = window_attributes.with_tabbing_identifier(&tab_id);
|
||||
@@ -242,10 +218,6 @@ impl Application {
|
||||
Action::ToggleResizable => window.toggle_resizable(),
|
||||
Action::ToggleDecorations => window.toggle_decorations(),
|
||||
Action::ToggleFullscreen => window.toggle_fullscreen(),
|
||||
#[cfg(macos_platform)]
|
||||
Action::ToggleSimpleFullscreen => {
|
||||
window.window.set_simple_fullscreen(!window.window.simple_fullscreen());
|
||||
},
|
||||
Action::ToggleMaximize => window.toggle_maximize(),
|
||||
Action::ToggleImeInput => window.toggle_ime(),
|
||||
Action::Minimize => window.minimize(),
|
||||
@@ -945,38 +917,18 @@ impl WindowState {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
const WHITE: u32 = 0xffffffff;
|
||||
const DARK_GRAY: u32 = 0xff181818;
|
||||
|
||||
let color = match self.theme {
|
||||
Theme::Light => WHITE,
|
||||
Theme::Dark => DARK_GRAY,
|
||||
};
|
||||
|
||||
let mut buffer = self.surface.buffer_mut()?;
|
||||
|
||||
// Draw a different color inside the safe area
|
||||
let surface_size = self.window.surface_size();
|
||||
let insets = self.window.safe_area();
|
||||
for y in 0..surface_size.height {
|
||||
for x in 0..surface_size.width {
|
||||
let index = y as usize * surface_size.width as usize + x as usize;
|
||||
if insets.left <= x
|
||||
&& x <= (surface_size.width - insets.right)
|
||||
&& insets.top <= y
|
||||
&& y <= (surface_size.height - insets.bottom)
|
||||
{
|
||||
// In safe area
|
||||
buffer[index] = match self.theme {
|
||||
Theme::Light => 0xffe8e8e8, // Light gray
|
||||
Theme::Dark => 0xff525252, // Medium gray
|
||||
};
|
||||
} else {
|
||||
// Outside safe area
|
||||
buffer[index] = match self.theme {
|
||||
Theme::Light => 0xffffffff, // White
|
||||
Theme::Dark => 0xff181818, // Dark gray
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Present the buffer
|
||||
buffer.fill(color);
|
||||
self.window.pre_present_notify();
|
||||
buffer.present()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1013,8 +965,6 @@ enum Action {
|
||||
ToggleDecorations,
|
||||
ToggleResizable,
|
||||
ToggleFullscreen,
|
||||
#[cfg(macos_platform)]
|
||||
ToggleSimpleFullscreen,
|
||||
ToggleMaximize,
|
||||
Minimize,
|
||||
NextCursor,
|
||||
@@ -1048,8 +998,6 @@ impl Action {
|
||||
Action::ToggleDecorations => "Toggle decorations",
|
||||
Action::ToggleResizable => "Toggle window resizable state",
|
||||
Action::ToggleFullscreen => "Toggle fullscreen",
|
||||
#[cfg(macos_platform)]
|
||||
Action::ToggleSimpleFullscreen => "Toggle simple fullscreen",
|
||||
Action::ToggleMaximize => "Maximize",
|
||||
Action::Minimize => "Minimize",
|
||||
Action::ToggleResizeIncrements => "Use resize increments when resizing window",
|
||||
@@ -1192,8 +1140,6 @@ const KEY_BINDINGS: &[Binding<&'static str>] = &[
|
||||
Binding::new("Q", ModifiersState::CONTROL, Action::CloseWindow),
|
||||
Binding::new("H", ModifiersState::CONTROL, Action::PrintHelp),
|
||||
Binding::new("F", ModifiersState::CONTROL, Action::ToggleFullscreen),
|
||||
#[cfg(macos_platform)]
|
||||
Binding::new("F", ModifiersState::ALT, Action::ToggleSimpleFullscreen),
|
||||
Binding::new("D", ModifiersState::CONTROL, Action::ToggleDecorations),
|
||||
Binding::new("I", ModifiersState::CONTROL, Action::ToggleImeInput),
|
||||
Binding::new("L", ModifiersState::CONTROL, Action::CycleCursorGrab),
|
||||
|
||||
@@ -59,22 +59,15 @@ changelog entry.
|
||||
- Implement `Clone`, `Copy`, `Debug`, `Deserialize`, `Eq`, `Hash`, `Ord`, `PartialEq`, `PartialOrd`
|
||||
and `Serialize` on many types.
|
||||
- Add `MonitorHandle::current_video_mode()`.
|
||||
- On Android, the soft keyboard can now be shown using `Window::set_ime_allowed`.
|
||||
- Add basic iOS IME support. The soft keyboard can now be shown using `Window::set_ime_allowed`.
|
||||
- Add `ApplicationHandlerExtMacOS` trait, and a `macos_handler` method to `ApplicationHandler` which returns a `dyn ApplicationHandlerExtMacOS` which allows for macOS specific extensions to winit.
|
||||
- Add a `standard_key_binding` method to the `ApplicationHandlerExtMacOS` trait. This allows handling of standard keybindings such as "go to end of line" on macOS.
|
||||
- On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game`
|
||||
to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games.
|
||||
- On macOS, add `WindowExtMacOS::set_unified_titlebar` and `WindowAttributesExtMacOS::with_unified_titlebar`
|
||||
to use a larger style of titlebar.
|
||||
- Add `WindowId::into_raw()` and `from_raw()`.
|
||||
- Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId`, `primary` and `position` to all
|
||||
pointer events as part of the pointer event overhaul.
|
||||
- Add `PointerKind`, `PointerSource`, `ButtonSource`, `FingerId` and `position` to all pointer
|
||||
events as part of the pointer event overhaul.
|
||||
- Add `DeviceId::into_raw()` and `from_raw()`.
|
||||
- On X11, the `window` example now understands the `X11_VISUAL_ID` and `X11_SCREEN_ID` env
|
||||
variables to test the respective modifiers of window creation.
|
||||
- Added `Window::surface_position`, which is the position of the surface inside the window.
|
||||
- Added `Window::safe_area`, which describes the area of the surface that is unobstructed.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -143,8 +136,6 @@ changelog entry.
|
||||
- Rename `CursorEntered` to `PointerEntered`.
|
||||
- Rename `CursorLeft` to `PointerLeft`.
|
||||
- Rename `MouseInput` to `PointerButton`.
|
||||
- Add `primary` to every `PointerEvent` as a way to identify discard non-primary pointers in a
|
||||
multi-touch interaction.
|
||||
- Add `position` to every `PointerEvent`.
|
||||
- `PointerMoved` is **not sent** after `PointerEntered` anymore.
|
||||
- Remove `Touch`, which is folded into the `Pointer*` events.
|
||||
@@ -157,9 +148,10 @@ changelog entry.
|
||||
type to a generic mouse button.
|
||||
- New `FingerId` added to `PointerKind::Touch` and `PointerSource::Touch` able to uniquely
|
||||
identify a finger in a multi-touch interaction. Replaces the old `Touch::id`.
|
||||
- On Web and Windows, add `FingerIdExt*::is_primary()`, exposing a way to determine
|
||||
the primary finger in a multi-touch interaction.
|
||||
- In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`.
|
||||
- Remove `Force::Calibrated::altitude_angle`.
|
||||
- On X11, use bottom-right corner for IME hotspot in `Window::set_ime_cursor_area`.
|
||||
|
||||
### Removed
|
||||
|
||||
@@ -191,7 +183,6 @@ changelog entry.
|
||||
- Remove `WindowEvent::Touch` and `Touch` in favor of the new `PointerKind`, `PointerSource` and
|
||||
`ButtonSource` as part of the new pointer event overhaul.
|
||||
- Remove `Force::altitude_angle`.
|
||||
- Removed `Window::inner_position`, use the new `Window::surface_position` instead.
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -201,8 +192,3 @@ changelog entry.
|
||||
default activation policy, unless explicitly provided during initialization.
|
||||
- On macOS, fix crash when calling `drag_window()` without a left click present.
|
||||
- On X11, key events forward to IME anyway, even when it's disabled.
|
||||
- On Windows, make `ControlFlow::WaitUntil` work more precisely using `CREATE_WAITABLE_TIMER_HIGH_RESOLUTION`.
|
||||
- On X11, creating windows on screen that is not the first one (e.g. `DISPLAY=:0.1`) works again.
|
||||
- On X11, creating windows while passing `with_x11_screen(non_default_screen)` works again.
|
||||
- On X11, fix XInput handling that prevented a new window from getting the focus in some cases.
|
||||
- On iOS, fixed `SurfaceResized` and `Window::surface_size` not reporting the size of the actual surface.
|
||||
|
||||
65
src/event.rs
65
src/event.rs
@@ -156,10 +156,7 @@ pub enum WindowEvent {
|
||||
/// [`Window::surface_size`]: crate::window::Window::surface_size
|
||||
SurfaceResized(PhysicalSize<u32>),
|
||||
|
||||
/// The position of the window has changed.
|
||||
///
|
||||
/// Contains the window's new position in desktop coordinates (can also be retrieved with
|
||||
/// [`Window::outer_position`]).
|
||||
/// The position of the window has changed. Contains the window's new position.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
@@ -248,12 +245,6 @@ pub enum WindowEvent {
|
||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
position: PhysicalPosition<f64>,
|
||||
|
||||
/// Indicates whether the event is created by a primary pointer.
|
||||
///
|
||||
/// A pointer is considered primary when it's a mouse, the first finger in a multi-touch
|
||||
/// interaction, or an unknown pointer source.
|
||||
primary: bool,
|
||||
|
||||
source: PointerSource,
|
||||
},
|
||||
|
||||
@@ -273,12 +264,6 @@ pub enum WindowEvent {
|
||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
position: PhysicalPosition<f64>,
|
||||
|
||||
/// Indicates whether the event is created by a primary pointer.
|
||||
///
|
||||
/// A pointer is considered primary when it's a mouse, the first finger in a multi-touch
|
||||
/// interaction, or an unknown pointer source.
|
||||
primary: bool,
|
||||
|
||||
kind: PointerKind,
|
||||
},
|
||||
|
||||
@@ -299,12 +284,6 @@ pub enum WindowEvent {
|
||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
position: Option<PhysicalPosition<f64>>,
|
||||
|
||||
/// Indicates whether the event is created by a primary pointer.
|
||||
///
|
||||
/// A pointer is considered primary when it's a mouse, the first finger in a multi-touch
|
||||
/// interaction, or an unknown pointer source.
|
||||
primary: bool,
|
||||
|
||||
kind: PointerKind,
|
||||
},
|
||||
|
||||
@@ -328,12 +307,6 @@ pub enum WindowEvent {
|
||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
position: PhysicalPosition<f64>,
|
||||
|
||||
/// Indicates whether the event is created by a primary pointer.
|
||||
///
|
||||
/// A pointer is considered primary when it's a mouse, the first finger in a multi-touch
|
||||
/// interaction, or an unknown pointer source.
|
||||
primary: bool,
|
||||
|
||||
button: ButtonSource,
|
||||
},
|
||||
|
||||
@@ -472,15 +445,13 @@ pub enum WindowEvent {
|
||||
|
||||
/// Emitted when a window should be redrawn.
|
||||
///
|
||||
/// This gets triggered in a few scenarios:
|
||||
/// This gets triggered in two scenarios:
|
||||
/// - The OS has performed an operation that's invalidated the window's contents (such as
|
||||
/// resizing the window, or changing [the safe area]).
|
||||
/// resizing the window).
|
||||
/// - The application has explicitly requested a redraw via [`Window::request_redraw`].
|
||||
///
|
||||
/// Winit will aggregate duplicate redraw requests into a single event, to
|
||||
/// help avoid duplicating rendering work.
|
||||
///
|
||||
/// [the safe area]: crate::window::Window::safe_area
|
||||
RedrawRequested,
|
||||
}
|
||||
|
||||
@@ -639,23 +610,12 @@ impl DeviceId {
|
||||
/// Whenever a touch event is received it contains a `FingerId` which uniquely identifies the finger
|
||||
/// used for the current interaction.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId(pub(crate) usize);
|
||||
pub struct FingerId(pub(crate) platform_impl::FingerId);
|
||||
|
||||
impl FingerId {
|
||||
/// Convert the [`FingerId`] into the underlying integer.
|
||||
///
|
||||
/// This is useful if you need to pass the ID across an FFI boundary, or store it in an atomic.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const fn into_raw(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Construct a [`FingerId`] from the underlying integer.
|
||||
///
|
||||
/// This should only be called with integers returned from [`FingerId::into_raw`].
|
||||
#[allow(dead_code)]
|
||||
pub(crate) const fn from_raw(id: usize) -> Self {
|
||||
Self(id)
|
||||
#[cfg(test)]
|
||||
pub(crate) const fn dummy() -> Self {
|
||||
FingerId(platform_impl::FingerId::dummy())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1170,7 +1130,7 @@ mod tests {
|
||||
($closure:expr) => {{
|
||||
#[allow(unused_mut)]
|
||||
let mut x = $closure;
|
||||
let fid = event::FingerId::from_raw(0);
|
||||
let fid = event::FingerId::dummy();
|
||||
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
@@ -1202,19 +1162,16 @@ mod tests {
|
||||
with_window_event(Ime(Enabled));
|
||||
with_window_event(PointerMoved {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: (0, 0).into(),
|
||||
source: PointerSource::Mouse,
|
||||
});
|
||||
with_window_event(ModifiersChanged(event::Modifiers::default()));
|
||||
with_window_event(PointerEntered {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: (0, 0).into(),
|
||||
kind: PointerKind::Mouse,
|
||||
});
|
||||
with_window_event(PointerLeft {
|
||||
primary: true,
|
||||
device_id: None,
|
||||
position: Some((0, 0).into()),
|
||||
kind: PointerKind::Mouse,
|
||||
@@ -1226,14 +1183,12 @@ mod tests {
|
||||
});
|
||||
with_window_event(PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: event::ElementState::Pressed,
|
||||
position: (0, 0).into(),
|
||||
button: event::MouseButton::Other(0).into(),
|
||||
});
|
||||
with_window_event(PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: event::ElementState::Released,
|
||||
position: (0, 0).into(),
|
||||
button: event::ButtonSource::Touch {
|
||||
@@ -1303,11 +1258,11 @@ mod tests {
|
||||
#[test]
|
||||
fn ensure_attrs_do_not_panic() {
|
||||
foreach_event!(|event: event::Event| {
|
||||
let _ = format!("{event:?}");
|
||||
let _ = format!("{:?}", event);
|
||||
});
|
||||
let _ = event::StartCause::Init.clone();
|
||||
|
||||
let fid = crate::event::FingerId::from_raw(0).clone();
|
||||
let fid = crate::event::FingerId::dummy().clone();
|
||||
HashSet::new().insert(fid);
|
||||
let mut set = [fid, fid, fid];
|
||||
set.sort_unstable();
|
||||
|
||||
@@ -13,11 +13,9 @@ use std::marker::PhantomData;
|
||||
#[cfg(any(x11_platform, wayland_platform))]
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
#[cfg(not(web_platform))]
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use rwh_06::{DisplayHandle, HandleError, HasDisplayHandle};
|
||||
#[cfg(web_platform)]
|
||||
use web_time::{Duration, Instant};
|
||||
|
||||
@@ -275,9 +273,10 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDisplayHandle for EventLoop {
|
||||
fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
|
||||
HasDisplayHandle::display_handle(self.event_loop.window_target().rwh_06_handle())
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for EventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target().rwh_06_handle())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,11 +407,13 @@ pub trait ActiveEventLoop: AsAny {
|
||||
fn owned_display_handle(&self) -> OwnedDisplayHandle;
|
||||
|
||||
/// Get the raw-window-handle handle.
|
||||
fn rwh_06_handle(&self) -> &dyn HasDisplayHandle;
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle;
|
||||
}
|
||||
|
||||
impl HasDisplayHandle for dyn ActiveEventLoop + '_ {
|
||||
fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for dyn ActiveEventLoop + '_ {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
self.rwh_06_handle().display_handle()
|
||||
}
|
||||
}
|
||||
@@ -429,55 +430,36 @@ impl HasDisplayHandle for dyn ActiveEventLoop + '_ {
|
||||
///
|
||||
/// - A zero-sized type that is likely optimized out.
|
||||
/// - A reference-counted pointer to the underlying type.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct OwnedDisplayHandle {
|
||||
pub(crate) handle: Arc<dyn HasDisplayHandle>,
|
||||
}
|
||||
|
||||
impl OwnedDisplayHandle {
|
||||
pub(crate) fn new(handle: Arc<dyn HasDisplayHandle>) -> Self {
|
||||
Self { handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
|
||||
self.handle.display_handle()
|
||||
}
|
||||
#[cfg_attr(not(feature = "rwh_06"), allow(dead_code))]
|
||||
pub(crate) platform: platform_impl::OwnedDisplayHandle,
|
||||
}
|
||||
|
||||
impl fmt::Debug for OwnedDisplayHandle {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for OwnedDisplayHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.display_handle(), other.display_handle()) {
|
||||
(Ok(lhs), Ok(rhs)) => lhs == rhs,
|
||||
_ => false,
|
||||
}
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
#[inline]
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.platform.raw_display_handle_rwh_06()?;
|
||||
|
||||
// SAFETY: The underlying display handle should be safe.
|
||||
let handle = unsafe { rwh_06::DisplayHandle::borrow_raw(raw) };
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for OwnedDisplayHandle {}
|
||||
|
||||
pub(crate) trait EventLoopProxyProvider: Send + Sync {
|
||||
/// See [`EventLoopProxy::wake_up`] for details.
|
||||
fn wake_up(&self);
|
||||
}
|
||||
|
||||
/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly.
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
pub(crate) proxy: Arc<dyn EventLoopProxyProvider>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for EventLoopProxy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("EventLoopProxy").finish_non_exhaustive()
|
||||
}
|
||||
pub(crate) event_loop_proxy: platform_impl::EventLoopProxy,
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
@@ -497,11 +479,13 @@ impl EventLoopProxy {
|
||||
///
|
||||
/// [#3687]: https://github.com/rust-windowing/winit/pull/3687
|
||||
pub fn wake_up(&self) {
|
||||
self.proxy.wake_up();
|
||||
self.event_loop_proxy.wake_up();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(proxy: Arc<dyn EventLoopProxyProvider>) -> Self {
|
||||
Self { proxy }
|
||||
impl fmt::Debug for EventLoopProxy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ActiveEventLoop").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
71
src/lib.rs
71
src/lib.rs
@@ -7,12 +7,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use winit::event_loop::EventLoop;
|
||||
//!
|
||||
//! # // Intentionally use `fn main` for clarity
|
||||
//! fn main() {
|
||||
//! let event_loop = EventLoop::new().unwrap();
|
||||
//! // ...
|
||||
//! }
|
||||
//! let event_loop = EventLoop::new().unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Then you create a [`Window`] with [`create_window`].
|
||||
@@ -88,22 +83,19 @@
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! # // Intentionally use `fn main` for clarity
|
||||
//! fn main() {
|
||||
//! let event_loop = EventLoop::new().unwrap();
|
||||
//! let event_loop = EventLoop::new().unwrap();
|
||||
//!
|
||||
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
||||
//! // dispatched any events. This is ideal for games and similar applications.
|
||||
//! event_loop.set_control_flow(ControlFlow::Poll);
|
||||
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
||||
//! // dispatched any events. This is ideal for games and similar applications.
|
||||
//! event_loop.set_control_flow(ControlFlow::Poll);
|
||||
//!
|
||||
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
|
||||
//! // This is ideal for non-game applications that only update in response to user
|
||||
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
||||
//! event_loop.set_control_flow(ControlFlow::Wait);
|
||||
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
|
||||
//! // This is ideal for non-game applications that only update in response to user
|
||||
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
||||
//! event_loop.set_control_flow(ControlFlow::Wait);
|
||||
//!
|
||||
//! let mut app = App::default();
|
||||
//! event_loop.run_app(&mut app);
|
||||
//! }
|
||||
//! let mut app = App::default();
|
||||
//! event_loop.run_app(&mut app);
|
||||
//! ```
|
||||
//!
|
||||
//! [`WindowEvent`] has a [`WindowId`] member. In multi-window environments, it should be
|
||||
@@ -123,45 +115,6 @@
|
||||
//! [`visible` set to `false`][crate::window::WindowAttributes::with_visible] and explicitly make
|
||||
//! the window visible only once you're ready to render into it.
|
||||
//!
|
||||
//! There is another important concept you need to know about when drawing: the "safe area". This
|
||||
//! can be accessed with [`Window::safe_area`], and describes a rectangle in the surface that is not
|
||||
//! obscured by notches, the status bar, and so on. You should be drawing your background and
|
||||
//! non-important content on the entire surface, but restrict important content (such as
|
||||
//! interactable UIs, text, etc.) to only being drawn inside the safe area.
|
||||
//!
|
||||
//! [`Window::safe_area`]: crate::window::Window::safe_area
|
||||
//!
|
||||
//! # Coordinate systems
|
||||
//!
|
||||
//! Windowing systems use many different coordinate systems, and this is reflected in Winit as well;
|
||||
//! there are "desktop coordinates", which is the coordinates of a window or monitor relative to the
|
||||
//! desktop at large, "window coordinates" which is the coordinates of the surface, relative to the
|
||||
//! window, and finally "surface coordinates", which is the coordinates relative to the drawn
|
||||
//! surface. All of these coordinates are relative to the top-left corner of their respective
|
||||
//! origin.
|
||||
//!
|
||||
//! Most of the functionality in Winit works with surface coordinates, so usually you only need to
|
||||
//! concern yourself with those. In case you need to convert to some other coordinate system, Winit
|
||||
//! provides [`Window::surface_position`] and [`Window::surface_size`] to describe the surface's
|
||||
//! location in window coordinates, and Winit provides [`Window::outer_position`] and
|
||||
//! [`Window::outer_size`] to describe the window's location in desktop coordinates. Using these
|
||||
//! methods, you should be able to convert a position in one coordinate system to another.
|
||||
//!
|
||||
//! An overview of how these four methods fit together can be seen in the image below:
|
||||
#![doc = concat!("\n\n", include_str!("../docs/res/coordinate-systems-desktop.svg"), "\n\n")] // Rustfmt removes \n, adding them like this works around that.
|
||||
//! On mobile, the situation is usually a bit different; because of the smaller screen space,
|
||||
//! windows usually fill the whole screen at a time, and as such there is _rarely_ a difference
|
||||
//! between these three coordinate systems, although you should still strive to handle this, as
|
||||
//! they're still relevant in more niche area such as Mac Catalyst, or multi-tasking on tablets.
|
||||
//!
|
||||
//! This is illustrated in the image below, along with the safe area since it's often relevant on
|
||||
//! mobile.
|
||||
#![doc = concat!("\n\n", include_str!("../docs/res/coordinate-systems-mobile.svg"), "\n\n")] // Rustfmt removes \n, adding them like this works around that.
|
||||
//! [`Window::surface_position`]: crate::window::Window::surface_position
|
||||
//! [`Window::surface_size`]: crate::window::Window::surface_size
|
||||
//! [`Window::outer_position`]: crate::window::Window::outer_position
|
||||
//! [`Window::outer_size`]: crate::window::Window::outer_size
|
||||
//!
|
||||
//! # UI scaling
|
||||
//!
|
||||
//! UI scaling is important, go read the docs for the [`dpi`] crate for an
|
||||
@@ -277,11 +230,11 @@
|
||||
// doc
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
#![warn(clippy::uninlined_format_args)]
|
||||
|
||||
// Re-export DPI types so that users don't have to put it in Cargo.toml.
|
||||
#[doc(inline)]
|
||||
pub use dpi;
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub use rwh_06 as raw_window_handle;
|
||||
|
||||
pub mod application;
|
||||
|
||||
@@ -141,11 +141,8 @@ impl MonitorHandle {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
/// Returns the top-left corner position of the monitor in desktop coordinates.
|
||||
///
|
||||
/// This position is in the same coordinate system as [`Window::outer_position`].
|
||||
///
|
||||
/// [`Window::outer_position`]: crate::window::Window::outer_position
|
||||
/// Returns the top-left corner position of the monitor relative to the larger full
|
||||
/// screen area.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
|
||||
@@ -92,9 +92,6 @@ pub trait WindowExtMacOS {
|
||||
/// This is how fullscreen used to work on macOS in versions before Lion.
|
||||
/// And allows the user to have a fullscreen window without using another
|
||||
/// space or taking control over the entire monitor.
|
||||
///
|
||||
/// Make sure you only draw your important content inside the safe area so that it does not
|
||||
/// overlap with the notch on newer devices, see [`Window::safe_area`] for details.
|
||||
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool;
|
||||
|
||||
/// Returns whether or not the window has shadow.
|
||||
@@ -160,13 +157,6 @@ pub trait WindowExtMacOS {
|
||||
|
||||
/// Getter for the [`WindowExtMacOS::set_borderless_game`].
|
||||
fn is_borderless_game(&self) -> bool;
|
||||
|
||||
/// Makes the titlebar bigger, effectively adding more space around the
|
||||
/// window controls if the titlebar is invisible.
|
||||
fn set_unified_titlebar(&self, unified_titlebar: bool);
|
||||
|
||||
/// Getter for the [`WindowExtMacOS::set_unified_titlebar`].
|
||||
fn unified_titlebar(&self) -> bool;
|
||||
}
|
||||
|
||||
impl WindowExtMacOS for dyn Window + '_ {
|
||||
@@ -265,18 +255,6 @@ impl WindowExtMacOS for dyn Window + '_ {
|
||||
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||
window.maybe_wait_on_main(|w| w.is_borderless_game())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_unified_titlebar(&self, unified_titlebar: bool) {
|
||||
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||
window.maybe_wait_on_main(|w| w.set_unified_titlebar(unified_titlebar))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unified_titlebar(&self) -> bool {
|
||||
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||
window.maybe_wait_on_main(|w| w.unified_titlebar())
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to `NSApplicationActivationPolicy`.
|
||||
@@ -330,8 +308,6 @@ pub trait WindowAttributesExtMacOS {
|
||||
fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self;
|
||||
/// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set.
|
||||
fn with_borderless_game(self, borderless_game: bool) -> Self;
|
||||
/// See [`WindowExtMacOS::set_unified_titlebar`] for details on what this means if set.
|
||||
fn with_unified_titlebar(self, unified_titlebar: bool) -> Self;
|
||||
}
|
||||
|
||||
impl WindowAttributesExtMacOS for WindowAttributes {
|
||||
@@ -406,12 +382,6 @@ impl WindowAttributesExtMacOS for WindowAttributes {
|
||||
self.platform_specific.borderless_game = borderless_game;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_unified_titlebar(mut self, unified_titlebar: bool) -> Self {
|
||||
self.platform_specific.unified_titlebar = unified_titlebar;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EventLoopBuilderExtMacOS {
|
||||
|
||||
@@ -21,7 +21,6 @@ pub mod windows;
|
||||
#[cfg(any(x11_platform, docsrs))]
|
||||
pub mod x11;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(any(
|
||||
windows_platform,
|
||||
macos_platform,
|
||||
|
||||
@@ -57,6 +57,7 @@ use web_sys::HtmlCanvasElement;
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::CustomCursorSource;
|
||||
use crate::error::NotSupportedError;
|
||||
use crate::event::FingerId;
|
||||
use crate::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use crate::monitor::MonitorHandle;
|
||||
use crate::platform_impl::PlatformCustomCursorSource;
|
||||
@@ -779,3 +780,16 @@ impl Display for OrientationLockError {
|
||||
}
|
||||
|
||||
impl Error for OrientationLockError {}
|
||||
|
||||
/// Additional methods on [`FingerId`] that are specific to Web.
|
||||
pub trait FingerIdExtWeb {
|
||||
/// Indicates if the finger represents the first contact in a multi-touch interaction.
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn is_primary(self) -> bool;
|
||||
}
|
||||
|
||||
impl FingerIdExtWeb for FingerId {
|
||||
fn is_primary(self) -> bool {
|
||||
self.0.is_primary()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
||||
use windows_sys::Win32::Foundation::HANDLE;
|
||||
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::DeviceId;
|
||||
use crate::event::{DeviceId, FingerId};
|
||||
use crate::event_loop::EventLoopBuilder;
|
||||
use crate::monitor::MonitorHandle;
|
||||
use crate::window::{BadIcon, Icon, Window, WindowAttributes};
|
||||
@@ -135,6 +135,7 @@ impl<W: Window> Deref for AnyThread<W> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl<W: Window> rwh_06::HasWindowHandle for AnyThread<W> {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
// SAFETY: The top level user has asserted this is only used safely.
|
||||
@@ -336,6 +337,7 @@ pub trait WindowExtWindows {
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "rwh_06")]
|
||||
unsafe fn window_handle_any_thread(
|
||||
&self,
|
||||
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError>;
|
||||
@@ -399,6 +401,7 @@ impl WindowExtWindows for dyn Window + '_ {
|
||||
window.set_corner_preference(preference)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
unsafe fn window_handle_any_thread(
|
||||
&self,
|
||||
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
@@ -432,8 +435,16 @@ pub trait WindowBorrowExtWindows: Borrow<dyn Window> + Sized {
|
||||
/// Win32 APIs.
|
||||
///
|
||||
/// [`Window`]: crate::window::Window
|
||||
/// [`HasWindowHandle`]: rwh_06::HasWindowHandle
|
||||
/// [`window_handle_any_thread`]: WindowExtWindows::window_handle_any_thread
|
||||
#[cfg_attr(
|
||||
feature = "rwh_06",
|
||||
doc = "[`HasWindowHandle`]: rwh_06::HasWindowHandle",
|
||||
doc = "[`window_handle_any_thread`]: WindowExtWindows::window_handle_any_thread"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(feature = "rwh_06"),
|
||||
doc = "[`HasWindowHandle`]: #only-available-with-rwh_06",
|
||||
doc = "[`window_handle_any_thread`]: #only-available-with-rwh_06"
|
||||
)]
|
||||
unsafe fn any_thread(self) -> AnyThread<Self>
|
||||
where
|
||||
Self: Window,
|
||||
@@ -659,6 +670,20 @@ impl DeviceIdExtWindows for DeviceId {
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `FingerId` that are specific to Windows.
|
||||
pub trait FingerIdExtWindows {
|
||||
/// Indicates if the finger represents the first contact in a multi-touch interaction.
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn is_primary(self) -> bool;
|
||||
}
|
||||
|
||||
impl FingerIdExtWindows for FingerId {
|
||||
#[inline]
|
||||
fn is_primary(self) -> bool {
|
||||
self.0.is_primary()
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on `Icon` that are specific to Windows.
|
||||
pub trait IconExtWindows: Sized {
|
||||
/// Create an icon from a file path.
|
||||
|
||||
@@ -13,13 +13,12 @@ use tracing::{debug, trace, warn};
|
||||
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{EventLoopError, NotSupportedError, RequestError};
|
||||
use crate::event::{self, DeviceId, FingerId, Force, StartCause, SurfaceSizeWriter};
|
||||
use crate::event::{self, DeviceId, Force, StartCause, SurfaceSizeWriter};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
@@ -108,7 +107,6 @@ pub struct EventLoop {
|
||||
running: bool,
|
||||
pending_redraw: bool,
|
||||
cause: StartCause,
|
||||
primary_pointer: Option<FingerId>,
|
||||
ignore_volume_keys: bool,
|
||||
combining_accent: Option<char>,
|
||||
}
|
||||
@@ -132,24 +130,22 @@ impl EventLoop {
|
||||
pub(crate) fn new(
|
||||
attributes: &PlatformSpecificEventLoopAttributes,
|
||||
) -> Result<Self, EventLoopError> {
|
||||
let proxy_wake_up = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let android_app = attributes.android_app.as_ref().expect(
|
||||
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
|
||||
Android",
|
||||
);
|
||||
|
||||
let event_loop_proxy = Arc::new(EventLoopProxy::new(android_app.create_waker()));
|
||||
|
||||
let redraw_flag = SharedFlag::new();
|
||||
|
||||
Ok(Self {
|
||||
android_app: android_app.clone(),
|
||||
primary_pointer: None,
|
||||
window_target: ActiveEventLoop {
|
||||
app: android_app.clone(),
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
exit: Cell::new(false),
|
||||
redraw_requester: RedrawRequester::new(&redraw_flag, android_app.create_waker()),
|
||||
event_loop_proxy,
|
||||
proxy_wake_up,
|
||||
},
|
||||
redraw_flag,
|
||||
loop_running: false,
|
||||
@@ -278,7 +274,7 @@ impl EventLoop {
|
||||
},
|
||||
}
|
||||
|
||||
if self.window_target.event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
|
||||
if self.window_target.proxy_wake_up.swap(false, Ordering::Relaxed) {
|
||||
app.proxy_wake_up(&self.window_target);
|
||||
}
|
||||
|
||||
@@ -337,83 +333,36 @@ impl EventLoop {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
for pointer in pointers.into_iter().flatten() {
|
||||
let tool_type = pointer.tool_type();
|
||||
let position = PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ };
|
||||
trace!(
|
||||
"Input event {device_id:?}, {action:?}, loc={position:?}, \
|
||||
pointer={pointer:?}, tool_type={tool_type:?}"
|
||||
);
|
||||
let finger_id = FingerId::from_raw(pointer.pointer_id() as usize);
|
||||
let force = Some(Force::Normalized(pointer.pressure() as f64));
|
||||
if let Some(pointers) = pointers {
|
||||
for pointer in pointers {
|
||||
let tool_type = pointer.tool_type();
|
||||
let position =
|
||||
PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ };
|
||||
trace!(
|
||||
"Input event {device_id:?}, {action:?}, loc={position:?}, \
|
||||
pointer={pointer:?}, tool_type={tool_type:?}"
|
||||
);
|
||||
let finger_id = event::FingerId(FingerId(pointer.pointer_id()));
|
||||
let force = Some(Force::Normalized(pointer.pressure() as f64));
|
||||
|
||||
match action {
|
||||
MotionAction::Down | MotionAction::PointerDown => {
|
||||
let primary = action == MotionAction::Down;
|
||||
if primary {
|
||||
self.primary_pointer = Some(finger_id);
|
||||
}
|
||||
let event = event::WindowEvent::PointerEntered {
|
||||
device_id,
|
||||
primary,
|
||||
position,
|
||||
kind: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerKind::Touch(finger_id)
|
||||
match action {
|
||||
MotionAction::Down | MotionAction::PointerDown => {
|
||||
let event = event::WindowEvent::PointerEntered {
|
||||
device_id,
|
||||
position,
|
||||
kind: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerKind::Touch(finger_id)
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerKind::Unknown,
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerKind::Unknown,
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
let event = event::WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary,
|
||||
state: event::ElementState::Pressed,
|
||||
position,
|
||||
button: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::ButtonSource::Touch { finger_id, force }
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::ButtonSource::Unknown(0),
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
},
|
||||
MotionAction::Move => {
|
||||
let primary = self.primary_pointer == Some(finger_id);
|
||||
let event = event::WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
primary,
|
||||
position,
|
||||
source: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerSource::Touch { finger_id, force }
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerSource::Unknown,
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
},
|
||||
MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => {
|
||||
let primary = action == MotionAction::Up
|
||||
|| (action == MotionAction::Cancel
|
||||
&& self.primary_pointer == Some(finger_id));
|
||||
|
||||
if primary {
|
||||
self.primary_pointer = None;
|
||||
}
|
||||
|
||||
if let MotionAction::Up | MotionAction::PointerUp = action {
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
let event = event::WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary,
|
||||
state: event::ElementState::Released,
|
||||
state: event::ElementState::Pressed,
|
||||
position,
|
||||
button: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
@@ -425,24 +374,56 @@ impl EventLoop {
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
}
|
||||
|
||||
let event = event::WindowEvent::PointerLeft {
|
||||
device_id,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerKind::Touch(finger_id)
|
||||
},
|
||||
MotionAction::Move => {
|
||||
let event = event::WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
position,
|
||||
source: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerSource::Touch { finger_id, force }
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerSource::Unknown,
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerKind::Unknown,
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
},
|
||||
MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => {
|
||||
if let MotionAction::Up | MotionAction::PointerUp = action {
|
||||
let event = event::WindowEvent::PointerButton {
|
||||
device_id,
|
||||
state: event::ElementState::Released,
|
||||
position,
|
||||
button: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::ButtonSource::Touch { finger_id, force }
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::ButtonSource::Unknown(0),
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
}
|
||||
|
||||
let event = event::WindowEvent::PointerLeft {
|
||||
device_id,
|
||||
position: Some(position),
|
||||
kind: match tool_type {
|
||||
android_activity::input::ToolType::Finger => {
|
||||
event::PointerKind::Touch(finger_id)
|
||||
},
|
||||
// TODO mouse events
|
||||
android_activity::input::ToolType::Mouse => continue,
|
||||
_ => event::PointerKind::Unknown,
|
||||
},
|
||||
};
|
||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -564,8 +545,7 @@ impl EventLoop {
|
||||
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
||||
|
||||
timeout = if self.running
|
||||
&& (self.pending_redraw
|
||||
|| self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
|
||||
&& (self.pending_redraw || self.window_target.proxy_wake_up.load(Ordering::Relaxed))
|
||||
{
|
||||
// If we already have work to do then we don't want to block on the next poll
|
||||
Some(Duration::ZERO)
|
||||
@@ -598,7 +578,7 @@ impl EventLoop {
|
||||
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
||||
if !self.running
|
||||
|| (!self.pending_redraw
|
||||
&& !self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
|
||||
&& !self.window_target.proxy_wake_up.load(Ordering::Relaxed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -637,20 +617,15 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
wake_up: AtomicBool,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
waker: AndroidAppWaker,
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
fn new(waker: AndroidAppWaker) -> Self {
|
||||
Self { wake_up: AtomicBool::new(false), waker }
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.wake_up.store(true, Ordering::Relaxed);
|
||||
pub fn wake_up(&self) {
|
||||
self.proxy_wake_up.store(true, Ordering::Relaxed);
|
||||
self.waker.wake();
|
||||
}
|
||||
}
|
||||
@@ -660,7 +635,7 @@ pub struct ActiveEventLoop {
|
||||
control_flow: Cell<ControlFlow>,
|
||||
exit: Cell<bool>,
|
||||
redraw_requester: RedrawRequester,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl ActiveEventLoop {
|
||||
@@ -670,8 +645,12 @@ impl ActiveEventLoop {
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
CoreEventLoopProxy::new(self.event_loop_proxy.clone())
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy {
|
||||
proxy_wake_up: self.proxy_wake_up.clone(),
|
||||
waker: self.app.create_waker(),
|
||||
};
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -718,15 +697,17 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.exit.get()
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::AndroidDisplayHandle::new();
|
||||
@@ -737,10 +718,23 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::AndroidDisplayHandle::new();
|
||||
Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw.into()) })
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::AndroidDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct FingerId(i32);
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,6 +764,7 @@ impl Window {
|
||||
self.app.content_rect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
// Allow the usage of HasRawWindowHandle inside this function
|
||||
#[allow(deprecated)]
|
||||
fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
||||
@@ -787,11 +782,13 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn raw_display_handle_rwh_06(&self) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
@@ -799,6 +796,7 @@ impl rwh_06::HasDisplayHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_window_handle_rwh_06()?;
|
||||
@@ -833,8 +831,8 @@ impl CoreWindow for Window {
|
||||
|
||||
fn pre_present_notify(&self) {}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
(0, 0).into()
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
Err(NotSupportedError::new("inner_position is not supported").into())
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
@@ -857,10 +855,6 @@ impl CoreWindow for Window {
|
||||
screen_size(&self.app)
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
PhysicalInsets::new(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, _: Option<Size>) {}
|
||||
|
||||
fn set_max_surface_size(&self, _: Option<Size>) {}
|
||||
@@ -927,13 +921,7 @@ impl CoreWindow for Window {
|
||||
|
||||
fn set_ime_cursor_area(&self, _position: Position, _size: Size) {}
|
||||
|
||||
fn set_ime_allowed(&self, allowed: bool) {
|
||||
if allowed {
|
||||
self.app.show_soft_input(true);
|
||||
} else {
|
||||
self.app.hide_soft_input(true);
|
||||
}
|
||||
}
|
||||
fn set_ime_allowed(&self, _allowed: bool) {}
|
||||
|
||||
fn set_ime_purpose(&self, _purpose: ImePurpose) {}
|
||||
|
||||
@@ -986,10 +974,12 @@ impl CoreWindow for Window {
|
||||
|
||||
fn reset_dead_keys(&self) {}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use std::cell::{Cell, OnceCell, RefCell};
|
||||
use std::mem;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::atomic::Ordering as AtomicOrdering;
|
||||
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSRunningApplication};
|
||||
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy};
|
||||
use objc2_foundation::{MainThreadMarker, NSNotification};
|
||||
|
||||
use super::super::event_handler::EventHandler;
|
||||
use super::event_loop::{stop_app_immediately, ActiveEventLoop, EventLoopProxy, PanicInfo};
|
||||
use super::event_loop::{stop_app_immediately, ActiveEventLoop, PanicInfo};
|
||||
use super::menu;
|
||||
use super::observer::{EventLoopWaker, RunLoop};
|
||||
use crate::application::ApplicationHandler;
|
||||
@@ -24,7 +24,7 @@ pub(super) struct AppState {
|
||||
default_menu: bool,
|
||||
activate_ignoring_other_apps: bool,
|
||||
run_loop: RunLoop,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
event_handler: EventHandler,
|
||||
stop_on_launch: Cell<bool>,
|
||||
stop_before_wait: Cell<bool>,
|
||||
@@ -72,7 +72,7 @@ impl AppState {
|
||||
let this = Rc::new(AppState {
|
||||
mtm,
|
||||
activation_policy,
|
||||
event_loop_proxy: Arc::new(EventLoopProxy::new()),
|
||||
proxy_wake_up: Arc::new(AtomicBool::new(false)),
|
||||
default_menu,
|
||||
activate_ignoring_other_apps,
|
||||
run_loop: RunLoop::main(mtm),
|
||||
@@ -113,21 +113,10 @@ impl AppState {
|
||||
// We need to delay setting the activation policy and activating the app
|
||||
// until `applicationDidFinishLaunching` has been called. Otherwise the
|
||||
// menu bar is initially unresponsive on macOS 10.15.
|
||||
if let Some(activation_policy) = self.activation_policy {
|
||||
app.setActivationPolicy(activation_policy);
|
||||
} else {
|
||||
// If no activation policy is explicitly provided, and the application
|
||||
// is bundled, do not set the activation policy at all, to allow the
|
||||
// package manifest to define the behavior via LSUIElement.
|
||||
//
|
||||
// See:
|
||||
// - https://github.com/rust-windowing/winit/issues/261
|
||||
// - https://github.com/rust-windowing/winit/issues/3958
|
||||
let is_bundled =
|
||||
unsafe { NSRunningApplication::currentApplication().bundleIdentifier().is_some() };
|
||||
if !is_bundled {
|
||||
app.setActivationPolicy(NSApplicationActivationPolicy::Regular);
|
||||
}
|
||||
// If no activation policy is explicitly provided, do not set it at all
|
||||
// to allow the package manifest to define behavior via LSUIElement.
|
||||
if self.activation_policy.is_some() {
|
||||
app.setActivationPolicy(self.activation_policy.unwrap());
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -176,8 +165,8 @@ impl AppState {
|
||||
self.event_handler.set(handler, closure)
|
||||
}
|
||||
|
||||
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.event_loop_proxy
|
||||
pub fn proxy_wake_up(&self) -> Arc<AtomicBool> {
|
||||
self.proxy_wake_up.clone()
|
||||
}
|
||||
|
||||
/// If `pump_events` is called to progress the event loop then we
|
||||
@@ -361,7 +350,7 @@ impl AppState {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.event_loop_proxy.wake_up.swap(false, AtomicOrdering::Relaxed) {
|
||||
if self.proxy_wake_up.swap(false, AtomicOrdering::Relaxed) {
|
||||
self.with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ use objc2_app_kit::{
|
||||
NSApplicationWillTerminateNotification, NSWindow,
|
||||
};
|
||||
use objc2_foundation::{MainThreadMarker, NSNotificationCenter, NSObject, NSObjectProtocol};
|
||||
use rwh_06::HasDisplayHandle;
|
||||
|
||||
use super::super::notification_center::create_observer;
|
||||
use super::app::WinitApplication;
|
||||
@@ -33,8 +32,7 @@ use crate::application::ApplicationHandler;
|
||||
use crate::error::{EventLoopError, RequestError};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::platform::macos::ActivationPolicy;
|
||||
@@ -97,8 +95,9 @@ impl ActiveEventLoop {
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
CoreEventLoopProxy::new(self.app_state.event_loop_proxy().clone())
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy::new(self.app_state.proxy_wake_up());
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -152,15 +151,17 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.app_state.exiting()
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::AppKit(rwh_06::AppKitDisplayHandle::new());
|
||||
@@ -390,12 +391,16 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::AppKit(rwh_06::AppKitDisplayHandle::new());
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::AppKitDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,9 +439,8 @@ pub fn stop_app_on_panic<F: FnOnce() -> R + UnwindSafe, R>(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventLoopProxy {
|
||||
pub(crate) wake_up: AtomicBool,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
source: CFRunLoopSourceRef,
|
||||
}
|
||||
|
||||
@@ -451,8 +455,14 @@ impl Drop for EventLoopProxy {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for EventLoopProxy {
|
||||
fn clone(&self) -> Self {
|
||||
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub(crate) fn new() -> Self {
|
||||
fn new(proxy_wake_up: Arc<AtomicBool>) -> Self {
|
||||
unsafe {
|
||||
// just wake up the eventloop
|
||||
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
||||
@@ -476,16 +486,14 @@ impl EventLoopProxy {
|
||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||
CFRunLoopWakeUp(rl);
|
||||
|
||||
EventLoopProxy { wake_up: AtomicBool::new(false), source }
|
||||
EventLoopProxy { proxy_wake_up, source }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.wake_up.store(true, AtomicOrdering::Relaxed);
|
||||
pub fn wake_up(&self) {
|
||||
self.proxy_wake_up.store(true, AtomicOrdering::Relaxed);
|
||||
unsafe {
|
||||
// Let the main thread know there's a new event.
|
||||
// let the main thread know there's a new event
|
||||
CFRunLoopSourceSignal(self.source);
|
||||
let rl = CFRunLoopGetMain();
|
||||
CFRunLoopWakeUp(rl);
|
||||
|
||||
@@ -17,7 +17,8 @@ mod window_delegate;
|
||||
pub(crate) use self::cursor::CustomCursor as PlatformCustomCursor;
|
||||
pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra};
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
||||
PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub(crate) use self::window::Window;
|
||||
@@ -25,3 +26,13 @@ pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
pub(crate) use crate::platform_impl::Fullscreen;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId;
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId
|
||||
}
|
||||
}
|
||||
|
||||
@@ -657,7 +657,6 @@ declare_class!(
|
||||
|
||||
self.queue_event(WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position,
|
||||
kind: PointerKind::Mouse,
|
||||
});
|
||||
@@ -671,7 +670,6 @@ declare_class!(
|
||||
|
||||
self.queue_event(WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Mouse,
|
||||
});
|
||||
@@ -1063,7 +1061,6 @@ impl WinitView {
|
||||
|
||||
self.queue_event(WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: button_state,
|
||||
position,
|
||||
button: button.into(),
|
||||
@@ -1090,7 +1087,6 @@ impl WinitView {
|
||||
|
||||
self.queue_event(WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: view_point.to_physical(self.scale_factor()),
|
||||
source: PointerSource::Mouse,
|
||||
});
|
||||
|
||||
@@ -42,6 +42,7 @@ impl Window {
|
||||
self.delegate.get_on_main(|delegate| f(delegate))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub(crate) fn raw_window_handle_rwh_06(
|
||||
&self,
|
||||
@@ -53,6 +54,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub(crate) fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
@@ -72,6 +74,7 @@ impl Drop for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
@@ -79,6 +82,7 @@ impl rwh_06::HasDisplayHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_window_handle_rwh_06()?;
|
||||
@@ -107,12 +111,12 @@ impl CoreWindow for Window {
|
||||
self.maybe_wait_on_main(|delegate| delegate.reset_dead_keys());
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> dpi::PhysicalPosition<i32> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.surface_position())
|
||||
fn inner_position(&self) -> Result<dpi::PhysicalPosition<i32>, RequestError> {
|
||||
Ok(self.maybe_wait_on_main(|delegate| delegate.inner_position()))
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<dpi::PhysicalPosition<i32>, RequestError> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.outer_position())
|
||||
Ok(self.maybe_wait_on_main(|delegate| delegate.outer_position()))
|
||||
}
|
||||
|
||||
fn set_outer_position(&self, position: Position) {
|
||||
@@ -131,10 +135,6 @@ impl CoreWindow for Window {
|
||||
self.maybe_wait_on_main(|delegate| delegate.outer_size())
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> dpi::PhysicalInsets<u32> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.safe_area())
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
||||
self.maybe_wait_on_main(|delegate| delegate.set_min_surface_size(min_size))
|
||||
}
|
||||
@@ -323,10 +323,12 @@ impl CoreWindow for Window {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use core_graphics::display::CGDisplay;
|
||||
use core_graphics::display::{CGDisplay, CGPoint};
|
||||
use monitor::VideoModeHandle;
|
||||
use objc2::rc::{autoreleasepool, Retained};
|
||||
use objc2::runtime::{AnyObject, ProtocolObject};
|
||||
@@ -15,16 +15,15 @@ use objc2_app_kit::{
|
||||
NSAppKitVersionNumber, NSAppKitVersionNumber10_12, NSAppearance, NSAppearanceCustomization,
|
||||
NSAppearanceNameAqua, NSApplication, NSApplicationPresentationOptions, NSBackingStoreType,
|
||||
NSColor, NSDraggingDestination, NSFilenamesPboardType, NSPasteboard,
|
||||
NSRequestUserAttentionType, NSScreen, NSToolbar, NSView, NSWindowButton, NSWindowDelegate,
|
||||
NSRequestUserAttentionType, NSScreen, NSView, NSWindowButton, NSWindowDelegate,
|
||||
NSWindowFullScreenButton, NSWindowLevel, NSWindowOcclusionState, NSWindowOrderingMode,
|
||||
NSWindowSharingType, NSWindowStyleMask, NSWindowTabbingMode, NSWindowTitleVisibility,
|
||||
NSWindowToolbarStyle,
|
||||
};
|
||||
use objc2_foundation::{
|
||||
ns_string, CGFloat, MainThreadMarker, NSArray, NSCopying, NSDictionary, NSEdgeInsets,
|
||||
NSKeyValueChangeKey, NSKeyValueChangeNewKey, NSKeyValueChangeOldKey,
|
||||
NSKeyValueObservingOptions, NSObject, NSObjectNSDelayedPerforming,
|
||||
NSObjectNSKeyValueObserverRegistration, NSObjectProtocol, NSPoint, NSRect, NSSize, NSString,
|
||||
ns_string, CGFloat, MainThreadMarker, NSArray, NSCopying, NSDictionary, NSKeyValueChangeKey,
|
||||
NSKeyValueChangeNewKey, NSKeyValueChangeOldKey, NSKeyValueObservingOptions, NSObject,
|
||||
NSObjectNSDelayedPerforming, NSObjectNSKeyValueObserverRegistration, NSObjectProtocol, NSPoint,
|
||||
NSRect, NSSize, NSString,
|
||||
};
|
||||
use tracing::{trace, warn};
|
||||
|
||||
@@ -35,10 +34,7 @@ use super::observer::RunLoop;
|
||||
use super::view::WinitView;
|
||||
use super::window::WinitWindow;
|
||||
use super::{ffi, Fullscreen, MonitorHandle};
|
||||
use crate::dpi::{
|
||||
LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize,
|
||||
Position, Size,
|
||||
};
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{SurfaceSizeWriter, WindowEvent};
|
||||
use crate::platform::macos::{OptionAsAlt, WindowExtMacOS};
|
||||
@@ -61,7 +57,6 @@ pub struct PlatformSpecificWindowAttributes {
|
||||
pub tabbing_identifier: Option<String>,
|
||||
pub option_as_alt: OptionAsAlt,
|
||||
pub borderless_game: bool,
|
||||
pub unified_titlebar: bool,
|
||||
}
|
||||
|
||||
impl Default for PlatformSpecificWindowAttributes {
|
||||
@@ -80,7 +75,6 @@ impl Default for PlatformSpecificWindowAttributes {
|
||||
tabbing_identifier: None,
|
||||
option_as_alt: Default::default(),
|
||||
borderless_game: false,
|
||||
unified_titlebar: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,15 +439,9 @@ declare_class!(
|
||||
// NOTE: We don't _really_ need to check the key path, as there should only be one, but
|
||||
// in the future we might want to observe other key paths.
|
||||
if key_path == Some(ns_string!("effectiveAppearance")) {
|
||||
let change = change.expect(
|
||||
"requested a change dictionary in `addObserver`, but none was provided",
|
||||
);
|
||||
let old = change
|
||||
.get(unsafe { NSKeyValueChangeOldKey })
|
||||
.expect("requested change dictionary did not contain `NSKeyValueChangeOldKey`");
|
||||
let new = change
|
||||
.get(unsafe { NSKeyValueChangeNewKey })
|
||||
.expect("requested change dictionary did not contain `NSKeyValueChangeNewKey`");
|
||||
let change = change.expect("requested a change dictionary in `addObserver`, but none was provided");
|
||||
let old = change.get(unsafe { NSKeyValueChangeOldKey }).expect("requested change dictionary did not contain `NSKeyValueChangeOldKey`");
|
||||
let new = change.get(unsafe { NSKeyValueChangeNewKey }).expect("requested change dictionary did not contain `NSKeyValueChangeNewKey`");
|
||||
|
||||
// SAFETY: The value of `effectiveAppearance` is `NSAppearance`
|
||||
let old: *const AnyObject = old;
|
||||
@@ -570,12 +558,6 @@ fn new_window(
|
||||
}
|
||||
|
||||
if attrs.platform_specific.fullsize_content_view {
|
||||
// NOTE: If we decide to add an option to change this at runtime, we must emit a
|
||||
// `SurfaceResized` event to let applications know that the safe area changed.
|
||||
//
|
||||
// An alternative would be to add a `WindowEvent::SafeAreaChanged` event, this could be
|
||||
// done with an observer on `safeAreaRect` / `contentLayoutRect`, see:
|
||||
// <https://github.com/rust-windowing/winit/issues/3911>
|
||||
masks |= NSWindowStyleMask::FullSizeContentView;
|
||||
}
|
||||
|
||||
@@ -634,14 +616,6 @@ fn new_window(
|
||||
if attrs.platform_specific.movable_by_window_background {
|
||||
window.setMovableByWindowBackground(true);
|
||||
}
|
||||
if attrs.platform_specific.unified_titlebar {
|
||||
unsafe {
|
||||
// The toolbar style is ignored if there is no toolbar, so it is
|
||||
// necessary to add one.
|
||||
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
||||
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
||||
}
|
||||
}
|
||||
|
||||
if !attrs.enabled_buttons.contains(WindowButtons::MAXIMIZE) {
|
||||
if let Some(button) = window.standardWindowButton(NSWindowButton::NSWindowZoomButton) {
|
||||
@@ -707,6 +681,7 @@ impl WindowDelegate {
|
||||
let window = new_window(app_state, &attrs, mtm)
|
||||
.ok_or_else(|| os_error!("couldn't create `NSWindow`"))?;
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
match attrs.parent_window.map(|handle| handle.0) {
|
||||
Some(rwh_06::RawWindowHandle::AppKit(handle)) => {
|
||||
// SAFETY: Caller ensures the pointer is valid or NULL
|
||||
@@ -949,15 +924,15 @@ impl WindowDelegate {
|
||||
#[inline]
|
||||
pub fn pre_present_notify(&self) {}
|
||||
|
||||
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
pub fn outer_position(&self) -> PhysicalPosition<i32> {
|
||||
let position = flip_window_screen_coordinates(self.window().frame());
|
||||
Ok(LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor()))
|
||||
LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor())
|
||||
}
|
||||
|
||||
pub fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
pub fn inner_position(&self) -> PhysicalPosition<i32> {
|
||||
let content_rect = self.window().contentRectForFrameRect(self.window().frame());
|
||||
let logical = LogicalPosition::new(content_rect.origin.x, content_rect.origin.y);
|
||||
logical.to_physical(self.scale_factor())
|
||||
let position = flip_window_screen_coordinates(content_rect);
|
||||
LogicalPosition::new(position.x, position.y).to_physical(self.scale_factor())
|
||||
}
|
||||
|
||||
pub fn set_outer_position(&self, position: Position) {
|
||||
@@ -983,32 +958,6 @@ impl WindowDelegate {
|
||||
logical.to_physical(self.scale_factor())
|
||||
}
|
||||
|
||||
pub fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
// Only available on macOS 11.0
|
||||
let insets = if self.view().respondsToSelector(sel!(safeAreaInsets)) {
|
||||
// Includes NSWindowStyleMask::FullSizeContentView by default, and the notch because
|
||||
// we've set it up with `additionalSafeAreaInsets`.
|
||||
unsafe { self.view().safeAreaInsets() }
|
||||
} else {
|
||||
let content_rect = self.window().contentRectForFrameRect(self.window().frame());
|
||||
// Includes NSWindowStyleMask::FullSizeContentView
|
||||
// Convert from window coordinates to view coordinates
|
||||
let safe_rect = unsafe {
|
||||
self.view().convertRect_fromView(self.window().contentLayoutRect(), None)
|
||||
};
|
||||
NSEdgeInsets {
|
||||
top: safe_rect.origin.y - content_rect.origin.y,
|
||||
left: safe_rect.origin.x - content_rect.origin.x,
|
||||
bottom: (content_rect.size.height + content_rect.origin.x)
|
||||
- (safe_rect.size.height + safe_rect.origin.x),
|
||||
right: (content_rect.size.width + content_rect.origin.y)
|
||||
- (safe_rect.size.width + safe_rect.origin.y),
|
||||
}
|
||||
};
|
||||
let insets = LogicalInsets::new(insets.top, insets.left, insets.bottom, insets.right);
|
||||
insets.to_physical(self.scale_factor())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_surface_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
|
||||
let scale_factor = self.scale_factor();
|
||||
@@ -1205,12 +1154,13 @@ impl WindowDelegate {
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(&self, cursor_position: Position) -> Result<(), RequestError> {
|
||||
let content_rect = self.window().contentRectForFrameRect(self.window().frame());
|
||||
let window_position = flip_window_screen_coordinates(content_rect);
|
||||
let cursor_position = cursor_position.to_logical::<CGFloat>(self.scale_factor());
|
||||
let point = core_graphics::display::CGPoint {
|
||||
x: window_position.x + cursor_position.x,
|
||||
y: window_position.y + cursor_position.y,
|
||||
let physical_window_position = self.inner_position();
|
||||
let scale_factor = self.scale_factor();
|
||||
let window_position = physical_window_position.to_logical::<CGFloat>(scale_factor);
|
||||
let logical_cursor_position = cursor_position.to_logical::<CGFloat>(scale_factor);
|
||||
let point = CGPoint {
|
||||
x: logical_cursor_position.x + window_position.x,
|
||||
y: logical_cursor_position.y + window_position.y,
|
||||
};
|
||||
CGDisplay::warp_mouse_cursor_position(point)
|
||||
.map_err(|status| os_error!(format!("CGError {status}")))?;
|
||||
@@ -1670,6 +1620,7 @@ impl WindowDelegate {
|
||||
Some(monitor)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_window_handle_rwh_06(&self) -> rwh_06::RawWindowHandle {
|
||||
let window_handle = rwh_06::AppKitWindowHandle::new({
|
||||
@@ -1792,15 +1743,12 @@ impl WindowExtMacOS for WindowDelegate {
|
||||
let screen = self.window().screen().expect("expected screen to be available");
|
||||
self.window().setFrame_display(screen.frame(), true);
|
||||
|
||||
// Configure the safe area rectangle, to ensure that we don't obscure the notch.
|
||||
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
||||
unsafe { self.view().setAdditionalSafeAreaInsets(screen.safeAreaInsets()) };
|
||||
}
|
||||
|
||||
// Fullscreen windows can't be resized, minimized, or moved
|
||||
self.toggle_style_mask(NSWindowStyleMask::Miniaturizable, false);
|
||||
self.toggle_style_mask(NSWindowStyleMask::Resizable, false);
|
||||
self.window().setMovable(false);
|
||||
|
||||
true
|
||||
} else {
|
||||
let new_mask = self.saved_style();
|
||||
self.set_style_mask(new_mask);
|
||||
@@ -1813,22 +1761,11 @@ impl WindowExtMacOS for WindowDelegate {
|
||||
app.setPresentationOptions(presentation_opts);
|
||||
}
|
||||
|
||||
if NSScreen::class().responds_to(sel!(safeAreaInsets)) {
|
||||
unsafe {
|
||||
self.view().setAdditionalSafeAreaInsets(NSEdgeInsets {
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
bottom: 0.0,
|
||||
right: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.window().setFrame_display(frame, true);
|
||||
self.window().setMovable(true);
|
||||
}
|
||||
|
||||
true
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1900,34 +1837,6 @@ impl WindowExtMacOS for WindowDelegate {
|
||||
fn is_borderless_game(&self) -> bool {
|
||||
self.ivars().is_borderless_game.get()
|
||||
}
|
||||
|
||||
fn set_unified_titlebar(&self, unified_titlebar: bool) {
|
||||
let window = self.window();
|
||||
|
||||
if unified_titlebar {
|
||||
let mtm = MainThreadMarker::from(self);
|
||||
|
||||
unsafe {
|
||||
// The toolbar style is ignored if there is no toolbar, so it is
|
||||
// necessary to add one.
|
||||
window.setToolbar(Some(&NSToolbar::new(mtm)));
|
||||
window.setToolbarStyle(NSWindowToolbarStyle::Unified);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
window.setToolbar(None);
|
||||
window.setToolbarStyle(NSWindowToolbarStyle::Automatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unified_titlebar(&self) -> bool {
|
||||
let window = self.window();
|
||||
|
||||
unsafe {
|
||||
window.toolbar().is_some() && window.toolbarStyle() == NSWindowToolbarStyle::Unified
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_STANDARD_FRAME: NSRect =
|
||||
|
||||
@@ -7,9 +7,7 @@ mod notification_center;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
mod uikit;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use self::appkit::*;
|
||||
#[allow(unused_imports)]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub use self::uikit::*;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use std::cell::{OnceCell, RefCell, RefMut};
|
||||
use std::collections::HashSet;
|
||||
use std::os::raw::c_void;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
use std::time::Instant;
|
||||
use std::{mem, ptr};
|
||||
@@ -24,7 +24,7 @@ use objc2_ui_kit::{UIApplication, UICoordinateSpace, UIView, UIWindow};
|
||||
|
||||
use super::super::event_handler::EventHandler;
|
||||
use super::window::WinitUIWindow;
|
||||
use super::{ActiveEventLoop, EventLoopProxy};
|
||||
use super::ActiveEventLoop;
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent};
|
||||
@@ -139,7 +139,7 @@ pub(crate) struct AppState {
|
||||
app_state: Option<AppStateImpl>,
|
||||
control_flow: ControlFlow,
|
||||
waker: EventLoopWaker,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
@@ -164,7 +164,7 @@ impl AppState {
|
||||
}),
|
||||
control_flow: ControlFlow::default(),
|
||||
waker,
|
||||
event_loop_proxy: Arc::new(EventLoopProxy::new()),
|
||||
proxy_wake_up: Arc::new(AtomicBool::new(false)),
|
||||
});
|
||||
}
|
||||
init_guard(&mut guard);
|
||||
@@ -376,8 +376,8 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.event_loop_proxy
|
||||
pub(crate) fn proxy_wake_up(&self) -> Arc<AtomicBool> {
|
||||
self.proxy_wake_up.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn set_control_flow(&mut self, control_flow: ControlFlow) {
|
||||
@@ -543,10 +543,10 @@ fn handle_user_events(mtm: MainThreadMarker) {
|
||||
if processing_redraws {
|
||||
bug!("user events attempted to be sent out while `ProcessingRedraws`");
|
||||
}
|
||||
let event_loop_proxy = this.event_loop_proxy().clone();
|
||||
let proxy_wake_up = this.proxy_wake_up.clone();
|
||||
drop(this);
|
||||
|
||||
if event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
|
||||
if proxy_wake_up.swap(false, Ordering::Relaxed) {
|
||||
handle_event(mtm, Event::UserWakeUp);
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
|
||||
}
|
||||
}
|
||||
|
||||
if event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
|
||||
if proxy_wake_up.swap(false, Ordering::Relaxed) {
|
||||
handle_event(mtm, Event::UserWakeUp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ use objc2_ui_kit::{
|
||||
UIApplicationWillEnterForegroundNotification, UIApplicationWillResignActiveNotification,
|
||||
UIApplicationWillTerminateNotification, UIScreen,
|
||||
};
|
||||
use rwh_06::HasDisplayHandle;
|
||||
|
||||
use super::super::notification_center::create_observer;
|
||||
use super::app_state::{send_occluded_event_for_all_windows, AppState, EventWrapper};
|
||||
@@ -30,8 +29,7 @@ use crate::error::{EventLoopError, NotSupportedError, RequestError};
|
||||
use crate::event::Event;
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::platform_impl::Window;
|
||||
@@ -43,8 +41,9 @@ pub(crate) struct ActiveEventLoop {
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
CoreEventLoopProxy::new(AppState::get_mut(self.mtm).event_loop_proxy().clone())
|
||||
fn create_proxy(&self) -> crate::event_loop::EventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy::new(AppState::get_mut(self.mtm).proxy_wake_up());
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -95,15 +94,17 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
false
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::UiKit(rwh_06::UiKitDisplayHandle::new());
|
||||
@@ -114,10 +115,13 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::UiKit(rwh_06::UiKitDisplayHandle::new());
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::UiKitDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,13 +292,19 @@ impl EventLoop {
|
||||
}
|
||||
|
||||
pub struct EventLoopProxy {
|
||||
pub(crate) wake_up: AtomicBool,
|
||||
proxy_wake_up: Arc<AtomicBool>,
|
||||
source: CFRunLoopSourceRef,
|
||||
}
|
||||
|
||||
unsafe impl Send for EventLoopProxy {}
|
||||
unsafe impl Sync for EventLoopProxy {}
|
||||
|
||||
impl Clone for EventLoopProxy {
|
||||
fn clone(&self) -> EventLoopProxy {
|
||||
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EventLoopProxy {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
@@ -305,7 +315,7 @@ impl Drop for EventLoopProxy {
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub(crate) fn new() -> EventLoopProxy {
|
||||
fn new(proxy_wake_up: Arc<AtomicBool>) -> EventLoopProxy {
|
||||
unsafe {
|
||||
// just wake up the eventloop
|
||||
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
||||
@@ -329,14 +339,12 @@ impl EventLoopProxy {
|
||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||
CFRunLoopWakeUp(rl);
|
||||
|
||||
EventLoopProxy { wake_up: AtomicBool::new(false), source }
|
||||
EventLoopProxy { proxy_wake_up, source }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.wake_up.store(true, AtomicOrdering::Relaxed);
|
||||
pub fn wake_up(&self) {
|
||||
self.proxy_wake_up.store(true, AtomicOrdering::Relaxed);
|
||||
unsafe {
|
||||
// let the main thread know there's a new event
|
||||
CFRunLoopSourceSignal(self.source);
|
||||
|
||||
@@ -10,7 +10,8 @@ mod window;
|
||||
use std::fmt;
|
||||
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, PlatformSpecificEventLoopAttributes,
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
||||
PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
@@ -20,6 +21,16 @@ pub(crate) use crate::cursor::{
|
||||
pub(crate) use crate::icon::NoIcon as PlatformIcon;
|
||||
pub(crate) use crate::platform_impl::Fullscreen;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId(usize);
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct KeyEventExtra {}
|
||||
|
||||
|
||||
@@ -6,19 +6,19 @@ use objc2::runtime::{NSObjectProtocol, ProtocolObject};
|
||||
use objc2::{declare_class, msg_send, msg_send_id, mutability, sel, ClassType, DeclaredClass};
|
||||
use objc2_foundation::{CGFloat, CGPoint, CGRect, MainThreadMarker, NSObject, NSSet, NSString};
|
||||
use objc2_ui_kit::{
|
||||
UIEvent, UIForceTouchCapability, UIGestureRecognizer, UIGestureRecognizerDelegate,
|
||||
UIGestureRecognizerState, UIKeyInput, UIPanGestureRecognizer, UIPinchGestureRecognizer,
|
||||
UIResponder, UIRotationGestureRecognizer, UITapGestureRecognizer, UITextInputTraits, UITouch,
|
||||
UITouchPhase, UITouchType, UITraitEnvironment, UIView,
|
||||
UICoordinateSpace, UIEvent, UIForceTouchCapability, UIGestureRecognizer,
|
||||
UIGestureRecognizerDelegate, UIGestureRecognizerState, UIKeyInput, UIPanGestureRecognizer,
|
||||
UIPinchGestureRecognizer, UIResponder, UIRotationGestureRecognizer, UITapGestureRecognizer,
|
||||
UITextInputTraits, UITouch, UITouchPhase, UITouchType, UITraitEnvironment, UIView,
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
use super::app_state::{self, EventWrapper};
|
||||
use super::window::WinitUIWindow;
|
||||
use super::FingerId;
|
||||
use crate::dpi::PhysicalPosition;
|
||||
use crate::event::{
|
||||
ButtonSource, ElementState, Event, FingerId, Force, KeyEvent, PointerKind, PointerSource,
|
||||
TouchPhase, WindowEvent,
|
||||
ButtonSource, ElementState, Event, FingerId as RootFingerId, Force, KeyEvent, PointerKind,
|
||||
PointerSource, TouchPhase, WindowEvent,
|
||||
};
|
||||
use crate::keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKeyCode, PhysicalKey};
|
||||
use crate::platform_impl::KeyEventExtra;
|
||||
@@ -34,9 +34,6 @@ pub struct WinitViewState {
|
||||
rotation_last_delta: Cell<CGFloat>,
|
||||
pinch_last_delta: Cell<CGFloat>,
|
||||
pan_last_delta: Cell<CGPoint>,
|
||||
|
||||
primary_finger: Cell<Option<FingerId>>,
|
||||
fingers: Cell<u8>,
|
||||
}
|
||||
|
||||
declare_class!(
|
||||
@@ -73,15 +70,26 @@ declare_class!(
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
let _: () = unsafe { msg_send![super(self), layoutSubviews] };
|
||||
|
||||
let frame = self.frame();
|
||||
let scale_factor = self.contentScaleFactor() as f64;
|
||||
let size = crate::dpi::LogicalSize {
|
||||
width: frame.size.width as f64,
|
||||
height: frame.size.height as f64,
|
||||
}
|
||||
.to_physical(scale_factor);
|
||||
|
||||
let window = self.window().unwrap();
|
||||
let window_bounds = window.bounds();
|
||||
let screen = window.screen();
|
||||
let screen_space = screen.coordinateSpace();
|
||||
let screen_frame = self.convertRect_toCoordinateSpace(window_bounds, &screen_space);
|
||||
let scale_factor = screen.scale();
|
||||
let size = crate::dpi::LogicalSize {
|
||||
width: screen_frame.size.width as f64,
|
||||
height: screen_frame.size.height as f64,
|
||||
}
|
||||
.to_physical(scale_factor as f64);
|
||||
|
||||
// If the app is started in landscape, the view frame and window bounds can be mismatched.
|
||||
// The view frame will be in portrait and the window bounds in landscape. So apply the
|
||||
// window bounds to the view frame to make it consistent.
|
||||
let view_frame = self.frame();
|
||||
if view_frame != window_bounds {
|
||||
self.setFrame(window_bounds);
|
||||
}
|
||||
|
||||
app_state::handle_nonuser_event(
|
||||
mtm,
|
||||
EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
@@ -116,10 +124,13 @@ declare_class!(
|
||||
"invalid scale_factor set on UIView",
|
||||
);
|
||||
let scale_factor = scale_factor as f64;
|
||||
let frame = self.frame();
|
||||
let bounds = self.bounds();
|
||||
let screen = window.screen();
|
||||
let screen_space = screen.coordinateSpace();
|
||||
let screen_frame = self.convertRect_toCoordinateSpace(bounds, &screen_space);
|
||||
let size = crate::dpi::LogicalSize {
|
||||
width: frame.size.width as f64,
|
||||
height: frame.size.height as f64,
|
||||
width: screen_frame.size.width as f64,
|
||||
height: screen_frame.size.height as f64,
|
||||
};
|
||||
let window_id = window.id();
|
||||
app_state::handle_nonuser_events(
|
||||
@@ -140,13 +151,6 @@ declare_class!(
|
||||
);
|
||||
}
|
||||
|
||||
#[method(safeAreaInsetsDidChange)]
|
||||
fn safe_area_changed(&self) {
|
||||
debug!("safeAreaInsetsDidChange was called, requesting redraw");
|
||||
// When the safe area changes we want to make sure to emit a redraw event
|
||||
self.setNeedsDisplay();
|
||||
}
|
||||
|
||||
#[method(touchesBegan:withEvent:)]
|
||||
fn touches_began(&self, touches: &NSSet<UITouch>, _event: Option<&UIEvent>) {
|
||||
self.handle_touches(touches)
|
||||
@@ -189,7 +193,7 @@ declare_class!(
|
||||
// Pass -delta so that action is reversed
|
||||
(TouchPhase::Cancelled, -recognizer.scale())
|
||||
}
|
||||
state => panic!("unexpected recognizer state: {state:?}"),
|
||||
state => panic!("unexpected recognizer state: {:?}", state),
|
||||
};
|
||||
|
||||
let gesture_event = EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
@@ -248,7 +252,7 @@ declare_class!(
|
||||
// Pass -delta so that action is reversed
|
||||
(TouchPhase::Cancelled, -recognizer.rotation())
|
||||
}
|
||||
state => panic!("unexpected recognizer state: {state:?}"),
|
||||
state => panic!("unexpected recognizer state: {:?}", state),
|
||||
};
|
||||
|
||||
// Make delta negative to match macos, convert to degrees
|
||||
@@ -299,7 +303,7 @@ declare_class!(
|
||||
// Pass -delta so that action is reversed
|
||||
(TouchPhase::Cancelled, -last_pan.x, -last_pan.y)
|
||||
}
|
||||
state => panic!("unexpected recognizer state: {state:?}"),
|
||||
state => panic!("unexpected recognizer state: {:?}", state),
|
||||
};
|
||||
|
||||
|
||||
@@ -367,9 +371,6 @@ impl WinitView {
|
||||
rotation_last_delta: Cell::new(0.0),
|
||||
pinch_last_delta: Cell::new(0.0),
|
||||
pan_last_delta: Cell::new(CGPoint { x: 0.0, y: 0.0 }),
|
||||
|
||||
primary_finger: Cell::new(None),
|
||||
fingers: Cell::new(0),
|
||||
});
|
||||
let this: Retained<Self> = unsafe { msg_send_id![super(this), initWithFrame: frame] };
|
||||
|
||||
@@ -512,37 +513,14 @@ impl WinitView {
|
||||
)
|
||||
};
|
||||
let window_id = window.id();
|
||||
let finger_id = FingerId::from_raw(touch_id);
|
||||
|
||||
let ivars = self.ivars();
|
||||
let finger_id = RootFingerId(FingerId(touch_id));
|
||||
|
||||
match phase {
|
||||
UITouchPhase::Began => {
|
||||
let primary = if let UITouchType::Pencil = touch_type {
|
||||
true
|
||||
} else {
|
||||
ivars.fingers.set(ivars.fingers.get() + 1);
|
||||
// Keep the primary finger around until we clear all the fingers to
|
||||
// recognize it when user briefly removes it.
|
||||
match ivars.primary_finger.get() {
|
||||
Some(primary_id) => primary_id == finger_id,
|
||||
None => {
|
||||
debug_assert_eq!(
|
||||
ivars.fingers.get(),
|
||||
1,
|
||||
"number of fingers were not counted correctly"
|
||||
);
|
||||
ivars.primary_finger.set(Some(finger_id));
|
||||
true
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
kind: if let UITouchType::Pencil = touch_type {
|
||||
PointerKind::Unknown
|
||||
@@ -555,7 +533,6 @@ impl WinitView {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: ElementState::Pressed,
|
||||
position,
|
||||
button: if let UITouchType::Pencil = touch_type {
|
||||
@@ -567,44 +544,26 @@ impl WinitView {
|
||||
}));
|
||||
},
|
||||
UITouchPhase::Moved => {
|
||||
let (primary, source) = if let UITouchType::Pencil = touch_type {
|
||||
(true, PointerSource::Unknown)
|
||||
} else {
|
||||
(ivars.primary_finger.get().unwrap() == finger_id, PointerSource::Touch {
|
||||
finger_id,
|
||||
force,
|
||||
})
|
||||
};
|
||||
|
||||
touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
source,
|
||||
source: if let UITouchType::Pencil = touch_type {
|
||||
PointerSource::Unknown
|
||||
} else {
|
||||
PointerSource::Touch { finger_id, force }
|
||||
},
|
||||
},
|
||||
}));
|
||||
},
|
||||
// 2 is UITouchPhase::Stationary and is not expected here
|
||||
UITouchPhase::Ended | UITouchPhase::Cancelled => {
|
||||
let primary = if let UITouchType::Pencil = touch_type {
|
||||
true
|
||||
} else {
|
||||
ivars.fingers.set(ivars.fingers.get() - 1);
|
||||
let primary = ivars.primary_finger.get().unwrap() == finger_id;
|
||||
if ivars.fingers.get() == 0 {
|
||||
ivars.primary_finger.set(None);
|
||||
}
|
||||
primary
|
||||
};
|
||||
|
||||
if let UITouchPhase::Ended = phase {
|
||||
touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: ElementState::Released,
|
||||
position,
|
||||
button: if let UITouchType::Pencil = touch_type {
|
||||
@@ -620,7 +579,6 @@ impl WinitView {
|
||||
window_id,
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: if let UITouchType::Pencil = touch_type {
|
||||
PointerKind::Unknown
|
||||
|
||||
@@ -8,8 +8,8 @@ use objc2_foundation::{
|
||||
CGFloat, CGPoint, CGRect, CGSize, MainThreadBound, MainThreadMarker, NSObject, NSObjectProtocol,
|
||||
};
|
||||
use objc2_ui_kit::{
|
||||
UIApplication, UICoordinateSpace, UIEdgeInsets, UIResponder, UIScreen,
|
||||
UIScreenOverscanCompensation, UIViewController, UIWindow,
|
||||
UIApplication, UICoordinateSpace, UIResponder, UIScreen, UIScreenOverscanCompensation,
|
||||
UIViewController, UIWindow,
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
@@ -18,10 +18,7 @@ use super::view::WinitView;
|
||||
use super::view_controller::WinitViewController;
|
||||
use super::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle};
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{
|
||||
LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize,
|
||||
Position, Size,
|
||||
};
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{Event, WindowEvent};
|
||||
use crate::icon::Icon;
|
||||
@@ -161,19 +158,20 @@ impl Inner {
|
||||
|
||||
pub fn pre_present_notify(&self) {}
|
||||
|
||||
pub fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
let view_position = self.view.frame().origin;
|
||||
pub fn inner_position(&self) -> PhysicalPosition<i32> {
|
||||
let safe_area = self.safe_area_screen_space();
|
||||
let position =
|
||||
unsafe { self.window.convertPoint_fromView(view_position, Some(&self.view)) };
|
||||
let position = LogicalPosition::new(position.x, position.y);
|
||||
position.to_physical(self.scale_factor())
|
||||
LogicalPosition { x: safe_area.origin.x as f64, y: safe_area.origin.y as f64 };
|
||||
let scale_factor = self.scale_factor();
|
||||
position.to_physical(scale_factor)
|
||||
}
|
||||
|
||||
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
pub fn outer_position(&self) -> PhysicalPosition<i32> {
|
||||
let screen_frame = self.screen_frame();
|
||||
let position =
|
||||
LogicalPosition { x: screen_frame.origin.x as f64, y: screen_frame.origin.y as f64 };
|
||||
Ok(position.to_physical(self.scale_factor()))
|
||||
let scale_factor = self.scale_factor();
|
||||
position.to_physical(scale_factor)
|
||||
}
|
||||
|
||||
pub fn set_outer_position(&self, physical_position: Position) {
|
||||
@@ -189,36 +187,29 @@ impl Inner {
|
||||
}
|
||||
|
||||
pub fn surface_size(&self) -> PhysicalSize<u32> {
|
||||
let frame = self.view.frame();
|
||||
let size = LogicalSize::new(frame.size.width, frame.size.height);
|
||||
size.to_physical(self.scale_factor())
|
||||
let scale_factor = self.scale_factor();
|
||||
let safe_area = self.safe_area_screen_space();
|
||||
let size = LogicalSize {
|
||||
width: safe_area.size.width as f64,
|
||||
height: safe_area.size.height as f64,
|
||||
};
|
||||
size.to_physical(scale_factor)
|
||||
}
|
||||
|
||||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||
let frame = self.window.frame();
|
||||
let size = LogicalSize::new(frame.size.width, frame.size.height);
|
||||
size.to_physical(self.scale_factor())
|
||||
let scale_factor = self.scale_factor();
|
||||
let screen_frame = self.screen_frame();
|
||||
let size = LogicalSize {
|
||||
width: screen_frame.size.width as f64,
|
||||
height: screen_frame.size.height as f64,
|
||||
};
|
||||
size.to_physical(scale_factor)
|
||||
}
|
||||
|
||||
pub fn request_surface_size(&self, _size: Size) -> Option<PhysicalSize<u32>> {
|
||||
Some(self.surface_size())
|
||||
}
|
||||
|
||||
pub fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
// Only available on iOS 11.0
|
||||
let insets = if app_state::os_capabilities().safe_area {
|
||||
self.view.safeAreaInsets()
|
||||
} else {
|
||||
// Assume the status bar frame is the only thing that obscures the view
|
||||
let app = UIApplication::sharedApplication(MainThreadMarker::new().unwrap());
|
||||
#[allow(deprecated)]
|
||||
let status_bar_frame = app.statusBarFrame();
|
||||
UIEdgeInsets { top: status_bar_frame.size.height, left: 0.0, bottom: 0.0, right: 0.0 }
|
||||
};
|
||||
let insets = LogicalInsets::new(insets.top, insets.left, insets.bottom, insets.right);
|
||||
insets.to_physical(self.scale_factor())
|
||||
}
|
||||
|
||||
pub fn set_min_surface_size(&self, _dimensions: Option<Size>) {
|
||||
warn!("`Window::set_min_surface_size` is ignored on iOS")
|
||||
}
|
||||
@@ -429,6 +420,7 @@ impl Inner {
|
||||
self.window.id()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub fn raw_window_handle_rwh_06(&self) -> rwh_06::RawWindowHandle {
|
||||
let mut window_handle = rwh_06::UiKitWindowHandle::new({
|
||||
let ui_view = Retained::as_ptr(&self.view) as _;
|
||||
@@ -522,9 +514,14 @@ impl Window {
|
||||
let scale_factor = view.contentScaleFactor();
|
||||
let scale_factor = scale_factor as f64;
|
||||
if scale_factor != 1.0 {
|
||||
let frame = view.frame();
|
||||
let size =
|
||||
LogicalSize { width: frame.size.width as f64, height: frame.size.height as f64 };
|
||||
let bounds = view.bounds();
|
||||
let screen = window.screen();
|
||||
let screen_space = screen.coordinateSpace();
|
||||
let screen_frame = view.convertRect_toCoordinateSpace(bounds, &screen_space);
|
||||
let size = LogicalSize {
|
||||
width: screen_frame.size.width as f64,
|
||||
height: screen_frame.size.height as f64,
|
||||
};
|
||||
app_state::handle_nonuser_events(
|
||||
mtm,
|
||||
std::iter::once(EventWrapper::ScaleFactorChanged(app_state::ScaleFactorChanged {
|
||||
@@ -549,6 +546,7 @@ impl Window {
|
||||
self.inner.get_on_main(|inner| f(inner))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub(crate) fn raw_window_handle_rwh_06(
|
||||
&self,
|
||||
@@ -560,6 +558,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub(crate) fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
@@ -568,6 +567,7 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
@@ -575,6 +575,7 @@ impl rwh_06::HasDisplayHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_window_handle_rwh_06()?;
|
||||
@@ -603,12 +604,12 @@ impl CoreWindow for Window {
|
||||
self.maybe_wait_on_main(|delegate| delegate.reset_dead_keys());
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.surface_position())
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
Ok(self.maybe_wait_on_main(|delegate| delegate.inner_position()))
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.outer_position())
|
||||
Ok(self.maybe_wait_on_main(|delegate| delegate.outer_position()))
|
||||
}
|
||||
|
||||
fn set_outer_position(&self, position: Position) {
|
||||
@@ -627,10 +628,6 @@ impl CoreWindow for Window {
|
||||
self.maybe_wait_on_main(|delegate| delegate.outer_size())
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
self.maybe_wait_on_main(|delegate| delegate.safe_area())
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
||||
self.maybe_wait_on_main(|delegate| delegate.set_min_surface_size(min_size))
|
||||
}
|
||||
@@ -818,10 +815,12 @@ impl CoreWindow for Window {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
@@ -889,7 +888,7 @@ impl Inner {
|
||||
|
||||
impl Inner {
|
||||
fn screen_frame(&self) -> CGRect {
|
||||
self.rect_to_screen_space(self.window.frame())
|
||||
self.rect_to_screen_space(self.window.bounds())
|
||||
}
|
||||
|
||||
fn rect_to_screen_space(&self, rect: CGRect) -> CGRect {
|
||||
@@ -901,6 +900,43 @@ impl Inner {
|
||||
let screen_space = self.window.screen().coordinateSpace();
|
||||
self.window.convertRect_fromCoordinateSpace(rect, &screen_space)
|
||||
}
|
||||
|
||||
fn safe_area_screen_space(&self) -> CGRect {
|
||||
let bounds = self.window.bounds();
|
||||
if app_state::os_capabilities().safe_area {
|
||||
let safe_area = self.window.safeAreaInsets();
|
||||
let safe_bounds = CGRect {
|
||||
origin: CGPoint {
|
||||
x: bounds.origin.x + safe_area.left,
|
||||
y: bounds.origin.y + safe_area.top,
|
||||
},
|
||||
size: CGSize {
|
||||
width: bounds.size.width - safe_area.left - safe_area.right,
|
||||
height: bounds.size.height - safe_area.top - safe_area.bottom,
|
||||
},
|
||||
};
|
||||
self.rect_to_screen_space(safe_bounds)
|
||||
} else {
|
||||
let screen_frame = self.rect_to_screen_space(bounds);
|
||||
let status_bar_frame = {
|
||||
let app = UIApplication::sharedApplication(MainThreadMarker::new().unwrap());
|
||||
#[allow(deprecated)]
|
||||
app.statusBarFrame()
|
||||
};
|
||||
let (y, height) = if screen_frame.origin.y > status_bar_frame.size.height {
|
||||
(screen_frame.origin.y, screen_frame.size.height)
|
||||
} else {
|
||||
let y = status_bar_frame.size.height;
|
||||
let height = screen_frame.size.height
|
||||
- (status_bar_frame.size.height - screen_frame.origin.y);
|
||||
(y, height)
|
||||
};
|
||||
CGRect {
|
||||
origin: CGPoint { x: screen_frame.origin.x, y },
|
||||
size: CGSize { width: screen_frame.size.width, height },
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
|
||||
@@ -107,6 +107,24 @@ impl Default for PlatformSpecificWindowAttributes {
|
||||
pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
|
||||
Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum FingerId {
|
||||
#[cfg(x11_platform)]
|
||||
X(x11::FingerId),
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(wayland::FingerId),
|
||||
}
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
#[cfg(wayland_platform)]
|
||||
return FingerId::Wayland(wayland::FingerId::dummy());
|
||||
#[cfg(all(not(wayland_platform), x11_platform))]
|
||||
return FingerId::X(x11::FingerId::dummy());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum MonitorHandle {
|
||||
#[cfg(x11_platform)]
|
||||
@@ -277,6 +295,14 @@ pub enum EventLoop {
|
||||
X(x11::EventLoop),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum EventLoopProxy {
|
||||
#[cfg(x11_platform)]
|
||||
X(x11::EventLoopProxy),
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(wayland::EventLoopProxy),
|
||||
}
|
||||
|
||||
impl EventLoop {
|
||||
pub(crate) fn new(
|
||||
attributes: &PlatformSpecificEventLoopAttributes,
|
||||
@@ -396,6 +422,65 @@ impl AsRawFd for EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub fn wake_up(&self) {
|
||||
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.wake_up())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum OwnedDisplayHandle {
|
||||
#[cfg(x11_platform)]
|
||||
X(Arc<XConnection>),
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(wayland_client::Connection),
|
||||
}
|
||||
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
use std::ptr::NonNull;
|
||||
|
||||
match self {
|
||||
#[cfg(x11_platform)]
|
||||
Self::X(xconn) => Ok(rwh_06::XlibDisplayHandle::new(
|
||||
NonNull::new(xconn.display.cast()),
|
||||
xconn.default_screen_index() as _,
|
||||
)
|
||||
.into()),
|
||||
|
||||
#[cfg(wayland_platform)]
|
||||
Self::Wayland(conn) => {
|
||||
use sctk::reexports::client::Proxy;
|
||||
|
||||
Ok(rwh_06::WaylandDisplayHandle::new(
|
||||
NonNull::new(conn.display().id().as_ptr().cast()).unwrap(),
|
||||
)
|
||||
.into())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for OwnedDisplayHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
#[cfg(x11_platform)]
|
||||
(Self::X(this), Self::X(other)) => Arc::as_ptr(this).eq(&Arc::as_ptr(other)),
|
||||
#[cfg(wayland_platform)]
|
||||
(Self::Wayland(this), Self::Wayland(other)) => this.eq(other),
|
||||
#[cfg(all(x11_platform, wayland_platform))]
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for OwnedDisplayHandle {}
|
||||
|
||||
/// Returns the minimum `Option<Duration>`, taking into account that `None`
|
||||
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
||||
/// `Option::min`)
|
||||
|
||||
@@ -16,10 +16,7 @@ use crate::cursor::OnlyCursorImage;
|
||||
use crate::dpi::LogicalSize;
|
||||
use crate::error::{EventLoopError, OsError, RequestError};
|
||||
use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
};
|
||||
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::platform_impl::platform::min_timeout;
|
||||
use crate::platform_impl::PlatformCustomCursor;
|
||||
@@ -28,13 +25,12 @@ use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme}
|
||||
mod proxy;
|
||||
pub mod sink;
|
||||
|
||||
use proxy::EventLoopProxy;
|
||||
pub use proxy::EventLoopProxy;
|
||||
use sink::EventSink;
|
||||
|
||||
use super::state::{WindowCompositorUpdate, WinitState};
|
||||
use super::window::state::FrameCallbackState;
|
||||
use super::{logical_to_physical_rounded, WindowId};
|
||||
pub use crate::event_loop::EventLoopProxy as CoreEventLoopProxy;
|
||||
|
||||
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
|
||||
|
||||
@@ -52,7 +48,7 @@ pub struct EventLoop {
|
||||
wayland_dispatcher: WaylandDispatcher,
|
||||
|
||||
/// Connection to the wayland server.
|
||||
handle: Arc<OwnedDisplayHandle>,
|
||||
connection: Connection,
|
||||
|
||||
/// Event loop window target.
|
||||
active_event_loop: ActiveEventLoop,
|
||||
@@ -120,12 +116,11 @@ impl EventLoop {
|
||||
})
|
||||
.map_err(|err| os_error!(err))?;
|
||||
|
||||
let handle = Arc::new(OwnedDisplayHandle::new(connection));
|
||||
let active_event_loop = ActiveEventLoop {
|
||||
handle: handle.clone(),
|
||||
connection: connection.clone(),
|
||||
wayland_dispatcher: wayland_dispatcher.clone(),
|
||||
event_loop_awakener,
|
||||
event_loop_proxy: EventLoopProxy::new(ping).into(),
|
||||
event_loop_proxy: EventLoopProxy::new(ping),
|
||||
queue_handle,
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
exit: Cell::new(None),
|
||||
@@ -137,7 +132,7 @@ impl EventLoop {
|
||||
compositor_updates: Vec::new(),
|
||||
buffer_sink: EventSink::default(),
|
||||
window_ids: Vec::new(),
|
||||
handle,
|
||||
connection,
|
||||
wayland_dispatcher,
|
||||
event_loop,
|
||||
active_event_loop,
|
||||
@@ -231,7 +226,7 @@ impl EventLoop {
|
||||
//
|
||||
// Checking for flush error is essential to perform an exit with error, since
|
||||
// once we have a protocol error, we could get stuck retrying...
|
||||
if self.handle.connection.flush().is_err() {
|
||||
if self.connection.flush().is_err() {
|
||||
self.set_exit_code(1);
|
||||
return;
|
||||
}
|
||||
@@ -544,7 +539,7 @@ impl AsRawFd for EventLoop {
|
||||
|
||||
pub struct ActiveEventLoop {
|
||||
/// Event loop proxy
|
||||
event_loop_proxy: CoreEventLoopProxy,
|
||||
event_loop_proxy: EventLoopProxy,
|
||||
|
||||
/// The event loop wakeup source.
|
||||
pub event_loop_awakener: calloop::ping::Ping,
|
||||
@@ -565,13 +560,17 @@ pub struct ActiveEventLoop {
|
||||
/// Dispatcher of Wayland events.
|
||||
pub wayland_dispatcher: WaylandDispatcher,
|
||||
|
||||
/// Handle for the underlying event loop.
|
||||
pub handle: Arc<OwnedDisplayHandle>,
|
||||
/// Connection to the wayland server.
|
||||
pub connection: Connection,
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
self.event_loop_proxy.clone()
|
||||
fn create_proxy(&self) -> crate::event_loop::EventLoopProxy {
|
||||
crate::event_loop::EventLoopProxy {
|
||||
event_loop_proxy: crate::platform_impl::EventLoopProxy::Wayland(
|
||||
self.event_loop_proxy.clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
@@ -632,10 +631,13 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
None
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(self.handle.clone())
|
||||
fn owned_display_handle(&self) -> crate::event_loop::OwnedDisplayHandle {
|
||||
crate::event_loop::OwnedDisplayHandle {
|
||||
platform: crate::platform_impl::OwnedDisplayHandle::Wayland(self.connection.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
@@ -655,23 +657,8 @@ impl ActiveEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
self.handle.display_handle()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OwnedDisplayHandle {
|
||||
pub(crate) connection: Connection,
|
||||
}
|
||||
|
||||
impl OwnedDisplayHandle {
|
||||
fn new(connection: Connection) -> Self {
|
||||
Self { connection }
|
||||
}
|
||||
}
|
||||
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
use sctk::reexports::client::Proxy;
|
||||
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
//! An event loop proxy.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use sctk::reexports::calloop::ping::Ping;
|
||||
|
||||
use crate::event_loop::{EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider};
|
||||
|
||||
/// A handle that can be sent across the threads and used to wake up the `EventLoop`.
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
ping: Ping,
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.ping.ping();
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub fn new(ping: Ping) -> Self {
|
||||
Self { ping }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventLoopProxy> for CoreEventLoopProxy {
|
||||
fn from(value: EventLoopProxy) -> Self {
|
||||
CoreEventLoopProxy::new(Arc::new(value))
|
||||
pub fn wake_up(&self) {
|
||||
self.ping.ping();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Winit's Wayland backend.
|
||||
|
||||
pub use event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub use event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy};
|
||||
pub use output::{MonitorHandle, VideoModeHandle};
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Proxy;
|
||||
@@ -17,6 +17,16 @@ mod state;
|
||||
mod types;
|
||||
mod window;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId(i32);
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId(0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the WindowId out of the surface.
|
||||
#[inline]
|
||||
fn make_wid(surface: &WlSurface) -> WindowId {
|
||||
|
||||
@@ -40,9 +40,6 @@ pub struct WinitSeatState {
|
||||
/// The mapping from touched points to the surfaces they're present.
|
||||
touch_map: AHashMap<i32, TouchPoint>,
|
||||
|
||||
/// Id of the first touch event.
|
||||
first_touch_id: Option<i32>,
|
||||
|
||||
/// The text input bound on the seat.
|
||||
text_input: Option<Arc<ZwpTextInputV3>>,
|
||||
|
||||
|
||||
@@ -27,10 +27,7 @@ use sctk::seat::pointer::{
|
||||
use sctk::seat::SeatState;
|
||||
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
||||
use crate::event::{
|
||||
ElementState, MouseButton, MouseScrollDelta, PointerKind, PointerSource, TouchPhase,
|
||||
WindowEvent,
|
||||
};
|
||||
use crate::event::{ElementState, MouseButton, MouseScrollDelta, PointerSource, PointerKind, TouchPhase, WindowEvent};
|
||||
|
||||
use crate::platform_impl::wayland::state::WinitState;
|
||||
use crate::platform_impl::wayland::{self, WindowId};
|
||||
@@ -127,7 +124,6 @@ impl PointerHandler for WinitState {
|
||||
PointerEventKind::Enter { .. } => {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerEntered {
|
||||
primary: true,
|
||||
device_id: None,
|
||||
position,
|
||||
kind: PointerKind::Mouse,
|
||||
@@ -148,7 +144,6 @@ impl PointerHandler for WinitState {
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerLeft {
|
||||
primary: true,
|
||||
device_id: None,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Mouse,
|
||||
@@ -159,7 +154,6 @@ impl PointerHandler for WinitState {
|
||||
PointerEventKind::Motion { .. } => {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerMoved {
|
||||
primary: true,
|
||||
device_id: None,
|
||||
position,
|
||||
source: PointerSource::Mouse,
|
||||
@@ -180,7 +174,6 @@ impl PointerHandler for WinitState {
|
||||
};
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerButton {
|
||||
primary: true,
|
||||
device_id: None,
|
||||
state,
|
||||
position,
|
||||
|
||||
@@ -8,9 +8,9 @@ use sctk::seat::touch::{TouchData, TouchHandler};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::dpi::LogicalPosition;
|
||||
use crate::event::{ButtonSource, ElementState, FingerId, PointerKind, PointerSource, WindowEvent};
|
||||
use crate::platform_impl::wayland;
|
||||
use crate::event::{ButtonSource, ElementState, PointerKind, PointerSource, WindowEvent};
|
||||
use crate::platform_impl::wayland::state::WinitState;
|
||||
use crate::platform_impl::wayland::{self, FingerId};
|
||||
|
||||
impl TouchHandler for WinitState {
|
||||
fn down(
|
||||
@@ -40,20 +40,15 @@ impl TouchHandler for WinitState {
|
||||
|
||||
// Update the state of the point.
|
||||
let location = LogicalPosition::<f64>::from(position);
|
||||
// Only update primary finger once we don't have any touch.
|
||||
if seat_state.touch_map.is_empty() {
|
||||
seat_state.first_touch_id = Some(id);
|
||||
}
|
||||
let primary = seat_state.first_touch_id == Some(id);
|
||||
seat_state.touch_map.insert(id, TouchPoint { surface, location });
|
||||
|
||||
let position = location.to_physical(scale_factor);
|
||||
let finger_id = FingerId::from_raw(id as usize);
|
||||
let finger_id =
|
||||
crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id)));
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
@@ -62,7 +57,6 @@ impl TouchHandler for WinitState {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: ElementState::Pressed,
|
||||
position,
|
||||
button: ButtonSource::Touch { finger_id, force: None },
|
||||
@@ -94,15 +88,6 @@ impl TouchHandler for WinitState {
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Update the primary touch point.
|
||||
let primary = seat_state.first_touch_id == Some(id);
|
||||
// Reset primary finger once all the other fingers are lifted to not transfer primary
|
||||
// finger to some other finger and still accept it when it's briefly moved between the
|
||||
// windows.
|
||||
if seat_state.touch_map.is_empty() {
|
||||
seat_state.first_touch_id = None;
|
||||
}
|
||||
|
||||
let window_id = wayland::make_wid(&touch_point.surface);
|
||||
let scale_factor = match self.windows.get_mut().get(&window_id) {
|
||||
Some(window) => window.lock().unwrap().scale_factor(),
|
||||
@@ -110,12 +95,12 @@ impl TouchHandler for WinitState {
|
||||
};
|
||||
|
||||
let position = touch_point.location.to_physical(scale_factor);
|
||||
let finger_id = FingerId::from_raw(id as usize);
|
||||
let finger_id =
|
||||
crate::event::FingerId(crate::platform_impl::FingerId::Wayland(FingerId(id)));
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: ElementState::Released,
|
||||
position,
|
||||
button: ButtonSource::Touch { finger_id, force: None },
|
||||
@@ -125,7 +110,6 @@ impl TouchHandler for WinitState {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
@@ -156,8 +140,6 @@ impl TouchHandler for WinitState {
|
||||
None => return,
|
||||
};
|
||||
|
||||
let primary = seat_state.first_touch_id == Some(id);
|
||||
|
||||
let window_id = wayland::make_wid(&touch_point.surface);
|
||||
let scale_factor = match self.windows.get_mut().get(&window_id) {
|
||||
Some(window) => window.lock().unwrap().scale_factor(),
|
||||
@@ -169,10 +151,11 @@ impl TouchHandler for WinitState {
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: touch_point.location.to_physical(scale_factor),
|
||||
source: PointerSource::Touch {
|
||||
finger_id: FingerId::from_raw(id as usize),
|
||||
finger_id: crate::event::FingerId(crate::platform_impl::FingerId::Wayland(
|
||||
FingerId(id),
|
||||
)),
|
||||
force: None,
|
||||
},
|
||||
},
|
||||
@@ -196,21 +179,19 @@ impl TouchHandler for WinitState {
|
||||
None => return,
|
||||
};
|
||||
|
||||
let primary = seat_state.first_touch_id == Some(id);
|
||||
let position = touch_point.location.to_physical(scale_factor);
|
||||
|
||||
self.events_sink.push_window_event(
|
||||
WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Touch(FingerId::from_raw(id as usize)),
|
||||
kind: PointerKind::Touch(crate::event::FingerId(
|
||||
crate::platform_impl::FingerId::Wayland(FingerId(id)),
|
||||
)),
|
||||
},
|
||||
window_id,
|
||||
);
|
||||
}
|
||||
|
||||
seat_state.first_touch_id = None;
|
||||
}
|
||||
|
||||
fn shape(
|
||||
|
||||
@@ -17,7 +17,7 @@ use super::output::MonitorHandle;
|
||||
use super::state::WinitState;
|
||||
use super::types::xdg_activation::XdgActivationTokenData;
|
||||
use super::ActiveEventLoop;
|
||||
use crate::dpi::{LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{Ime, WindowEvent};
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
@@ -87,7 +87,7 @@ impl Window {
|
||||
let compositor = state.compositor_state.clone();
|
||||
let xdg_activation =
|
||||
state.xdg_activation.as_ref().map(|activation_state| activation_state.global().clone());
|
||||
let display = event_loop_window_target.handle.connection.display();
|
||||
let display = event_loop_window_target.connection.display();
|
||||
|
||||
let size: Size = attributes.surface_size.unwrap_or(LogicalSize::new(800., 600.).into());
|
||||
|
||||
@@ -103,7 +103,7 @@ impl Window {
|
||||
state.xdg_shell.create_window(surface.clone(), default_decorations, &queue_handle);
|
||||
|
||||
let mut window_state = WindowState::new(
|
||||
event_loop_window_target.handle.clone(),
|
||||
event_loop_window_target.connection.clone(),
|
||||
&event_loop_window_target.queue_handle,
|
||||
&state,
|
||||
size,
|
||||
@@ -248,6 +248,7 @@ impl Drop for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::WaylandWindowHandle::new({
|
||||
@@ -259,6 +260,7 @@ impl rwh_06::HasWindowHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::WaylandDisplayHandle::new({
|
||||
@@ -303,8 +305,9 @@ impl CoreWindow for Window {
|
||||
crate::platform_impl::common::xkb::reset_dead_keys()
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
(0, 0).into()
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
Err(NotSupportedError::new("window position information is not available on Wayland")
|
||||
.into())
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
@@ -335,10 +338,6 @@ impl CoreWindow for Window {
|
||||
super::logical_to_physical_rounded(window_state.outer_size(), scale_factor)
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
PhysicalInsets::new(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
||||
let scale_factor = self.scale_factor();
|
||||
let min_size = min_size.map(|size| size.to_logical(scale_factor));
|
||||
@@ -649,11 +648,13 @@ impl CoreWindow for Window {
|
||||
}
|
||||
|
||||
/// Get the raw-window-handle v0.6 display handle.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the raw-window-handle v0.6 window handle.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use sctk::reexports::client::backend::ObjectId;
|
||||
use sctk::reexports::client::protocol::wl_seat::WlSeat;
|
||||
use sctk::reexports::client::protocol::wl_shm::WlShm;
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::{Proxy, QueueHandle};
|
||||
use sctk::reexports::client::{Connection, Proxy, QueueHandle};
|
||||
use sctk::reexports::csd_frame::{
|
||||
DecorationsFrame, FrameAction, FrameClick, ResizeEdge, WindowState as XdgWindowState,
|
||||
};
|
||||
@@ -31,7 +31,6 @@ use wayland_protocols_plasma::blur::client::org_kde_kwin_blur::OrgKdeKwinBlur;
|
||||
use crate::cursor::CustomCursor as RootCustomCursor;
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::platform_impl::wayland::event_loop::OwnedDisplayHandle;
|
||||
use crate::platform_impl::wayland::logical_to_physical_rounded;
|
||||
use crate::platform_impl::wayland::seat::{
|
||||
PointerConstraintsState, WinitPointerData, WinitPointerDataExt, ZwpTextInputV3Ext,
|
||||
@@ -53,7 +52,7 @@ const MIN_WINDOW_SIZE: LogicalSize<u32> = LogicalSize::new(2, 1);
|
||||
/// The state of the window which is being updated from the [`WinitState`].
|
||||
pub struct WindowState {
|
||||
/// The connection to Wayland server.
|
||||
pub handle: Arc<OwnedDisplayHandle>,
|
||||
pub connection: Connection,
|
||||
|
||||
/// The `Shm` to set cursor.
|
||||
pub shm: WlShm,
|
||||
@@ -162,7 +161,7 @@ pub struct WindowState {
|
||||
impl WindowState {
|
||||
/// Create new window state.
|
||||
pub fn new(
|
||||
handle: Arc<OwnedDisplayHandle>,
|
||||
connection: Connection,
|
||||
queue_handle: &QueueHandle<WinitState>,
|
||||
winit_state: &WinitState,
|
||||
initial_size: Size,
|
||||
@@ -184,7 +183,7 @@ impl WindowState {
|
||||
blur: None,
|
||||
blur_manager: winit_state.kwin_blur_manager.clone(),
|
||||
compositor,
|
||||
handle,
|
||||
connection,
|
||||
csd_fails: false,
|
||||
cursor_grab_mode: GrabState::new(),
|
||||
selected_cursor: Default::default(),
|
||||
@@ -694,7 +693,7 @@ impl WindowState {
|
||||
}
|
||||
|
||||
self.apply_on_pointer(|pointer, _| {
|
||||
if pointer.set_cursor(&self.handle.connection, cursor_icon).is_err() {
|
||||
if pointer.set_cursor(&self.connection, cursor_icon).is_err() {
|
||||
warn!("Failed to set cursor to {:?}", cursor_icon);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -172,7 +172,7 @@ fn push_display(buffer: &mut Vec<u8>, display: &impl std::fmt::Display) {
|
||||
}
|
||||
}
|
||||
|
||||
write!(Writer { buffer }, "{display}").unwrap();
|
||||
write!(Writer { buffer }, "{}", display).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -22,9 +22,8 @@ use xkbcommon_dl::xkb_mod_mask_t;
|
||||
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::event::{
|
||||
ButtonSource, DeviceEvent, DeviceId, ElementState, Event, FingerId, Ime, MouseButton,
|
||||
MouseScrollDelta, PointerKind, PointerSource, RawKeyEvent, SurfaceSizeWriter, TouchPhase,
|
||||
WindowEvent,
|
||||
ButtonSource, DeviceEvent, DeviceId, ElementState, Event, Ime, MouseButton, MouseScrollDelta,
|
||||
PointerKind, PointerSource, RawKeyEvent, SurfaceSizeWriter, TouchPhase, WindowEvent,
|
||||
};
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::platform_impl::common::xkb::{self, XkbState};
|
||||
@@ -34,7 +33,7 @@ use crate::platform_impl::platform::x11::ActiveEventLoop;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::util::cookie::GenericEventCookie;
|
||||
use crate::platform_impl::x11::{
|
||||
mkdid, mkwid, util, CookieResultExt, Device, DeviceInfo, Dnd, DndState, ImeReceiver,
|
||||
mkdid, mkfid, mkwid, util, CookieResultExt, Device, DeviceInfo, Dnd, DndState, ImeReceiver,
|
||||
ScrollOrientation, UnownedWindow, WindowId,
|
||||
};
|
||||
|
||||
@@ -1035,14 +1034,12 @@ impl EventProcessor {
|
||||
let event = match event.detail as u32 {
|
||||
xlib::Button1 => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Left.into(),
|
||||
},
|
||||
xlib::Button2 => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Middle.into(),
|
||||
@@ -1050,7 +1047,6 @@ impl EventProcessor {
|
||||
|
||||
xlib::Button3 => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Right.into(),
|
||||
@@ -1073,7 +1069,6 @@ impl EventProcessor {
|
||||
},
|
||||
8 => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Back.into(),
|
||||
@@ -1081,14 +1076,12 @@ impl EventProcessor {
|
||||
|
||||
9 => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Forward.into(),
|
||||
},
|
||||
x => WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: true,
|
||||
state,
|
||||
position,
|
||||
button: MouseButton::Other(x as u16).into(),
|
||||
@@ -1123,7 +1116,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
primary: true,
|
||||
position,
|
||||
source: PointerSource::Mouse,
|
||||
},
|
||||
@@ -1213,7 +1205,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered {
|
||||
device_id,
|
||||
primary: true,
|
||||
position,
|
||||
kind: PointerKind::Mouse,
|
||||
},
|
||||
@@ -1238,7 +1229,6 @@ impl EventProcessor {
|
||||
window_id: mkwid(window),
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id: Some(mkdid(event.deviceid as xinput::DeviceId)),
|
||||
primary: true,
|
||||
position: Some(PhysicalPosition::new(event.event_x, event.event_y)),
|
||||
kind: PointerKind::Mouse,
|
||||
},
|
||||
@@ -1299,12 +1289,7 @@ impl EventProcessor {
|
||||
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
primary: true,
|
||||
position,
|
||||
source: PointerSource::Mouse,
|
||||
},
|
||||
event: WindowEvent::PointerMoved { device_id, position, source: PointerSource::Mouse },
|
||||
};
|
||||
callback(&self.target, event);
|
||||
}
|
||||
@@ -1375,14 +1360,11 @@ impl EventProcessor {
|
||||
|
||||
// Mouse cursor position changes when touch events are received.
|
||||
// Only the first concurrently active touch ID moves the mouse cursor.
|
||||
let is_first_touch =
|
||||
is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase);
|
||||
if is_first_touch {
|
||||
if is_first_touch(&mut self.first_touch, &mut self.num_touch, id, phase) {
|
||||
let event = Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: position.cast(),
|
||||
source: PointerSource::Mouse,
|
||||
},
|
||||
@@ -1391,7 +1373,7 @@ impl EventProcessor {
|
||||
}
|
||||
|
||||
let device_id = Some(mkdid(xev.deviceid as xinput::DeviceId));
|
||||
let finger_id = FingerId::from_raw(id as usize);
|
||||
let finger_id = mkfid(id);
|
||||
|
||||
match phase {
|
||||
xinput2::XI_TouchBegin => {
|
||||
@@ -1399,7 +1381,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered {
|
||||
device_id,
|
||||
primary: is_first_touch,
|
||||
position,
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
@@ -1409,7 +1390,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: is_first_touch,
|
||||
state: ElementState::Pressed,
|
||||
position,
|
||||
button: ButtonSource::Touch { finger_id, force: None },
|
||||
@@ -1422,7 +1402,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
primary: is_first_touch,
|
||||
position,
|
||||
source: PointerSource::Touch { finger_id, force: None },
|
||||
},
|
||||
@@ -1434,7 +1413,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary: is_first_touch,
|
||||
state: ElementState::Released,
|
||||
position,
|
||||
button: ButtonSource::Touch { finger_id, force: None },
|
||||
@@ -1445,7 +1423,6 @@ impl EventProcessor {
|
||||
window_id,
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id,
|
||||
primary: is_first_touch,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
|
||||
@@ -27,14 +27,13 @@ use crate::error::{EventLoopError, RequestError};
|
||||
use crate::event::{DeviceId, Event, StartCause, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::platform_impl::common::xkb::Context;
|
||||
use crate::platform_impl::platform::min_timeout;
|
||||
use crate::platform_impl::x11::window::Window;
|
||||
use crate::platform_impl::PlatformCustomCursor;
|
||||
use crate::platform_impl::{OwnedDisplayHandle, PlatformCustomCursor};
|
||||
use crate::window::{
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, Window as CoreWindow,
|
||||
WindowAttributes, WindowId,
|
||||
@@ -140,7 +139,7 @@ pub struct ActiveEventLoop {
|
||||
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||
redraw_sender: WakeSender<WindowId>,
|
||||
activation_sender: WakeSender<ActivationToken>,
|
||||
event_loop_proxy: CoreEventLoopProxy,
|
||||
event_loop_proxy: EventLoopProxy,
|
||||
device_events: Cell<DeviceEvents>,
|
||||
}
|
||||
|
||||
@@ -307,7 +306,7 @@ impl EventLoop {
|
||||
sender: activation_token_sender, // not used again so no clone
|
||||
waker: waker.clone(),
|
||||
},
|
||||
event_loop_proxy: event_loop_proxy.into(),
|
||||
event_loop_proxy,
|
||||
device_events: Default::default(),
|
||||
};
|
||||
|
||||
@@ -648,6 +647,21 @@ impl ActiveEventLoop {
|
||||
.expect_then_ignore_error("Failed to update device event filter");
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
let display_handle = rwh_06::XlibDisplayHandle::new(
|
||||
// SAFETY: display will never be null
|
||||
Some(
|
||||
std::ptr::NonNull::new(self.xconn.display as *mut _)
|
||||
.expect("X11 display should never be null"),
|
||||
),
|
||||
self.xconn.default_screen_index() as c_int,
|
||||
);
|
||||
Ok(display_handle.into())
|
||||
}
|
||||
|
||||
pub(crate) fn clear_exit(&self) {
|
||||
self.exit.set(None)
|
||||
}
|
||||
@@ -662,8 +676,12 @@ impl ActiveEventLoop {
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
self.event_loop_proxy.clone()
|
||||
fn create_proxy(&self) -> crate::event_loop::EventLoopProxy {
|
||||
crate::event_loop::EventLoopProxy {
|
||||
event_loop_proxy: crate::platform_impl::EventLoopProxy::X(
|
||||
self.event_loop_proxy.clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -725,18 +743,28 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.exit.get().is_some()
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(self.x_connection().clone())
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
let handle = OwnedDisplayHandle::X(self.x_connection().clone());
|
||||
RootOwnedDisplayHandle { platform: handle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
self.xconn.display_handle()
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub fn wake_up(&self) {
|
||||
self.ping.ping();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,29 +805,28 @@ impl<'a> Deref for DeviceInfo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId(u32);
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
#[allow(unused)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
ping: Ping,
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.ping.ping();
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
fn new(ping: Ping) -> Self {
|
||||
Self { ping }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventLoopProxy> for CoreEventLoopProxy {
|
||||
fn from(value: EventLoopProxy) -> Self {
|
||||
CoreEventLoopProxy::new(Arc::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic sum error type for X11 errors.
|
||||
#[derive(Debug)]
|
||||
pub enum X11Error {
|
||||
@@ -843,24 +870,24 @@ pub enum X11Error {
|
||||
impl fmt::Display for X11Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
X11Error::Xlib(e) => write!(f, "Xlib error: {e}"),
|
||||
X11Error::Connect(e) => write!(f, "X11 connection error: {e}"),
|
||||
X11Error::Connection(e) => write!(f, "X11 connection error: {e}"),
|
||||
X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {e}"),
|
||||
X11Error::GetProperty(e) => write!(f, "Failed to get X property {e}"),
|
||||
X11Error::X11(e) => write!(f, "X11 error: {e:?}"),
|
||||
X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {s}"),
|
||||
X11Error::Xlib(e) => write!(f, "Xlib error: {}", e),
|
||||
X11Error::Connect(e) => write!(f, "X11 connection error: {}", e),
|
||||
X11Error::Connection(e) => write!(f, "X11 connection error: {}", e),
|
||||
X11Error::XidsExhausted(e) => write!(f, "XID range exhausted: {}", e),
|
||||
X11Error::GetProperty(e) => write!(f, "Failed to get X property {}", e),
|
||||
X11Error::X11(e) => write!(f, "X11 error: {:?}", e),
|
||||
X11Error::UnexpectedNull(s) => write!(f, "Xlib function returned null: {}", s),
|
||||
X11Error::InvalidActivationToken(s) => write!(
|
||||
f,
|
||||
"Invalid activation token: {}",
|
||||
std::str::from_utf8(s).unwrap_or("<invalid utf8>")
|
||||
),
|
||||
X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {s}"),
|
||||
X11Error::MissingExtension(s) => write!(f, "Missing X11 extension: {}", s),
|
||||
X11Error::NoSuchVisual(visualid) => {
|
||||
write!(f, "Could not find a matching X11 visual for ID `{visualid:x}`")
|
||||
write!(f, "Could not find a matching X11 visual for ID `{:x}`", visualid)
|
||||
},
|
||||
X11Error::XsettingsParse(err) => {
|
||||
write!(f, "Failed to parse xsettings: {err:?}")
|
||||
write!(f, "Failed to parse xsettings: {:?}", err)
|
||||
},
|
||||
X11Error::NoArgb32Format => {
|
||||
f.write_str("winit only supports X11 displays with ARGB32 picture formats")
|
||||
@@ -967,6 +994,10 @@ fn mkdid(w: xinput::DeviceId) -> DeviceId {
|
||||
DeviceId::from_raw(w as i64)
|
||||
}
|
||||
|
||||
fn mkfid(w: u32) -> crate::event::FingerId {
|
||||
crate::event::FingerId(crate::platform_impl::FingerId::X(FingerId(w)))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Device {
|
||||
_name: String,
|
||||
|
||||
@@ -67,20 +67,15 @@ pub struct FrameExtentsHeuristic {
|
||||
}
|
||||
|
||||
impl FrameExtentsHeuristic {
|
||||
pub fn surface_position(&self) -> (i32, i32) {
|
||||
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
use self::FrameExtentsHeuristicPath::*;
|
||||
if self.heuristic_path != UnsupportedBordered {
|
||||
(self.frame_extents.left as i32, self.frame_extents.top as i32)
|
||||
(x - self.frame_extents.left as i32, y - self.frame_extents.top as i32)
|
||||
} else {
|
||||
(0, 0)
|
||||
(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
let (left, top) = self.surface_position();
|
||||
(x - left, y - top)
|
||||
}
|
||||
|
||||
pub fn surface_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) {
|
||||
(
|
||||
width.saturating_add(
|
||||
|
||||
@@ -21,7 +21,7 @@ use super::{
|
||||
ffi, ActiveEventLoop, CookieResultExt, ImeRequest, ImeSender, VoidCookie, XConnection,
|
||||
};
|
||||
use crate::cursor::{Cursor, CustomCursor as RootCustomCursor};
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{Event, SurfaceSizeWriter, WindowEvent};
|
||||
use crate::event_loop::AsyncRequestSerial;
|
||||
@@ -82,8 +82,8 @@ impl CoreWindow for Window {
|
||||
common::xkb::reset_dead_keys();
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
self.0.surface_position()
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
self.0.inner_position()
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
@@ -106,10 +106,6 @@ impl CoreWindow for Window {
|
||||
self.0.outer_size()
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
self.0.safe_area()
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
||||
self.0.set_min_surface_size(min_size)
|
||||
}
|
||||
@@ -298,15 +294,18 @@ impl CoreWindow for Window {
|
||||
.map(|inner| crate::monitor::MonitorHandle { inner })
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.0.raw_display_handle_rwh_06()?;
|
||||
@@ -314,6 +313,7 @@ impl rwh_06::HasDisplayHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.0.raw_window_handle_rwh_06()?;
|
||||
@@ -443,26 +443,15 @@ impl UnownedWindow {
|
||||
) -> Result<UnownedWindow, RequestError> {
|
||||
let xconn = &event_loop.xconn;
|
||||
let atoms = xconn.atoms();
|
||||
|
||||
let screen_id = match window_attrs.platform_specific.x11.screen_id {
|
||||
Some(id) => id,
|
||||
None => xconn.default_screen_index() as c_int,
|
||||
};
|
||||
|
||||
let screen = {
|
||||
let screen_id_usize = usize::try_from(screen_id)
|
||||
.map_err(|_| NotSupportedError::new("screen id must be non-negative"))?;
|
||||
xconn.xcb_connection().setup().roots.get(screen_id_usize).ok_or(
|
||||
NotSupportedError::new("requested screen id not present in server's response"),
|
||||
)?
|
||||
};
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
let root = match window_attrs.parent_window.as_ref().map(|handle| handle.0) {
|
||||
Some(rwh_06::RawWindowHandle::Xlib(handle)) => handle.window as xproto::Window,
|
||||
Some(rwh_06::RawWindowHandle::Xcb(handle)) => handle.window.get(),
|
||||
Some(raw) => unreachable!("Invalid raw window handle {raw:?} on X11"),
|
||||
None => screen.root,
|
||||
None => event_loop.root,
|
||||
};
|
||||
#[cfg(not(feature = "rwh_06"))]
|
||||
let root = event_loop.root;
|
||||
|
||||
let mut monitors = leap!(xconn.available_monitors());
|
||||
let guessed_monitor = if monitors.is_empty() {
|
||||
@@ -517,10 +506,18 @@ impl UnownedWindow {
|
||||
dimensions
|
||||
};
|
||||
|
||||
// An iterator over the visuals matching screen id combined with their depths.
|
||||
let mut all_visuals = screen
|
||||
.allowed_depths
|
||||
let screen_id = match window_attrs.platform_specific.x11.screen_id {
|
||||
Some(id) => id,
|
||||
None => xconn.default_screen_index() as c_int,
|
||||
};
|
||||
|
||||
// An iterator over all of the visuals combined with their depths.
|
||||
let mut all_visuals = xconn
|
||||
.xcb_connection()
|
||||
.setup()
|
||||
.roots
|
||||
.iter()
|
||||
.flat_map(|root| &root.allowed_depths)
|
||||
.flat_map(|depth| depth.visuals.iter().map(move |visual| (visual, depth.depth)));
|
||||
|
||||
// creating
|
||||
@@ -809,20 +806,6 @@ impl UnownedWindow {
|
||||
leap!(result).ignore_error();
|
||||
}
|
||||
|
||||
// Select XInput2 events
|
||||
let mask = xinput::XIEventMask::MOTION
|
||||
| xinput::XIEventMask::BUTTON_PRESS
|
||||
| xinput::XIEventMask::BUTTON_RELEASE
|
||||
| xinput::XIEventMask::ENTER
|
||||
| xinput::XIEventMask::LEAVE
|
||||
| xinput::XIEventMask::FOCUS_IN
|
||||
| xinput::XIEventMask::FOCUS_OUT
|
||||
| xinput::XIEventMask::TOUCH_BEGIN
|
||||
| xinput::XIEventMask::TOUCH_UPDATE
|
||||
| xinput::XIEventMask::TOUCH_END;
|
||||
leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask))
|
||||
.ignore_error();
|
||||
|
||||
// Set visibility (map window)
|
||||
if window_attrs.visible {
|
||||
leap!(xconn.xcb_connection().map_window(window.xwindow)).ignore_error();
|
||||
@@ -846,6 +829,20 @@ impl UnownedWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Select XInput2 events
|
||||
let mask = xinput::XIEventMask::MOTION
|
||||
| xinput::XIEventMask::BUTTON_PRESS
|
||||
| xinput::XIEventMask::BUTTON_RELEASE
|
||||
| xinput::XIEventMask::ENTER
|
||||
| xinput::XIEventMask::LEAVE
|
||||
| xinput::XIEventMask::FOCUS_IN
|
||||
| xinput::XIEventMask::FOCUS_OUT
|
||||
| xinput::XIEventMask::TOUCH_BEGIN
|
||||
| xinput::XIEventMask::TOUCH_UPDATE
|
||||
| xinput::XIEventMask::TOUCH_END;
|
||||
leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask))
|
||||
.ignore_error();
|
||||
|
||||
// Try to create input context for the window.
|
||||
if let Some(ime) = event_loop.ime.as_ref() {
|
||||
ime.borrow_mut()
|
||||
@@ -1512,7 +1509,7 @@ impl UnownedWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_position_physical(&self) -> (i32, i32) {
|
||||
pub(crate) fn inner_position_physical(&self) -> (i32, i32) {
|
||||
// This should be okay to unwrap since the only error XTranslateCoordinates can return
|
||||
// is BadWindow, and if the window handle is bad we have bigger problems.
|
||||
self.xconn
|
||||
@@ -1522,14 +1519,8 @@ impl UnownedWindow {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
let extents = self.shared_state_lock().frame_extents.clone();
|
||||
if let Some(extents) = extents {
|
||||
extents.surface_position().into()
|
||||
} else {
|
||||
self.update_cached_frame_extents();
|
||||
self.surface_position()
|
||||
}
|
||||
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
Ok(self.inner_position_physical().into())
|
||||
}
|
||||
|
||||
pub(crate) fn set_position_inner(
|
||||
@@ -1592,10 +1583,6 @@ impl UnownedWindow {
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
PhysicalInsets::new(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn request_surface_size_physical(&self, width: u32, height: u32) {
|
||||
self.xconn
|
||||
.xcb_connection()
|
||||
@@ -2003,7 +1990,7 @@ impl UnownedWindow {
|
||||
.query_pointer(self.xwindow, util::VIRTUAL_CORE_POINTER)
|
||||
.map_err(|err| os_error!(err))?;
|
||||
|
||||
let window_position = self.inner_position_physical();
|
||||
let window_position = self.inner_position()?;
|
||||
|
||||
let atoms = self.xconn.atoms();
|
||||
let message = atoms[_NET_WM_MOVERESIZE];
|
||||
@@ -2030,8 +2017,8 @@ impl UnownedWindow {
|
||||
| xproto::EventMask::SUBSTRUCTURE_NOTIFY,
|
||||
),
|
||||
[
|
||||
(window_position.0 + xinput_fp1616_to_float(pointer.win_x) as i32) as u32,
|
||||
(window_position.1 + xinput_fp1616_to_float(pointer.win_y) as i32) as u32,
|
||||
(window_position.x + xinput_fp1616_to_float(pointer.win_x) as i32) as u32,
|
||||
(window_position.y + xinput_fp1616_to_float(pointer.win_y) as i32) as u32,
|
||||
action.try_into().unwrap(),
|
||||
1, // Button 1
|
||||
1,
|
||||
@@ -2045,19 +2032,12 @@ impl UnownedWindow {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_ime_cursor_area(&self, spot: Position, size: Size) {
|
||||
let PhysicalPosition { x, y } = spot.to_physical::<i16>(self.scale_factor());
|
||||
let PhysicalSize { width, height } = size.to_physical::<i16>(self.scale_factor());
|
||||
// We only currently support reporting a caret position via XIM.
|
||||
// No IM servers currently process preedit area information from XIM clients
|
||||
// and it is unclear this is even part of the standard protocol.
|
||||
// Fcitx and iBus both assume that the position reported is at the insertion
|
||||
// caret, and by default will place the candidate window under and to the
|
||||
// right of the reported point.
|
||||
pub fn set_ime_cursor_area(&self, spot: Position, _size: Size) {
|
||||
let (x, y) = spot.to_physical::<i32>(self.scale_factor()).into();
|
||||
let _ = self.ime_sender.lock().unwrap().send(ImeRequest::Position(
|
||||
self.xwindow as ffi::Window,
|
||||
x.saturating_add(width),
|
||||
y.saturating_add(height),
|
||||
x,
|
||||
y,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2172,6 +2152,7 @@ impl UnownedWindow {
|
||||
// TODO timer
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
||||
let mut window_handle = rwh_06::XlibWindowHandle::new(self.xlib_window());
|
||||
@@ -2179,6 +2160,7 @@ impl UnownedWindow {
|
||||
Ok(window_handle.into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::ffi::c_int;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
|
||||
use std::{fmt, ptr};
|
||||
|
||||
use rwh_06::HasDisplayHandle;
|
||||
use x11rb::connection::Connection;
|
||||
use x11rb::protocol::randr::ConnectionExt as _;
|
||||
use x11rb::protocol::render;
|
||||
@@ -64,13 +62,6 @@ pub struct XConnection {
|
||||
pub cursor_cache: Mutex<HashMap<Option<CursorIcon>, xproto::Cursor>>,
|
||||
}
|
||||
|
||||
impl HasDisplayHandle for XConnection {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle()?;
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for XConnection {}
|
||||
unsafe impl Sync for XConnection {}
|
||||
|
||||
@@ -164,7 +155,7 @@ impl XConnection {
|
||||
fn new_xsettings_screen(xcb: &XCBConnection, default_screen: usize) -> Option<xproto::Atom> {
|
||||
// Fetch the _XSETTINGS_S[screen number] atom.
|
||||
let xsettings_screen = xcb
|
||||
.intern_atom(false, format!("_XSETTINGS_S{default_screen}").as_bytes())
|
||||
.intern_atom(false, format!("_XSETTINGS_S{}", default_screen).as_bytes())
|
||||
.ok()?
|
||||
.reply()
|
||||
.ok()?
|
||||
@@ -293,19 +284,6 @@ impl XConnection {
|
||||
|
||||
self.xcb_connection().setup().image_byte_order != endian
|
||||
}
|
||||
|
||||
pub fn raw_display_handle(&self) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
let display_handle = rwh_06::XlibDisplayHandle::new(
|
||||
// SAFETY: display will never be null
|
||||
Some(
|
||||
std::ptr::NonNull::new(self.display as *mut _)
|
||||
.expect("X11 display should never be null"),
|
||||
),
|
||||
self.default_screen_index() as c_int,
|
||||
);
|
||||
|
||||
Ok(display_handle.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for XConnection {
|
||||
|
||||
@@ -22,7 +22,6 @@ use self::apple as platform;
|
||||
use self::linux as platform;
|
||||
#[cfg(orbital_platform)]
|
||||
use self::orbital as platform;
|
||||
#[allow(unused_imports)]
|
||||
pub use self::platform::*;
|
||||
#[cfg(web_platform)]
|
||||
use self::web as platform;
|
||||
|
||||
@@ -18,11 +18,7 @@ use super::{
|
||||
use crate::application::ApplicationHandler;
|
||||
use crate::error::{EventLoopError, NotSupportedError, RequestError};
|
||||
use crate::event::{self, Ime, Modifiers, StartCause};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
};
|
||||
use crate::event_loop::{self, ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||
use crate::keyboard::{
|
||||
Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NamedKey, NativeKey, NativeKeyCode,
|
||||
PhysicalKey,
|
||||
@@ -290,7 +286,8 @@ impl EventLoop {
|
||||
let event_socket =
|
||||
Arc::new(RedoxSocket::event().map_err(|error| os_error!(format!("{error}")))?);
|
||||
|
||||
let wake_socket = TimeSocket::open().map_err(|error| os_error!(format!("{error}")))?;
|
||||
let wake_socket =
|
||||
Arc::new(TimeSocket::open().map_err(|error| os_error!(format!("{error}")))?);
|
||||
|
||||
event_socket
|
||||
.write(&syscall::Event {
|
||||
@@ -309,7 +306,8 @@ impl EventLoop {
|
||||
redraws: Arc::new(Mutex::new(VecDeque::new())),
|
||||
destroys: Arc::new(Mutex::new(VecDeque::new())),
|
||||
event_socket,
|
||||
event_loop_proxy: Arc::new(EventLoopProxy { wake_socket, user_events_sender }),
|
||||
wake_socket,
|
||||
user_events_sender,
|
||||
},
|
||||
user_events_receiver,
|
||||
})
|
||||
@@ -406,7 +404,6 @@ impl EventLoop {
|
||||
EventOption::Mouse(MouseEvent { x, y }) => {
|
||||
app.window_event(window_target, window_id, event::WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: (x, y).into(),
|
||||
source: event::PointerSource::Mouse,
|
||||
});
|
||||
@@ -420,7 +417,6 @@ impl EventLoop {
|
||||
while let Some((button, state)) = event_state.mouse(left, middle, right) {
|
||||
app.window_event(window_target, window_id, event::WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state,
|
||||
position: dpi::PhysicalPosition::default(),
|
||||
button: button.into(),
|
||||
@@ -462,14 +458,12 @@ impl EventLoop {
|
||||
let event = if entered {
|
||||
event::WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: dpi::PhysicalPosition::default(),
|
||||
kind: event::PointerKind::Mouse,
|
||||
}
|
||||
} else {
|
||||
event::WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: None,
|
||||
kind: event::PointerKind::Mouse,
|
||||
}
|
||||
@@ -666,11 +660,11 @@ impl EventLoop {
|
||||
|
||||
pub struct EventLoopProxy {
|
||||
user_events_sender: mpsc::SyncSender<()>,
|
||||
pub(super) wake_socket: TimeSocket,
|
||||
wake_socket: Arc<TimeSocket>,
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
impl EventLoopProxy {
|
||||
pub fn wake_up(&self) {
|
||||
// When we fail to send the event it means that we haven't woken up to read the previous
|
||||
// event.
|
||||
if self.user_events_sender.try_send(()).is_ok() {
|
||||
@@ -679,6 +673,15 @@ impl EventLoopProxyProvider for EventLoopProxy {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for EventLoopProxy {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
user_events_sender: self.user_events_sender.clone(),
|
||||
wake_socket: self.wake_socket.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Unpin for EventLoopProxy {}
|
||||
|
||||
pub struct ActiveEventLoop {
|
||||
@@ -688,12 +691,18 @@ pub struct ActiveEventLoop {
|
||||
pub(super) redraws: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
pub(super) destroys: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
pub(super) event_socket: Arc<RedoxSocket>,
|
||||
pub(super) event_loop_proxy: Arc<EventLoopProxy>,
|
||||
pub(super) wake_socket: Arc<TimeSocket>,
|
||||
user_events_sender: mpsc::SyncSender<()>,
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> CoreEventLoopProxy {
|
||||
CoreEventLoopProxy::new(self.event_loop_proxy.clone())
|
||||
fn create_proxy(&self) -> event_loop::EventLoopProxy {
|
||||
event_loop::EventLoopProxy {
|
||||
event_loop_proxy: EventLoopProxy {
|
||||
user_events_sender: self.user_events_sender.clone(),
|
||||
wake_socket: self.wake_socket.clone(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -742,15 +751,17 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.exit.get()
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> event_loop::OwnedDisplayHandle {
|
||||
event_loop::OwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Orbital(rwh_06::OrbitalDisplayHandle::new());
|
||||
@@ -758,12 +769,15 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Orbital(rwh_06::OrbitalDisplayHandle::new());
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::OrbitalDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{fmt, str};
|
||||
|
||||
use smol_str::SmolStr;
|
||||
|
||||
pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::keyboard::Key;
|
||||
mod event_loop;
|
||||
@@ -99,6 +99,16 @@ impl TimeSocket {
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct FingerId;
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct PlatformSpecificWindowAttributes;
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use super::event_loop::EventLoopProxy;
|
||||
use super::{ActiveEventLoop, MonitorHandle, RedoxSocket, WindowProperties};
|
||||
use super::{ActiveEventLoop, MonitorHandle, RedoxSocket, TimeSocket, WindowProperties};
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::monitor::MonitorHandle as CoreMonitorHandle;
|
||||
use crate::window::{self, Fullscreen, ImePurpose, Window as CoreWindow, WindowId};
|
||||
@@ -24,7 +23,7 @@ pub struct Window {
|
||||
window_socket: Arc<RedoxSocket>,
|
||||
redraws: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
destroys: Arc<Mutex<VecDeque<WindowId>>>,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
wake_socket: Arc<TimeSocket>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
@@ -114,13 +113,13 @@ impl Window {
|
||||
creates.push_back(window_socket.clone());
|
||||
}
|
||||
|
||||
el.event_loop_proxy.wake_socket.wake().unwrap();
|
||||
el.wake_socket.wake().unwrap();
|
||||
|
||||
Ok(Self {
|
||||
window_socket,
|
||||
redraws: el.redraws.clone(),
|
||||
destroys: el.destroys.clone(),
|
||||
event_loop_proxy: el.event_loop_proxy.clone(),
|
||||
wake_socket: el.wake_socket.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -138,6 +137,7 @@ impl Window {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
||||
let handle = rwh_06::OrbitalWindowHandle::new({
|
||||
@@ -147,6 +147,7 @@ impl Window {
|
||||
Ok(rwh_06::RawWindowHandle::Orbital(handle))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
fn raw_display_handle_rwh_06(&self) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::RawDisplayHandle::Orbital(rwh_06::OrbitalDisplayHandle::new()))
|
||||
@@ -185,7 +186,7 @@ impl CoreWindow for Window {
|
||||
if !redraws.contains(&window_id) {
|
||||
redraws.push_back(window_id);
|
||||
|
||||
self.event_loop_proxy.wake_socket.wake().unwrap();
|
||||
self.wake_socket.wake().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,19 +199,19 @@ impl CoreWindow for Window {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
// TODO: adjust for window decorations
|
||||
(0, 0).into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let path = self.window_socket.fpath(&mut buf).expect("failed to read properties");
|
||||
let properties = WindowProperties::new(path);
|
||||
Ok((properties.x, properties.y).into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
// TODO: adjust for window decorations
|
||||
self.inner_position()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_outer_position(&self, position: Position) {
|
||||
// TODO: adjust for window decorations
|
||||
@@ -239,10 +240,6 @@ impl CoreWindow for Window {
|
||||
self.surface_size()
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
PhysicalInsets::new(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_min_surface_size(&self, _: Option<Size>) {}
|
||||
|
||||
@@ -414,7 +411,7 @@ impl CoreWindow for Window {
|
||||
window::ResizeDirection::West => "L",
|
||||
};
|
||||
self.window_socket
|
||||
.write(format!("D,{arg}").as_bytes())
|
||||
.write(format!("D,{}", arg).as_bytes())
|
||||
.map_err(|err| os_error!(format!("{err}")))?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -450,15 +447,18 @@ impl CoreWindow for Window {
|
||||
|
||||
fn set_content_protected(&self, _protected: bool) {}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_window_handle_rwh_06()?;
|
||||
@@ -466,6 +466,7 @@ impl rwh_06::HasWindowHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
@@ -480,6 +481,6 @@ impl Drop for Window {
|
||||
destroys.push_back(self.id());
|
||||
}
|
||||
|
||||
self.event_loop_proxy.wake_socket.wake().unwrap();
|
||||
self.wake_socket.wake().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ mod channel;
|
||||
mod concurrent_queue;
|
||||
mod dispatcher;
|
||||
mod notifier;
|
||||
mod waker;
|
||||
mod wrapper;
|
||||
|
||||
pub(crate) use atomic_waker::AtomicWaker;
|
||||
use atomic_waker::AtomicWaker;
|
||||
use concurrent_queue::{ConcurrentQueue, PushError};
|
||||
|
||||
pub use self::abortable::{AbortHandle, Abortable, DropAbortHandle};
|
||||
pub use self::channel::{channel, Receiver, Sender};
|
||||
pub use self::dispatcher::{DispatchRunner, Dispatcher};
|
||||
pub use self::notifier::{Notified, Notifier};
|
||||
pub(crate) use self::wrapper::Wrapper;
|
||||
pub use self::waker::{Waker, WakerSpawner};
|
||||
use self::wrapper::Wrapper;
|
||||
|
||||
117
src/platform_impl/web/async/waker.rs
Normal file
117
src/platform_impl/web/async/waker.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use std::future;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use super::{AtomicWaker, Wrapper};
|
||||
|
||||
pub struct WakerSpawner<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||
|
||||
pub struct Waker<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||
|
||||
struct Handler<T> {
|
||||
value: T,
|
||||
handler: fn(&T, bool),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Sender(Arc<Inner>);
|
||||
|
||||
impl<T> WakerSpawner<T> {
|
||||
pub fn new(main_thread: MainThreadMarker, value: T, handler: fn(&T, bool)) -> Self {
|
||||
let inner = Arc::new(Inner {
|
||||
awoken: AtomicBool::new(false),
|
||||
waker: AtomicWaker::new(),
|
||||
closed: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
let handler = Handler { value, handler };
|
||||
|
||||
let sender = Sender(Arc::clone(&inner));
|
||||
|
||||
Self(Wrapper::new(
|
||||
main_thread,
|
||||
handler,
|
||||
|handler, _| {
|
||||
let handler = handler.borrow();
|
||||
let handler = handler.as_ref().unwrap();
|
||||
(handler.handler)(&handler.value, true);
|
||||
},
|
||||
{
|
||||
let inner = Arc::clone(&inner);
|
||||
|
||||
move |handler| async move {
|
||||
while future::poll_fn(|cx| {
|
||||
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
inner.waker.register(cx.waker());
|
||||
|
||||
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
if inner.closed.load(Ordering::Relaxed) {
|
||||
return Poll::Ready(false);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
let handler = handler.borrow();
|
||||
let handler = handler.as_ref().unwrap();
|
||||
(handler.handler)(&handler.value, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
sender,
|
||||
|inner, _| {
|
||||
inner.0.awoken.store(true, Ordering::Relaxed);
|
||||
inner.0.waker.wake();
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn waker(&self) -> Waker<T> {
|
||||
Waker(self.0.clone())
|
||||
}
|
||||
|
||||
pub fn take(&self) -> bool {
|
||||
debug_assert!(
|
||||
MainThreadMarker::new().is_some(),
|
||||
"this should only be called from the main thread"
|
||||
);
|
||||
|
||||
self.0.with_sender_data(|inner| inner.0.awoken.swap(false, Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for WakerSpawner<T> {
|
||||
fn drop(&mut self) {
|
||||
self.0.with_sender_data(|inner| {
|
||||
inner.0.closed.store(true, Ordering::Relaxed);
|
||||
inner.0.waker.wake();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Waker<T> {
|
||||
pub fn wake(&self) {
|
||||
self.0.send(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Waker<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
awoken: AtomicBool,
|
||||
waker: AtomicWaker,
|
||||
closed: AtomicBool,
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::event::DeviceId;
|
||||
use crate::event::{DeviceId, FingerId as RootFingerId};
|
||||
|
||||
pub(crate) fn mkdid(pointer_id: i32) -> Option<DeviceId> {
|
||||
if let Ok(pointer_id) = u32::try_from(pointer_id) {
|
||||
@@ -10,3 +10,30 @@ pub(crate) fn mkdid(pointer_id: i32) -> Option<DeviceId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId {
|
||||
pointer_id: i32,
|
||||
primary: bool,
|
||||
}
|
||||
|
||||
impl FingerId {
|
||||
pub fn new(pointer_id: i32, primary: bool) -> Self {
|
||||
Self { pointer_id, primary }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
Self { pointer_id: -1, primary: false }
|
||||
}
|
||||
|
||||
pub fn is_primary(self) -> bool {
|
||||
self.primary
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FingerId> for RootFingerId {
|
||||
fn from(id: FingerId) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ pub(crate) mod runner;
|
||||
mod state;
|
||||
mod window_target;
|
||||
|
||||
pub(crate) use window_target::ActiveEventLoop;
|
||||
pub(crate) use proxy::EventLoopProxy;
|
||||
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
||||
|
||||
pub struct EventLoop {
|
||||
elw: ActiveEventLoop,
|
||||
|
||||
@@ -1,101 +1,17 @@
|
||||
use std::future;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
use super::runner::WeakShared;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use crate::event_loop::EventLoopProxyProvider;
|
||||
use crate::platform_impl::web::event_loop::runner::WeakShared;
|
||||
use crate::platform_impl::web::r#async::{AtomicWaker, Wrapper};
|
||||
|
||||
pub struct EventLoopProxy(Wrapper<WeakShared, Arc<State>, ()>);
|
||||
|
||||
struct State {
|
||||
awoken: AtomicBool,
|
||||
waker: AtomicWaker,
|
||||
closed: AtomicBool,
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
runner: Waker<WeakShared>,
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub fn new(main_thread: MainThreadMarker, runner: WeakShared) -> Self {
|
||||
let state = Arc::new(State {
|
||||
awoken: AtomicBool::new(false),
|
||||
waker: AtomicWaker::new(),
|
||||
closed: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
Self(Wrapper::new(
|
||||
main_thread,
|
||||
runner,
|
||||
|runner, _| {
|
||||
let runner = runner.borrow();
|
||||
let runner = runner.as_ref().unwrap();
|
||||
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
let state = Arc::clone(&state);
|
||||
|
||||
move |runner| async move {
|
||||
while future::poll_fn(|cx| {
|
||||
if state.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
if state.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
if state.closed.load(Ordering::Relaxed) {
|
||||
return Poll::Ready(false);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
let runner = runner.borrow();
|
||||
let runner = runner.as_ref().unwrap();
|
||||
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
state,
|
||||
|state, _| {
|
||||
state.awoken.store(true, Ordering::Relaxed);
|
||||
state.waker.wake();
|
||||
},
|
||||
))
|
||||
pub fn new(runner: Waker<WeakShared>) -> Self {
|
||||
Self { runner }
|
||||
}
|
||||
|
||||
pub fn take(&self) -> bool {
|
||||
debug_assert!(
|
||||
MainThreadMarker::new().is_some(),
|
||||
"this should only be called from the main thread"
|
||||
);
|
||||
|
||||
self.0.with_sender_data(|state| state.awoken.swap(false, Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EventLoopProxy {
|
||||
fn drop(&mut self) {
|
||||
self.0.with_sender_data(|state| {
|
||||
state.closed.store(true, Ordering::Relaxed);
|
||||
state.waker.wake();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.0.send(())
|
||||
pub fn wake_up(&self) {
|
||||
self.runner.wake();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ use std::collections::{HashSet, VecDeque};
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::Arc;
|
||||
|
||||
use wasm_bindgen::prelude::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
@@ -14,14 +13,13 @@ use super::super::event;
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use super::super::monitor::MonitorHandler;
|
||||
use super::backend;
|
||||
use super::proxy::EventLoopProxy;
|
||||
use super::state::State;
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::{DeviceEvent, ElementState, Event, RawKeyEvent, StartCause, WindowEvent};
|
||||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
||||
use crate::platform_impl::platform::backend::{EventListenerHandle, SafeAreaHandle};
|
||||
use crate::platform_impl::platform::r#async::DispatchRunner;
|
||||
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
||||
use crate::platform_impl::platform::window::Inner;
|
||||
use crate::window::WindowId;
|
||||
|
||||
@@ -39,7 +37,7 @@ type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
||||
|
||||
struct Execution {
|
||||
main_thread: MainThreadMarker,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
proxy_spawner: WakerSpawner<WeakShared>,
|
||||
control_flow: Cell<ControlFlow>,
|
||||
poll_strategy: Cell<PollStrategy>,
|
||||
wait_until_strategy: Cell<WaitUntilStrategy>,
|
||||
@@ -57,7 +55,6 @@ struct Execution {
|
||||
redraw_pending: RefCell<HashSet<WindowId>>,
|
||||
destroy_pending: RefCell<VecDeque<WindowId>>,
|
||||
pub(crate) monitor: Rc<MonitorHandler>,
|
||||
safe_area: Rc<SafeAreaHandle>,
|
||||
page_transition_event_handle: RefCell<Option<backend::PageTransitionEventHandle>>,
|
||||
device_events: Cell<DeviceEvents>,
|
||||
on_mouse_move: OnEventHandle<PointerEvent>,
|
||||
@@ -143,7 +140,12 @@ impl Shared {
|
||||
let document = window.document().expect("Failed to obtain document");
|
||||
|
||||
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
||||
let proxy_spawner = EventLoopProxy::new(main_thread, WeakShared(weak.clone()));
|
||||
let proxy_spawner =
|
||||
WakerSpawner::new(main_thread, WeakShared(weak.clone()), |runner, local| {
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(local);
|
||||
}
|
||||
});
|
||||
|
||||
let monitor = MonitorHandler::new(
|
||||
main_thread,
|
||||
@@ -152,11 +154,9 @@ impl Shared {
|
||||
WeakShared(weak.clone()),
|
||||
);
|
||||
|
||||
let safe_area = SafeAreaHandle::new(&window, &document);
|
||||
|
||||
Execution {
|
||||
main_thread,
|
||||
event_loop_proxy: Arc::new(proxy_spawner),
|
||||
proxy_spawner,
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
poll_strategy: Cell::new(PollStrategy::default()),
|
||||
wait_until_strategy: Cell::new(WaitUntilStrategy::default()),
|
||||
@@ -173,7 +173,6 @@ impl Shared {
|
||||
redraw_pending: RefCell::new(HashSet::new()),
|
||||
destroy_pending: RefCell::new(VecDeque::new()),
|
||||
monitor: Rc::new(monitor),
|
||||
safe_area: Rc::new(safe_area),
|
||||
page_transition_event_handle: RefCell::new(None),
|
||||
device_events: Cell::default(),
|
||||
on_mouse_move: RefCell::new(None),
|
||||
@@ -654,7 +653,7 @@ impl Shared {
|
||||
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
||||
events.extend(
|
||||
self.0
|
||||
.event_loop_proxy
|
||||
.proxy_spawner
|
||||
.take()
|
||||
.then_some(Event::UserWakeUp)
|
||||
.map(EventWrapper::from),
|
||||
@@ -819,8 +818,8 @@ impl Shared {
|
||||
self.0.wait_until_strategy.get()
|
||||
}
|
||||
|
||||
pub(crate) fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.0.event_loop_proxy
|
||||
pub(crate) fn waker(&self) -> Waker<WeakShared> {
|
||||
self.0.proxy_spawner.waker()
|
||||
}
|
||||
|
||||
pub(crate) fn weak(&self) -> WeakShared {
|
||||
@@ -830,10 +829,6 @@ impl Shared {
|
||||
pub(crate) fn monitor(&self) -> &Rc<MonitorHandler> {
|
||||
&self.0.monitor
|
||||
}
|
||||
|
||||
pub(crate) fn safe_area(&self) -> &Rc<SafeAreaHandle> {
|
||||
&self.0.safe_area
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -2,25 +2,24 @@ use std::cell::Cell;
|
||||
use std::clone::Clone;
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use web_sys::Element;
|
||||
|
||||
use super::super::monitor::MonitorPermissionFuture;
|
||||
use super::super::{lock, KeyEventExtra};
|
||||
use super::runner::EventWrapper;
|
||||
use super::{backend, runner};
|
||||
use super::runner::{EventWrapper, WeakShared};
|
||||
use super::{backend, runner, EventLoopProxy};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{ElementState, Event, KeyEvent, TouchPhase, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy};
|
||||
use crate::platform_impl::platform::cursor::CustomCursor;
|
||||
use crate::platform_impl::web::event_loop::proxy::EventLoopProxy;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
use crate::platform_impl::Window;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId};
|
||||
|
||||
@@ -198,7 +197,7 @@ impl ActiveEventLoop {
|
||||
let has_focus = has_focus.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, primary, position, kind| {
|
||||
move |active_modifiers, device_id, position, kind| {
|
||||
let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
@@ -209,12 +208,7 @@ impl ActiveEventLoop {
|
||||
|
||||
runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind,
|
||||
},
|
||||
event: WindowEvent::PointerLeft { device_id, position: Some(position), kind },
|
||||
})))
|
||||
}
|
||||
});
|
||||
@@ -224,7 +218,7 @@ impl ActiveEventLoop {
|
||||
let has_focus = has_focus.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, primary, position, kind| {
|
||||
move |active_modifiers, device_id, position, kind| {
|
||||
let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
@@ -235,7 +229,7 @@ impl ActiveEventLoop {
|
||||
|
||||
runner.send_events(focus.into_iter().chain(iter::once(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered { device_id, primary, position, kind },
|
||||
event: WindowEvent::PointerEntered { device_id, position, kind },
|
||||
})))
|
||||
}
|
||||
});
|
||||
@@ -247,31 +241,21 @@ impl ActiveEventLoop {
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |device_id, events| {
|
||||
runner.send_events(events.flat_map(
|
||||
|(active_modifiers, primary, position, source)| {
|
||||
let modifiers = (has_focus.get()
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ModifiersChanged(
|
||||
active_modifiers.into(),
|
||||
),
|
||||
}
|
||||
});
|
||||
runner.send_events(events.flat_map(|(active_modifiers, position, source)| {
|
||||
let modifiers = (has_focus.get() && modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
|
||||
}
|
||||
});
|
||||
|
||||
modifiers.into_iter().chain(iter::once(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id,
|
||||
primary,
|
||||
position,
|
||||
source,
|
||||
},
|
||||
}))
|
||||
},
|
||||
));
|
||||
modifiers.into_iter().chain(iter::once(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved { device_id, position, source },
|
||||
}))
|
||||
}));
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -279,7 +263,7 @@ impl ActiveEventLoop {
|
||||
let has_focus = has_focus.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, primary, position, state, button| {
|
||||
move |active_modifiers, device_id, position, state, button| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
@@ -291,13 +275,7 @@ impl ActiveEventLoop {
|
||||
|
||||
runner.send_events(modifiers.into_iter().chain([Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary,
|
||||
state,
|
||||
position,
|
||||
button,
|
||||
},
|
||||
event: WindowEvent::PointerButton { device_id, state, position, button },
|
||||
}]));
|
||||
}
|
||||
},
|
||||
@@ -307,7 +285,7 @@ impl ActiveEventLoop {
|
||||
let runner = self.runner.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, primary, position, button| {
|
||||
move |active_modifiers, device_id, position, button| {
|
||||
let modifiers = (modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
@@ -320,7 +298,6 @@ impl ActiveEventLoop {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary,
|
||||
state: ElementState::Pressed,
|
||||
position,
|
||||
button,
|
||||
@@ -334,7 +311,7 @@ impl ActiveEventLoop {
|
||||
let has_focus = has_focus.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, primary, position, button| {
|
||||
move |active_modifiers, device_id, position, button| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
@@ -348,7 +325,6 @@ impl ActiveEventLoop {
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id,
|
||||
primary,
|
||||
state: ElementState::Released,
|
||||
position,
|
||||
button,
|
||||
@@ -477,15 +453,15 @@ impl ActiveEventLoop {
|
||||
self.runner.monitor().has_detailed_monitor_permission()
|
||||
}
|
||||
|
||||
pub(crate) fn event_loop_proxy(&self) -> Arc<EventLoopProxy> {
|
||||
self.runner.event_loop_proxy().clone()
|
||||
pub(crate) fn waker(&self) -> Waker<WeakShared> {
|
||||
self.runner.waker()
|
||||
}
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = self.event_loop_proxy();
|
||||
RootEventLoopProxy::new(event_loop_proxy)
|
||||
let event_loop_proxy = EventLoopProxy::new(self.waker());
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -547,15 +523,17 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.runner.exiting()
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Web(rwh_06::WebDisplayHandle::new());
|
||||
@@ -563,12 +541,15 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Web(rwh_06::WebDisplayHandle::new());
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::WebDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,10 @@ pub(crate) use cursor::{
|
||||
CustomCursorSource as PlatformCustomCursorSource,
|
||||
};
|
||||
|
||||
pub use self::event::FingerId;
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
||||
PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::keyboard::KeyEventExtra;
|
||||
pub(crate) use self::monitor::{
|
||||
|
||||
@@ -72,8 +72,8 @@ pub struct Common {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Style {
|
||||
pub(super) read: CssStyleDeclaration,
|
||||
pub(super) write: CssStyleDeclaration,
|
||||
read: CssStyleDeclaration,
|
||||
write: CssStyleDeclaration,
|
||||
}
|
||||
|
||||
impl Canvas {
|
||||
@@ -331,32 +331,28 @@ impl Canvas {
|
||||
|
||||
pub fn on_pointer_leave<F>(&self, handler: F)
|
||||
where
|
||||
F: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
|
||||
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
|
||||
{
|
||||
self.handlers.borrow_mut().pointer_handler.on_pointer_leave(&self.common, handler)
|
||||
}
|
||||
|
||||
pub fn on_pointer_enter<F>(&self, handler: F)
|
||||
where
|
||||
F: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
|
||||
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
|
||||
{
|
||||
self.handlers.borrow_mut().pointer_handler.on_pointer_enter(&self.common, handler)
|
||||
}
|
||||
|
||||
pub fn on_pointer_release<C>(&self, handler: C)
|
||||
where
|
||||
C: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
|
||||
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
|
||||
{
|
||||
self.handlers.borrow_mut().pointer_handler.on_pointer_release(&self.common, handler)
|
||||
}
|
||||
|
||||
pub fn on_pointer_press<C>(&self, handler: C)
|
||||
where
|
||||
C: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
|
||||
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
|
||||
{
|
||||
self.handlers.borrow_mut().pointer_handler.on_pointer_press(
|
||||
&self.common,
|
||||
@@ -370,15 +366,12 @@ impl Canvas {
|
||||
C: 'static
|
||||
+ FnMut(
|
||||
Option<DeviceId>,
|
||||
&mut dyn Iterator<
|
||||
Item = (ModifiersState, bool, PhysicalPosition<f64>, PointerSource),
|
||||
>,
|
||||
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
|
||||
),
|
||||
B: 'static
|
||||
+ FnMut(
|
||||
ModifiersState,
|
||||
Option<DeviceId>,
|
||||
bool,
|
||||
PhysicalPosition<f64>,
|
||||
ElementState,
|
||||
ButtonSource,
|
||||
|
||||
@@ -6,8 +6,9 @@ use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{KeyboardEvent, MouseEvent, Navigator, PointerEvent, WheelEvent};
|
||||
|
||||
use super::super::FingerId;
|
||||
use super::Engine;
|
||||
use crate::event::{FingerId, MouseButton, MouseScrollDelta, PointerKind};
|
||||
use crate::event::{MouseButton, MouseScrollDelta, PointerKind};
|
||||
use crate::keyboard::{Key, KeyLocation, ModifiersState, NamedKey, PhysicalKey};
|
||||
|
||||
bitflags::bitflags! {
|
||||
@@ -163,7 +164,7 @@ pub fn mouse_scroll_delta(
|
||||
pub fn pointer_type(event: &PointerEvent, pointer_id: i32) -> PointerKind {
|
||||
match event.pointer_type().as_str() {
|
||||
"mouse" => PointerKind::Mouse,
|
||||
"touch" => PointerKind::Touch(FingerId::from_raw(pointer_id as usize)),
|
||||
"touch" => PointerKind::Touch(FingerId::new(pointer_id, event.is_primary()).into()),
|
||||
_ => PointerKind::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ mod intersection_handle;
|
||||
mod media_query_handle;
|
||||
mod pointer;
|
||||
mod resize_scaling;
|
||||
mod safe_area;
|
||||
mod schedule;
|
||||
|
||||
use std::cell::OnceCell;
|
||||
@@ -21,7 +20,6 @@ use web_sys::{Document, HtmlCanvasElement, Navigator, PageTransitionEvent, Visib
|
||||
pub use self::canvas::{Canvas, Style};
|
||||
pub use self::event_handle::EventListenerHandle;
|
||||
pub use self::resize_scaling::ResizeScaleHandle;
|
||||
pub use self::safe_area::SafeAreaHandle;
|
||||
pub use self::schedule::Schedule;
|
||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@ impl PointerHandler {
|
||||
|
||||
pub fn on_pointer_leave<F>(&mut self, canvas_common: &Common, mut handler: F)
|
||||
where
|
||||
F: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
|
||||
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
|
||||
{
|
||||
let window = canvas_common.window.clone();
|
||||
self.on_cursor_leave =
|
||||
@@ -47,14 +46,13 @@ impl PointerHandler {
|
||||
let position =
|
||||
event::mouse_position(&event).to_physical(super::scale_factor(&window));
|
||||
let kind = event::pointer_type(&event, pointer_id);
|
||||
handler(modifiers, device_id, event.is_primary(), position, kind);
|
||||
handler(modifiers, device_id, position, kind);
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_pointer_enter<F>(&mut self, canvas_common: &Common, mut handler: F)
|
||||
where
|
||||
F: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, PointerKind),
|
||||
F: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, PointerKind),
|
||||
{
|
||||
let window = canvas_common.window.clone();
|
||||
self.on_cursor_enter =
|
||||
@@ -65,14 +63,13 @@ impl PointerHandler {
|
||||
let position =
|
||||
event::mouse_position(&event).to_physical(super::scale_factor(&window));
|
||||
let kind = event::pointer_type(&event, pointer_id);
|
||||
handler(modifiers, device_id, event.is_primary(), position, kind);
|
||||
handler(modifiers, device_id, position, kind);
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_pointer_release<C>(&mut self, canvas_common: &Common, mut handler: C)
|
||||
where
|
||||
C: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
|
||||
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
|
||||
{
|
||||
let window = canvas_common.window.clone();
|
||||
self.on_pointer_release =
|
||||
@@ -95,7 +92,6 @@ impl PointerHandler {
|
||||
handler(
|
||||
modifiers,
|
||||
mkdid(pointer_id),
|
||||
event.is_primary(),
|
||||
event::mouse_position(&event).to_physical(super::scale_factor(&window)),
|
||||
source,
|
||||
)
|
||||
@@ -108,8 +104,7 @@ impl PointerHandler {
|
||||
mut handler: C,
|
||||
prevent_default: Rc<Cell<bool>>,
|
||||
) where
|
||||
C: 'static
|
||||
+ FnMut(ModifiersState, Option<DeviceId>, bool, PhysicalPosition<f64>, ButtonSource),
|
||||
C: 'static + FnMut(ModifiersState, Option<DeviceId>, PhysicalPosition<f64>, ButtonSource),
|
||||
{
|
||||
let window = canvas_common.window.clone();
|
||||
let canvas = canvas_common.raw().clone();
|
||||
@@ -148,7 +143,6 @@ impl PointerHandler {
|
||||
handler(
|
||||
modifiers,
|
||||
mkdid(pointer_id),
|
||||
event.is_primary(),
|
||||
event::mouse_position(&event).to_physical(super::scale_factor(&window)),
|
||||
source,
|
||||
)
|
||||
@@ -165,15 +159,12 @@ impl PointerHandler {
|
||||
C: 'static
|
||||
+ FnMut(
|
||||
Option<DeviceId>,
|
||||
&mut dyn Iterator<
|
||||
Item = (ModifiersState, bool, PhysicalPosition<f64>, PointerSource),
|
||||
>,
|
||||
&mut dyn Iterator<Item = (ModifiersState, PhysicalPosition<f64>, PointerSource)>,
|
||||
),
|
||||
B: 'static
|
||||
+ FnMut(
|
||||
ModifiersState,
|
||||
Option<DeviceId>,
|
||||
bool,
|
||||
PhysicalPosition<f64>,
|
||||
ElementState,
|
||||
ButtonSource,
|
||||
@@ -186,7 +177,6 @@ impl PointerHandler {
|
||||
let pointer_id = event.pointer_id();
|
||||
let device_id = mkdid(pointer_id);
|
||||
let kind = event::pointer_type(&event, pointer_id);
|
||||
let primary = event.is_primary();
|
||||
|
||||
// chorded button event
|
||||
if let Some(button) = event::mouse_button(&event) {
|
||||
@@ -223,7 +213,6 @@ impl PointerHandler {
|
||||
button_handler(
|
||||
event::mouse_modifiers(&event),
|
||||
device_id,
|
||||
primary,
|
||||
event::mouse_position(&event).to_physical(super::scale_factor(&window)),
|
||||
state,
|
||||
button,
|
||||
@@ -240,7 +229,6 @@ impl PointerHandler {
|
||||
&mut event::pointer_move_event(event).map(|event| {
|
||||
(
|
||||
event::mouse_modifiers(&event),
|
||||
event.is_primary(),
|
||||
event::mouse_position(&event).to_physical(scale),
|
||||
match kind {
|
||||
PointerKind::Mouse => PointerSource::Mouse,
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
use dpi::{LogicalPosition, LogicalSize};
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{Document, HtmlHtmlElement, Window};
|
||||
|
||||
use super::Style;
|
||||
|
||||
pub struct SafeAreaHandle {
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl SafeAreaHandle {
|
||||
pub fn new(window: &Window, document: &Document) -> Self {
|
||||
let document: HtmlHtmlElement = document.document_element().unwrap().unchecked_into();
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let write = document.style();
|
||||
write
|
||||
.set_property(
|
||||
"--__winit_safe_area",
|
||||
"env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) \
|
||||
env(safe-area-inset-left)",
|
||||
)
|
||||
.expect("unexpected read-only declaration block");
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
let read = window
|
||||
.get_computed_style(&document)
|
||||
.expect("failed to obtain computed style")
|
||||
// this can't fail: we aren't using a pseudo-element
|
||||
.expect("invalid pseudo-element");
|
||||
|
||||
SafeAreaHandle { style: Style { read, write } }
|
||||
}
|
||||
|
||||
pub fn get(&self) -> (LogicalPosition<f64>, LogicalSize<f64>) {
|
||||
let value = self.style.get("--__winit_safe_area");
|
||||
|
||||
let mut values = value
|
||||
.split(' ')
|
||||
.map(|value| value.strip_suffix("px").expect("unexpected unit other then `px` found"));
|
||||
let top: f64 = values.next().unwrap().parse().unwrap();
|
||||
let right: f64 = values.next().unwrap().parse().unwrap();
|
||||
let bottom: f64 = values.next().unwrap().parse().unwrap();
|
||||
let left: f64 = values.next().unwrap().parse().unwrap();
|
||||
assert_eq!(values.next(), None, "unexpected fifth value");
|
||||
|
||||
let width = super::style_size_property(&self.style, "width") - left - right;
|
||||
let height = super::style_size_property(&self.style, "height") - top - bottom;
|
||||
|
||||
(LogicalPosition::new(left, top), LogicalSize::new(width, height))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SafeAreaHandle {
|
||||
fn drop(&mut self) {
|
||||
self.style.remove("--__winit_safe_area");
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,13 @@ use std::cell::Ref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use dpi::{LogicalPosition, LogicalSize};
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
||||
use super::main_thread::{MainThreadMarker, MainThreadSafe};
|
||||
use super::monitor::MonitorHandler;
|
||||
use super::r#async::Dispatcher;
|
||||
use super::{backend, lock, ActiveEventLoop};
|
||||
use crate::dpi::{LogicalInsets, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::icon::Icon;
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
@@ -27,7 +26,6 @@ pub struct Inner {
|
||||
id: WindowId,
|
||||
pub window: web_sys::Window,
|
||||
monitor: Rc<MonitorHandler>,
|
||||
safe_area: Rc<backend::SafeAreaHandle>,
|
||||
canvas: Rc<backend::Canvas>,
|
||||
destroy_fn: Option<Box<dyn FnOnce()>>,
|
||||
}
|
||||
@@ -61,7 +59,6 @@ impl Window {
|
||||
id,
|
||||
window: window.clone(),
|
||||
monitor: Rc::clone(target.runner.monitor()),
|
||||
safe_area: Rc::clone(target.runner.safe_area()),
|
||||
canvas,
|
||||
destroy_fn: Some(destroy_fn),
|
||||
};
|
||||
@@ -112,9 +109,9 @@ impl RootWindow for Window {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
// Note: the canvas element has no window decorations.
|
||||
(0, 0).into()
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
// Note: the canvas element has no window decorations, so this is equal to `outer_position`.
|
||||
self.outer_position()
|
||||
}
|
||||
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
@@ -155,34 +152,6 @@ impl RootWindow for Window {
|
||||
self.surface_size()
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
self.inner.queue(|inner| {
|
||||
let (safe_start_pos, safe_size) = inner.safe_area.get();
|
||||
let safe_end_pos = LogicalPosition::new(
|
||||
safe_start_pos.x + safe_size.width,
|
||||
safe_start_pos.y + safe_size.height,
|
||||
);
|
||||
|
||||
let surface_start_pos = inner.canvas.position();
|
||||
let surface_size = LogicalSize::new(
|
||||
backend::style_size_property(inner.canvas.style(), "width"),
|
||||
backend::style_size_property(inner.canvas.style(), "height"),
|
||||
);
|
||||
let surface_end_pos = LogicalPosition::new(
|
||||
surface_start_pos.x + surface_size.width,
|
||||
surface_start_pos.y + surface_size.height,
|
||||
);
|
||||
|
||||
let top = f64::max(safe_start_pos.y - surface_start_pos.y, 0.);
|
||||
let left = f64::max(safe_start_pos.x - surface_start_pos.x, 0.);
|
||||
let bottom = f64::max(surface_end_pos.y - safe_end_pos.y, 0.);
|
||||
let right = f64::max(surface_end_pos.x - safe_end_pos.x, 0.);
|
||||
|
||||
let insets = LogicalInsets::new(top, left, bottom, right);
|
||||
insets.to_physical(inner.scale_factor())
|
||||
})
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
||||
self.inner.dispatch(move |inner| {
|
||||
let dimensions = min_size.map(|min_size| min_size.to_logical(inner.scale_factor()));
|
||||
@@ -406,15 +375,18 @@ impl RootWindow for Window {
|
||||
self.inner.queue(|inner| inner.monitor.primary_monitor()).map(RootMonitorHandle::from)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
MainThreadMarker::new()
|
||||
@@ -436,6 +408,7 @@ impl rwh_06::HasWindowHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
Ok(rwh_06::DisplayHandle::web())
|
||||
|
||||
@@ -4,7 +4,6 @@ mod runner;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::ffi::c_void;
|
||||
use std::os::windows::io::{AsRawHandle as _, FromRawHandle as _, OwnedHandle, RawHandle};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
@@ -13,20 +12,13 @@ use std::{mem, panic, ptr};
|
||||
|
||||
use runner::EventLoopRunner;
|
||||
use windows_sys::Win32::Devices::HumanInterfaceDevice::MOUSE_MOVE_RELATIVE;
|
||||
use windows_sys::Win32::Foundation::{
|
||||
GetLastError, FALSE, HANDLE, HWND, LPARAM, LRESULT, POINT, RECT, WAIT_FAILED, WPARAM,
|
||||
};
|
||||
use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, POINT, RECT, WPARAM};
|
||||
use windows_sys::Win32::Graphics::Gdi::{
|
||||
GetMonitorInfoW, MonitorFromRect, MonitorFromWindow, RedrawWindow, ScreenToClient,
|
||||
ValidateRect, MONITORINFO, MONITOR_DEFAULTTONULL, RDW_INTERNALPAINT, SC_SCREENSAVE,
|
||||
};
|
||||
use windows_sys::Win32::System::Diagnostics::ToolHelp as toolhelp;
|
||||
use windows_sys::Win32::System::Ole::RevokeDragDrop;
|
||||
use windows_sys::Win32::System::Threading::{
|
||||
CreateWaitableTimerExW, GetCurrentProcessId, GetCurrentThreadId, GetThreadTimes, OpenThread,
|
||||
SetWaitableTimer, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, INFINITE, THREAD_QUERY_INFORMATION,
|
||||
TIMER_ALL_ACCESS,
|
||||
};
|
||||
use windows_sys::Win32::System::Threading::{GetCurrentThreadId, INFINITE};
|
||||
use windows_sys::Win32::UI::Controls::{HOVER_DEFAULT, WM_MOUSELEAVE};
|
||||
use windows_sys::Win32::UI::Input::Ime::{GCS_COMPSTR, GCS_RESULTSTR, ISC_SHOWUICOMPOSITIONWINDOW};
|
||||
use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
|
||||
@@ -42,15 +34,14 @@ use windows_sys::Win32::UI::Input::Touch::{
|
||||
use windows_sys::Win32::UI::Input::{RAWINPUT, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE};
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetClientRect, GetCursorPos,
|
||||
GetMenu, LoadCursorW, MsgWaitForMultipleObjectsEx, PeekMessageW, PostMessageW,
|
||||
RegisterClassExW, RegisterWindowMessageA, SetCursor, SetWindowPos, TranslateMessage,
|
||||
CREATESTRUCTW, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG,
|
||||
MWMO_INPUTAVAILABLE, NCCALCSIZE_PARAMS, PM_REMOVE, PT_TOUCH, QS_ALLEVENTS, RI_MOUSE_HWHEEL,
|
||||
RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE,
|
||||
SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM, WMSZ_BOTTOMLEFT,
|
||||
WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT, WMSZ_TOPRIGHT,
|
||||
WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE,
|
||||
WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION,
|
||||
GetMenu, GetMessageW, KillTimer, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW,
|
||||
RegisterWindowMessageA, SetCursor, SetTimer, SetWindowPos, TranslateMessage, CREATESTRUCTW,
|
||||
GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT, MINMAXINFO, MNC_CLOSE, MSG, NCCALCSIZE_PARAMS,
|
||||
PM_REMOVE, PT_TOUCH, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED,
|
||||
SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS, WMSZ_BOTTOM,
|
||||
WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
|
||||
WMSZ_TOPRIGHT, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED,
|
||||
WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION,
|
||||
WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS,
|
||||
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL,
|
||||
WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY,
|
||||
@@ -67,12 +58,12 @@ use crate::application::ApplicationHandler;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::error::{EventLoopError, RequestError};
|
||||
use crate::event::{
|
||||
Event, FingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, TouchPhase, WindowEvent,
|
||||
Event, FingerId as RootFingerId, Force, Ime, RawKeyEvent, SurfaceSizeWriter, TouchPhase,
|
||||
WindowEvent,
|
||||
};
|
||||
use crate::event_loop::{
|
||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
|
||||
EventLoopProxy as RootEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
EventLoopProxy as RootEventLoopProxy, OwnedDisplayHandle as RootOwnedDisplayHandle,
|
||||
};
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
@@ -89,7 +80,7 @@ use crate::platform_impl::platform::window::InitData;
|
||||
use crate::platform_impl::platform::window_state::{
|
||||
CursorFlags, ImeState, WindowFlags, WindowState,
|
||||
};
|
||||
use crate::platform_impl::platform::{raw_input, util, wrap_device_id, Fullscreen};
|
||||
use crate::platform_impl::platform::{raw_input, util, wrap_device_id, FingerId, Fullscreen};
|
||||
use crate::platform_impl::Window;
|
||||
use crate::utils::Lazy;
|
||||
use crate::window::{
|
||||
@@ -136,10 +127,6 @@ pub(crate) enum ProcResult {
|
||||
pub struct EventLoop {
|
||||
window_target: ActiveEventLoop,
|
||||
msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
|
||||
// It is a timer used on timed waits.
|
||||
// It is created lazily in case if we have `ControlFlow::WaitUntil`.
|
||||
// Keep it as a field to avoid recreating it on every `ControlFlow::WaitUntil`.
|
||||
high_resolution_timer: Option<OwnedHandle>,
|
||||
}
|
||||
|
||||
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
||||
@@ -214,7 +201,6 @@ impl EventLoop {
|
||||
Ok(EventLoop {
|
||||
window_target: ActiveEventLoop { thread_id, thread_msg_target, runner_shared },
|
||||
msg_hook: attributes.msg_hook.take(),
|
||||
high_resolution_timer: None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -259,9 +245,8 @@ impl EventLoop {
|
||||
}
|
||||
|
||||
let exit_code = loop {
|
||||
self.wait_for_messages(None);
|
||||
// wait_for_messages calls user application before and after waiting
|
||||
// so it may have decided to exit.
|
||||
self.wait_and_dispatch_message(None);
|
||||
|
||||
if let Some(code) = self.exit_code() {
|
||||
break code;
|
||||
}
|
||||
@@ -327,11 +312,8 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
if self.exit_code().is_none() {
|
||||
self.wait_for_messages(timeout);
|
||||
}
|
||||
// wait_for_messages calls user application before and after waiting
|
||||
// so it may have decided to exit.
|
||||
self.wait_and_dispatch_message(timeout);
|
||||
|
||||
if self.exit_code().is_none() {
|
||||
self.dispatch_peeked_messages();
|
||||
}
|
||||
@@ -361,27 +343,101 @@ impl EventLoop {
|
||||
status
|
||||
}
|
||||
|
||||
/// Waits until new event messages arrive to be peeked.
|
||||
/// Doesn't peek messages itself.
|
||||
///
|
||||
/// Parameter timeout is optional. This method would wait for the smaller timeout
|
||||
/// between the argument and a timeout from control flow.
|
||||
fn wait_for_messages(&mut self, timeout: Option<Duration>) {
|
||||
/// Wait for one message and dispatch it, optionally with a timeout
|
||||
fn wait_and_dispatch_message(&mut self, timeout: Option<Duration>) {
|
||||
fn get_msg_with_timeout(msg: &mut MSG, timeout: Option<Duration>) -> PumpStatus {
|
||||
unsafe {
|
||||
// A timeout of None means wait indefinitely (so we don't need to call SetTimer)
|
||||
let timer_id = timeout.map(|timeout| SetTimer(0, 0, dur2timeout(timeout), None));
|
||||
let get_status = GetMessageW(msg, 0, 0, 0);
|
||||
if let Some(timer_id) = timer_id {
|
||||
KillTimer(0, timer_id);
|
||||
}
|
||||
// A return value of 0 implies `WM_QUIT`
|
||||
if get_status == 0 {
|
||||
PumpStatus::Exit(0)
|
||||
} else {
|
||||
PumpStatus::Continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the next MSG either via PeekMessage or GetMessage depending on whether the
|
||||
/// requested timeout is `ZERO` (and so we don't want to block)
|
||||
///
|
||||
/// Returns `None` if no MSG was read, else a `Continue` or `Exit` status
|
||||
fn wait_for_msg(msg: &mut MSG, timeout: Option<Duration>) -> Option<PumpStatus> {
|
||||
if timeout == Some(Duration::ZERO) {
|
||||
unsafe {
|
||||
if PeekMessageW(msg, 0, 0, 0, PM_REMOVE) != 0 {
|
||||
Some(PumpStatus::Continue)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(get_msg_with_timeout(msg, timeout))
|
||||
}
|
||||
}
|
||||
|
||||
let runner = &self.window_target.runner_shared;
|
||||
|
||||
// We aim to be consistent with the MacOS backend which has a RunLoop
|
||||
// observer that will dispatch AboutToWait when about to wait for
|
||||
// events, and NewEvents after the RunLoop wakes up.
|
||||
//
|
||||
// We emulate similar behaviour by treating `MsgWaitForMultipleObjectsEx` as our wait
|
||||
// We emulate similar behaviour by treating `GetMessage` as our wait
|
||||
// point and wake up point (when it returns) and we drain all other
|
||||
// pending messages via `PeekMessage` until we come back to "wait" via
|
||||
// `MsgWaitForMultipleObjectsEx`.
|
||||
// `GetMessage`
|
||||
//
|
||||
runner.prepare_wait();
|
||||
wait_for_messages_impl(&mut self.high_resolution_timer, runner.control_flow(), timeout);
|
||||
|
||||
let control_flow_timeout = match runner.control_flow() {
|
||||
ControlFlow::Wait => None,
|
||||
ControlFlow::Poll => Some(Duration::ZERO),
|
||||
ControlFlow::WaitUntil(wait_deadline) => {
|
||||
let start = Instant::now();
|
||||
Some(wait_deadline.saturating_duration_since(start))
|
||||
},
|
||||
};
|
||||
let timeout = min_timeout(control_flow_timeout, timeout);
|
||||
|
||||
// # Safety
|
||||
// The Windows API has no documented requirement for bitwise
|
||||
// initializing a `MSG` struct (it can be uninitialized memory for the C
|
||||
// API) and there's no API to construct or initialize a `MSG`. This
|
||||
// is the simplest way avoid uninitialized memory in Rust
|
||||
let mut msg = unsafe { mem::zeroed() };
|
||||
let msg_status = wait_for_msg(&mut msg, timeout);
|
||||
|
||||
// Before we potentially exit, make sure to consistently emit an event for the wake up
|
||||
runner.wakeup();
|
||||
|
||||
match msg_status {
|
||||
None => {}, // No MSG to dispatch
|
||||
Some(PumpStatus::Exit(code)) => {
|
||||
runner.set_exit_code(code);
|
||||
},
|
||||
Some(PumpStatus::Continue) => {
|
||||
unsafe {
|
||||
let handled = if let Some(callback) = self.msg_hook.as_deref_mut() {
|
||||
callback(&mut msg as *mut _ as *mut _)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !handled {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(payload) = runner.take_panic_error() {
|
||||
runner.reset_runner();
|
||||
panic::resume_unwind(payload);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Dispatch all queued messages via `PeekMessageW`
|
||||
@@ -400,7 +456,7 @@ impl EventLoop {
|
||||
// initializing a `MSG` struct (it can be uninitialized memory for the C
|
||||
// API) and there's no API to construct or initialize a `MSG`. This
|
||||
// is the simplest way avoid uninitialized memory in Rust
|
||||
let mut msg: MSG = unsafe { mem::zeroed() };
|
||||
let mut msg = unsafe { mem::zeroed() };
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
@@ -439,14 +495,6 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EventLoop {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DestroyWindow(self.window_target.thread_msg_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveEventLoop {
|
||||
#[inline(always)]
|
||||
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
|
||||
@@ -465,7 +513,7 @@ impl ActiveEventLoop {
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy { target_window: self.thread_msg_target };
|
||||
RootEventLoopProxy::new(Arc::new(event_loop_proxy))
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
@@ -518,8 +566,8 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
self.runner_shared.set_exit_code(0)
|
||||
}
|
||||
|
||||
fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
|
||||
CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
|
||||
fn owned_display_handle(&self) -> RootOwnedDisplayHandle {
|
||||
RootOwnedDisplayHandle { platform: OwnedDisplayHandle }
|
||||
}
|
||||
|
||||
fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
@@ -527,6 +575,7 @@ impl RootActiveEventLoop for ActiveEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new());
|
||||
@@ -534,47 +583,19 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub(crate) struct OwnedDisplayHandle;
|
||||
|
||||
impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new());
|
||||
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
||||
impl OwnedDisplayHandle {
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
Ok(rwh_06::WindowsDisplayHandle::new().into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the main thread ID.
|
||||
fn main_thread_id() -> u32 {
|
||||
main_thread_id_via_snapshot().unwrap_or_else(main_thread_id_via_crt)
|
||||
}
|
||||
|
||||
/// Get the main thread ID via the snapshot feature.
|
||||
fn main_thread_id_via_snapshot() -> Option<u32> {
|
||||
// Get the current process ID.
|
||||
let process_id = unsafe { GetCurrentProcessId() };
|
||||
|
||||
// Take a snapshot of the process.
|
||||
let snapshot = match ToolhelpSnapshot::new(process_id) {
|
||||
Ok(snapshot) => snapshot,
|
||||
Err(err) => {
|
||||
tracing::error!("failed to take snapshot of process: {err}");
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
// Filter to threads owned by this process.
|
||||
let threads = snapshot.filter(|ti| ti.process_id == process_id);
|
||||
|
||||
// Get the time that the thread was created.
|
||||
let threadtimes = threads
|
||||
.filter_map(|ti| ti.thread_time().map(move |time| (ti, time)))
|
||||
.filter(|(_, time)| *time != 0);
|
||||
|
||||
// Identify the thread with the earliest time, since that must be the thread that called main().
|
||||
threadtimes.min_by_key(|(_, time)| *time).map(|(ti, _)| ti.thread_id)
|
||||
}
|
||||
|
||||
/// Returns the id of the main thread.
|
||||
///
|
||||
/// Windows has no real API to check if the current executing thread is the "main thread", unlike
|
||||
@@ -593,11 +614,7 @@ fn main_thread_id_via_snapshot() -> Option<u32> {
|
||||
///
|
||||
/// Full details of CRT initialization can be found here:
|
||||
/// <https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160>
|
||||
///
|
||||
/// notgull addendum: The above comment is a lie, we can get the total list of threads in the
|
||||
/// process and figure out which thread came first. We try to use that strategy first, and use this
|
||||
/// strategy as a fallback.
|
||||
fn main_thread_id_via_crt() -> u32 {
|
||||
fn main_thread_id() -> u32 {
|
||||
static mut MAIN_THREAD_ID: u32 = 0;
|
||||
|
||||
/// Function pointer used in CRT initialization section to set the above static field's value.
|
||||
@@ -620,110 +637,6 @@ fn main_thread_id_via_crt() -> u32 {
|
||||
unsafe { MAIN_THREAD_ID }
|
||||
}
|
||||
|
||||
/// A screenshot from the toolhelp tool.
|
||||
struct ToolhelpSnapshot {
|
||||
/// The handle to the snapshot.
|
||||
handle: OwnedHandle,
|
||||
|
||||
/// Are we returning the first thread entry?
|
||||
first_entry: bool,
|
||||
}
|
||||
|
||||
impl ToolhelpSnapshot {
|
||||
/// Take a screenshot of the provided process.
|
||||
fn new(process_id: u32) -> Result<Self, EventLoopError> {
|
||||
// Take a snapshot.
|
||||
let handle =
|
||||
unsafe { toolhelp::CreateToolhelp32Snapshot(toolhelp::TH32CS_SNAPTHREAD, process_id) };
|
||||
|
||||
if handle == 0 {
|
||||
return Err(EventLoopError::Os(os_error!("failed to get toolhelp snapshot")));
|
||||
}
|
||||
|
||||
Ok(Self { handle: unsafe { OwnedHandle::from_raw_handle(handle as _) }, first_entry: true })
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ToolhelpSnapshot {
|
||||
type Item = ThreadEntry;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut slot = mem::MaybeUninit::uninit();
|
||||
|
||||
// Write the size to the slot.
|
||||
unsafe {
|
||||
let slot: *mut toolhelp::THREADENTRY32 = slot.as_mut_ptr();
|
||||
let size = ptr::addr_of_mut!((*slot).dwSize);
|
||||
size.write(mem::size_of::<toolhelp::THREADENTRY32>() as _);
|
||||
}
|
||||
|
||||
let result = if self.first_entry {
|
||||
self.first_entry = false;
|
||||
unsafe { toolhelp::Thread32First(self.handle.as_raw_handle() as _, slot.as_mut_ptr()) }
|
||||
} else {
|
||||
unsafe { toolhelp::Thread32Next(self.handle.as_raw_handle() as _, slot.as_mut_ptr()) }
|
||||
};
|
||||
|
||||
if result != 0 {
|
||||
let thread_entry = unsafe { slot.assume_init() };
|
||||
Some(ThreadEntry {
|
||||
thread_id: thread_entry.th32ThreadID,
|
||||
process_id: thread_entry.th32OwnerProcessID,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ThreadEntry {
|
||||
/// The thread ID.
|
||||
thread_id: u32,
|
||||
|
||||
/// The owner process ID.
|
||||
process_id: u32,
|
||||
}
|
||||
|
||||
impl ThreadEntry {
|
||||
/// Get the time this thread was created.
|
||||
fn thread_time(self) -> Option<u64> {
|
||||
// Open a thread id.
|
||||
let thread_handle = unsafe {
|
||||
let handle = OpenThread(THREAD_QUERY_INFORMATION, 1, self.thread_id);
|
||||
|
||||
if handle == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
OwnedHandle::from_raw_handle(handle as _)
|
||||
};
|
||||
|
||||
// Get the time this thread was opened.
|
||||
let file_time = unsafe {
|
||||
let mut file_time = [mem::MaybeUninit::uninit(); 4];
|
||||
let result = GetThreadTimes(
|
||||
thread_handle.as_raw_handle() as _,
|
||||
file_time[0].as_mut_ptr(),
|
||||
file_time[1].as_mut_ptr(),
|
||||
file_time[2].as_mut_ptr(),
|
||||
file_time[3].as_mut_ptr(),
|
||||
);
|
||||
|
||||
if result == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
file_time[0].assume_init()
|
||||
};
|
||||
|
||||
Some(
|
||||
((file_time.dwHighDateTime as u64) << 32)
|
||||
| ((file_time.dwLowDateTime as u64) & 0xffffffff),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum `Option<Duration>`, taking into account that `None`
|
||||
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
||||
/// `Option::min`)
|
||||
@@ -755,139 +668,10 @@ fn dur2timeout(dur: Duration) -> u32 {
|
||||
.unwrap_or(INFINITE)
|
||||
}
|
||||
|
||||
/// Set upper limit for waiting time to avoid overflows.
|
||||
/// I chose 50 days as a limit because it is used in dur2timeout.
|
||||
const FIFTY_DAYS: Duration = Duration::from_secs(50_u64 * 24 * 60 * 60);
|
||||
/// Waitable timers use 100 ns intervals to indicate due time.
|
||||
/// <https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer#parameters>
|
||||
/// And there is no point waiting using other ways for such small timings
|
||||
/// because they are even less precise (can overshoot by few ms).
|
||||
const MIN_WAIT: Duration = Duration::from_nanos(100);
|
||||
|
||||
fn create_high_resolution_timer() -> Option<OwnedHandle> {
|
||||
unsafe {
|
||||
let handle: HANDLE = CreateWaitableTimerExW(
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
|
||||
TIMER_ALL_ACCESS,
|
||||
);
|
||||
// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is supported only after
|
||||
// Win10 1803 but it is already default option for rustc
|
||||
// (std uses it to implement `std::thread::sleep`).
|
||||
if handle == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(OwnedHandle::from_raw_handle(handle as *mut c_void))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This function should not return error if parameters are valid
|
||||
/// but there is no guarantee about that at MSDN docs
|
||||
/// so we return result of GetLastError if fail.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// timer must be a valid timer handle created by [create_high_resolution_timer].
|
||||
/// timeout divided by 100 nanoseconds must be more than 0 and less than i64::MAX.
|
||||
unsafe fn set_high_resolution_timer(timer: RawHandle, timeout: Duration) -> Result<(), u32> {
|
||||
const INTERVAL_NS: u32 = MIN_WAIT.subsec_nanos();
|
||||
const INTERVALS_IN_SEC: u64 = (Duration::from_secs(1).as_nanos() / INTERVAL_NS as u128) as u64;
|
||||
let intervals_to_wait: u64 =
|
||||
timeout.as_secs() * INTERVALS_IN_SEC + u64::from(timeout.subsec_nanos() / INTERVAL_NS);
|
||||
debug_assert!(intervals_to_wait < i64::MAX as u64, "Must be called with smaller duration",);
|
||||
// Use negative time to indicate relative time.
|
||||
let due_time: i64 = -(intervals_to_wait as i64);
|
||||
unsafe {
|
||||
let set_result = SetWaitableTimer(timer as HANDLE, &due_time, 0, None, ptr::null(), FALSE);
|
||||
if set_result != FALSE {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(GetLastError())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation detail of [EventLoop::wait_for_messages].
|
||||
///
|
||||
/// Does actual system-level waiting and doesn't process any messages itself,
|
||||
/// including winits internal notifications about waiting and new messages arrival.
|
||||
fn wait_for_messages_impl(
|
||||
high_resolution_timer: &mut Option<OwnedHandle>,
|
||||
control_flow: ControlFlow,
|
||||
timeout: Option<Duration>,
|
||||
) {
|
||||
let timeout = {
|
||||
let control_flow_timeout = match control_flow {
|
||||
ControlFlow::Wait => None,
|
||||
ControlFlow::Poll => Some(Duration::ZERO),
|
||||
ControlFlow::WaitUntil(wait_deadline) => {
|
||||
let start = Instant::now();
|
||||
Some(wait_deadline.saturating_duration_since(start))
|
||||
},
|
||||
};
|
||||
let timeout = min_timeout(timeout, control_flow_timeout);
|
||||
if timeout == Some(Duration::ZERO) {
|
||||
// Do not wait if we don't have time.
|
||||
return;
|
||||
}
|
||||
// Now we decided to wait so need to do some clamping
|
||||
// to avoid problems with overflow and calling WinAPI with invalid parameters.
|
||||
timeout
|
||||
.map(|t| t.min(FIFTY_DAYS))
|
||||
// If timeout is less than minimally supported by Windows,
|
||||
// increase it to that minimum. Who want less than microsecond delays anyway?
|
||||
.map(|t| t.max(MIN_WAIT))
|
||||
};
|
||||
|
||||
if timeout.is_some() && high_resolution_timer.is_none() {
|
||||
*high_resolution_timer = create_high_resolution_timer();
|
||||
}
|
||||
|
||||
let high_resolution_timer: Option<RawHandle> =
|
||||
high_resolution_timer.as_ref().map(OwnedHandle::as_raw_handle);
|
||||
|
||||
let use_timer: bool;
|
||||
if let (Some(handle), Some(timeout)) = (high_resolution_timer, timeout) {
|
||||
let res = unsafe {
|
||||
// Safety: handle can be Some only if we succeeded in creating high resolution
|
||||
// timer. We properly clamped timeout so it can be used as argument
|
||||
// to timer.
|
||||
set_high_resolution_timer(handle, timeout)
|
||||
};
|
||||
if let Err(error_code) = res {
|
||||
// We successfully got timer but failed to set it?
|
||||
// Should be some bug in our code.
|
||||
tracing::trace!("Failed to set high resolution timer: last error {}", error_code);
|
||||
use_timer = false;
|
||||
} else {
|
||||
use_timer = true;
|
||||
}
|
||||
} else {
|
||||
use_timer = false;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Either:
|
||||
// 1. User wants to wait indefinely if timeout is not set.
|
||||
// 2. We failed to get and set high resolution timer and we need something instead of it.
|
||||
let wait_duration_ms = timeout.map(dur2timeout).unwrap_or(INFINITE);
|
||||
|
||||
let (num_handles, raw_handles) =
|
||||
if use_timer { (1, [high_resolution_timer.unwrap()]) } else { (0, [ptr::null_mut()]) };
|
||||
|
||||
let result = MsgWaitForMultipleObjectsEx(
|
||||
num_handles,
|
||||
raw_handles.as_ptr() as *const _,
|
||||
wait_duration_ms,
|
||||
QS_ALLEVENTS,
|
||||
MWMO_INPUTAVAILABLE,
|
||||
);
|
||||
if result == WAIT_FAILED {
|
||||
// Well, nothing smart to do in such case.
|
||||
// Treat it as spurious wake up.
|
||||
tracing::warn!("Failed to MsgWaitForMultipleObjectsEx: error code {}", GetLastError(),);
|
||||
impl Drop for EventLoop {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DestroyWindow(self.window_target.thread_msg_target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -942,14 +726,15 @@ impl EventLoopThreadExecutor {
|
||||
|
||||
type ThreadExecFn = Box<Box<dyn FnMut()>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
target_window: HWND,
|
||||
}
|
||||
|
||||
unsafe impl Send for EventLoopProxy {}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
impl EventLoopProxy {
|
||||
pub fn wake_up(&self) {
|
||||
unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) };
|
||||
}
|
||||
}
|
||||
@@ -1757,7 +1542,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerEntered {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position,
|
||||
kind: PointerKind::Mouse,
|
||||
},
|
||||
@@ -1783,7 +1567,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerLeft {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Mouse,
|
||||
},
|
||||
@@ -1805,12 +1588,7 @@ unsafe fn public_window_callback_inner(
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerMoved {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
position,
|
||||
source: PointerSource::Mouse,
|
||||
},
|
||||
event: PointerMoved { device_id: None, position, source: PointerSource::Mouse },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1828,7 +1606,7 @@ unsafe fn public_window_callback_inner(
|
||||
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerLeft { device_id: None, primary: true, position: None, kind: Mouse },
|
||||
event: PointerLeft { device_id: None, position: None, kind: Mouse },
|
||||
});
|
||||
|
||||
result = ProcResult::Value(0);
|
||||
@@ -1905,7 +1683,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: Left.into(),
|
||||
@@ -1931,7 +1708,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Released,
|
||||
position,
|
||||
button: Left.into(),
|
||||
@@ -1957,7 +1733,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: Right.into(),
|
||||
@@ -1983,7 +1758,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Released,
|
||||
position,
|
||||
button: Right.into(),
|
||||
@@ -2009,7 +1783,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: Middle.into(),
|
||||
@@ -2035,7 +1808,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Released,
|
||||
position,
|
||||
button: Middle.into(),
|
||||
@@ -2062,7 +1834,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: match xbutton {
|
||||
@@ -2094,7 +1865,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id: WindowId::from_raw(window as usize),
|
||||
event: PointerButton {
|
||||
device_id: None,
|
||||
primary: true,
|
||||
state: Released,
|
||||
position,
|
||||
button: match xbutton {
|
||||
@@ -2148,15 +1918,16 @@ unsafe fn public_window_callback_inner(
|
||||
let position = PhysicalPosition::new(x, y);
|
||||
|
||||
let window_id = WindowId::from_raw(window as usize);
|
||||
let finger_id = FingerId::from_raw(input.dwID as usize);
|
||||
let primary = util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY);
|
||||
let finger_id = RootFingerId(FingerId {
|
||||
id: input.dwID,
|
||||
primary: util::has_flag(input.dwFlags, TOUCHEVENTF_PRIMARY),
|
||||
});
|
||||
|
||||
if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) {
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
@@ -2165,7 +1936,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: Touch { finger_id, force: None },
|
||||
@@ -2176,7 +1946,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: Released,
|
||||
position,
|
||||
button: Touch { finger_id, force: None },
|
||||
@@ -2186,7 +1955,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: PointerKind::Touch(finger_id),
|
||||
},
|
||||
@@ -2196,7 +1964,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
source: PointerSource::Touch { finger_id, force: None },
|
||||
},
|
||||
@@ -2319,15 +2086,16 @@ unsafe fn public_window_callback_inner(
|
||||
let position = PhysicalPosition::new(x, y);
|
||||
|
||||
let window_id = WindowId::from_raw(window as usize);
|
||||
let finger_id = FingerId::from_raw(pointer_info.pointerId as usize);
|
||||
let primary = util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_PRIMARY);
|
||||
let finger_id = RootFingerId(FingerId {
|
||||
id: pointer_info.pointerId,
|
||||
primary: util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_PRIMARY),
|
||||
});
|
||||
|
||||
if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) {
|
||||
userdata.send_event(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::PointerEntered {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
kind: if let PT_TOUCH = pointer_info.pointerType {
|
||||
PointerKind::Touch(finger_id)
|
||||
@@ -2340,7 +2108,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: Pressed,
|
||||
position,
|
||||
button: if let PT_TOUCH = pointer_info.pointerType {
|
||||
@@ -2355,7 +2122,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerButton {
|
||||
device_id: None,
|
||||
primary,
|
||||
state: Released,
|
||||
position,
|
||||
button: if let PT_TOUCH = pointer_info.pointerType {
|
||||
@@ -2369,7 +2135,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerLeft {
|
||||
device_id: None,
|
||||
primary,
|
||||
position: Some(position),
|
||||
kind: if let PT_TOUCH = pointer_info.pointerType {
|
||||
PointerKind::Touch(finger_id)
|
||||
@@ -2383,7 +2148,6 @@ unsafe fn public_window_callback_inner(
|
||||
window_id,
|
||||
event: WindowEvent::PointerMoved {
|
||||
device_id: None,
|
||||
primary,
|
||||
position,
|
||||
source: if let PT_TOUCH = pointer_info.pointerType {
|
||||
PointerSource::Touch { finger_id, force }
|
||||
|
||||
@@ -97,7 +97,7 @@ impl KeyEventBuilder {
|
||||
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
||||
},
|
||||
WM_KILLFOCUS => {
|
||||
// synthesize keyup events
|
||||
// sythesize keyup events
|
||||
let kbd_state = get_kbd_state();
|
||||
let key_events = Self::synthesize_kbd_state(ElementState::Released, &kbd_state);
|
||||
MatchResult::MessagesToDispatch(self.pending.complete_multi(key_events))
|
||||
@@ -333,11 +333,11 @@ impl KeyEventBuilder {
|
||||
// We are synthesizing the press event for caps-lock first for the following reasons:
|
||||
// 1. If caps-lock is *not* held down but *is* active, then we have to synthesize all
|
||||
// printable keys, respecting the caps-lock state.
|
||||
// 2. If caps-lock is held down, we could choose to synthesize its keypress after every
|
||||
// other key, in which case all other keys *must* be sythesized as if the caps-lock state
|
||||
// was be the opposite of what it currently is.
|
||||
// 2. If caps-lock is held down, we could choose to sythesize its keypress after every other
|
||||
// key, in which case all other keys *must* be sythesized as if the caps-lock state was
|
||||
// be the opposite of what it currently is.
|
||||
// --
|
||||
// For the sake of simplicity we are choosing to always synthesize
|
||||
// For the sake of simplicity we are choosing to always sythesize
|
||||
// caps-lock first, and always use the current caps-lock state
|
||||
// to determine the produced text
|
||||
if is_key_pressed!(VK_CAPITAL) {
|
||||
|
||||
@@ -2,7 +2,9 @@ use smol_str::SmolStr;
|
||||
use windows_sys::Win32::Foundation::HWND;
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX};
|
||||
|
||||
pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
|
||||
pub(crate) use self::event_loop::{
|
||||
EventLoop, EventLoopProxy, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub use self::icon::WinIcon as PlatformIcon;
|
||||
pub(crate) use self::icon::{SelectedCursor, WinCursor as PlatformCustomCursor, WinIcon};
|
||||
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
@@ -57,6 +59,25 @@ impl Default for PlatformSpecificWindowAttributes {
|
||||
unsafe impl Send for PlatformSpecificWindowAttributes {}
|
||||
unsafe impl Sync for PlatformSpecificWindowAttributes {}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct FingerId {
|
||||
id: u32,
|
||||
primary: bool,
|
||||
}
|
||||
|
||||
impl FingerId {
|
||||
#[cfg(test)]
|
||||
pub const fn dummy() -> Self {
|
||||
FingerId { id: 0, primary: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl FingerId {
|
||||
pub fn is_primary(self) -> bool {
|
||||
self.primary
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_device_id(id: u32) -> DeviceId {
|
||||
DeviceId::from_raw(id as i64)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
};
|
||||
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::icon::Icon;
|
||||
use crate::monitor::MonitorHandle as CoreMonitorHandle;
|
||||
@@ -106,6 +106,7 @@ impl Window {
|
||||
self.window
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub unsafe fn rwh_06_no_thread_check(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
||||
@@ -118,6 +119,7 @@ impl Window {
|
||||
Ok(rwh_06::RawWindowHandle::Win32(window_handle))
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
||||
// TODO: Write a test once integration framework is ready to ensure that it holds.
|
||||
// If we aren't in the GUI thread, we can't return the window.
|
||||
@@ -130,6 +132,7 @@ impl Window {
|
||||
unsafe { self.rwh_06_no_thread_check() }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
&self,
|
||||
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
||||
@@ -346,6 +349,7 @@ impl Drop for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for Window {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_display_handle_rwh_06()?;
|
||||
@@ -353,6 +357,7 @@ impl rwh_06::HasDisplayHandle for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for Window {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
let raw = self.raw_window_handle_rwh_06()?;
|
||||
@@ -416,15 +421,15 @@ impl CoreWindow for Window {
|
||||
)
|
||||
}
|
||||
|
||||
fn surface_position(&self) -> PhysicalPosition<i32> {
|
||||
let mut rect: RECT = unsafe { mem::zeroed() };
|
||||
if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() {
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
||||
let mut position: POINT = unsafe { mem::zeroed() };
|
||||
if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() {
|
||||
panic!(
|
||||
"Unexpected GetClientRect failure: please report this error to \
|
||||
"Unexpected ClientToScreen failure: please report this error to \
|
||||
rust-windowing/winit"
|
||||
)
|
||||
}
|
||||
PhysicalPosition::new(rect.left, rect.top)
|
||||
Ok(PhysicalPosition::new(position.x, position.y))
|
||||
}
|
||||
|
||||
fn set_outer_position(&self, position: Position) {
|
||||
@@ -494,10 +499,6 @@ impl CoreWindow for Window {
|
||||
None
|
||||
}
|
||||
|
||||
fn safe_area(&self) -> PhysicalInsets<u32> {
|
||||
PhysicalInsets::new(0, 0, 0, 0)
|
||||
}
|
||||
|
||||
fn set_min_surface_size(&self, size: Option<Size>) {
|
||||
self.window_state_lock().min_size = size;
|
||||
// Make windows re-check the window size bounds.
|
||||
@@ -1053,10 +1054,12 @@ impl CoreWindow for Window {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
||||
self
|
||||
}
|
||||
@@ -1285,6 +1288,7 @@ unsafe fn init(
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
let parent = match attributes.parent_window.as_ref().map(|handle| handle.0) {
|
||||
Some(rwh_06::RawWindowHandle::Win32(handle)) => {
|
||||
window_flags.set(WindowFlags::CHILD, true);
|
||||
@@ -1297,6 +1301,9 @@ unsafe fn init(
|
||||
None => fallback_parent(),
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "rwh_06"))]
|
||||
let parent = fallback_parent();
|
||||
|
||||
let menu = attributes.platform_specific.menu;
|
||||
let fullscreen = attributes.fullscreen.clone();
|
||||
let maximized = attributes.maximized;
|
||||
|
||||
147
src/window.rs
147
src/window.rs
@@ -7,7 +7,7 @@ pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::cursor::{BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE};
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::RequestError;
|
||||
pub use crate::icon::{BadIcon, Icon};
|
||||
use crate::monitor::{MonitorHandle, VideoModeHandle};
|
||||
@@ -67,6 +67,7 @@ pub struct WindowAttributes {
|
||||
pub window_level: WindowLevel,
|
||||
pub active: bool,
|
||||
pub cursor: Cursor,
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub(crate) parent_window: Option<SendSyncRawWindowHandle>,
|
||||
pub fullscreen: Option<Fullscreen>,
|
||||
// Platform-specific configuration.
|
||||
@@ -97,6 +98,7 @@ impl Default for WindowAttributes {
|
||||
preferred_theme: None,
|
||||
content_protected: false,
|
||||
cursor: Cursor::default(),
|
||||
#[cfg(feature = "rwh_06")]
|
||||
parent_window: None,
|
||||
active: true,
|
||||
platform_specific: Default::default(),
|
||||
@@ -111,13 +113,17 @@ impl Default for WindowAttributes {
|
||||
/// The user has to account for that when using [`WindowAttributes::with_parent_window()`],
|
||||
/// which is `unsafe`.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle);
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
unsafe impl Send for SendSyncRawWindowHandle {}
|
||||
#[cfg(feature = "rwh_06")]
|
||||
unsafe impl Sync for SendSyncRawWindowHandle {}
|
||||
|
||||
impl WindowAttributes {
|
||||
/// Get the parent window stored on the attributes.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> {
|
||||
self.parent_window.as_ref().map(|handle| &handle.0)
|
||||
}
|
||||
@@ -403,6 +409,7 @@ impl WindowAttributes {
|
||||
/// <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
|
||||
/// - **X11**: A child window is confined to the client area of its parent window.
|
||||
/// - **Android / iOS / Wayland / Web:** Unsupported.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub unsafe fn with_parent_window(
|
||||
mut self,
|
||||
@@ -574,51 +581,41 @@ pub trait Window: AsAny + Send + Sync {
|
||||
// extension trait
|
||||
fn reset_dead_keys(&self);
|
||||
|
||||
/// The position of the top-left hand corner of the surface relative to the top-left hand corner
|
||||
/// of the window.
|
||||
/// Returns the position of the top-left hand corner of the window's client area relative to the
|
||||
/// top-left hand corner of the desktop.
|
||||
///
|
||||
/// This, combined with [`outer_position`], can be useful for calculating the position of the
|
||||
/// surface relative to the desktop.
|
||||
///
|
||||
/// This may also be useful for figuring out the size of the window's decorations (such as
|
||||
/// buttons, title, etc.), but may also not correspond to that (e.g. if the title bar is made
|
||||
/// transparent using [`with_titlebar_transparent`] on macOS, or your are drawing window
|
||||
/// decorations yourself).
|
||||
///
|
||||
/// This may be negative.
|
||||
///
|
||||
/// If the window does not have any decorations, and the surface is in the exact same position
|
||||
/// as the window itself, this simply returns `(0, 0)`.
|
||||
///
|
||||
/// [`outer_position`]: Self::outer_position
|
||||
#[cfg_attr(
|
||||
any(macos_platform, docsrs),
|
||||
doc = "[`with_titlebar_transparent`]: \
|
||||
crate::platform::macos::WindowAttributesExtMacOS::with_titlebar_transparent"
|
||||
)]
|
||||
#[cfg_attr(
|
||||
not(any(macos_platform, docsrs)),
|
||||
doc = "[`with_titlebar_transparent`]: #only-available-on-macos"
|
||||
)]
|
||||
fn surface_position(&self) -> PhysicalPosition<i32>;
|
||||
|
||||
/// The position of the top-left hand corner of the window relative to the top-left hand corner
|
||||
/// of the desktop.
|
||||
///
|
||||
/// Note that the top-left hand corner of the desktop is not necessarily the same as
|
||||
/// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner
|
||||
/// of the desktop is the top-left hand corner of the primary monitor of the desktop.
|
||||
///
|
||||
/// The coordinates can be negative if the top-left hand corner of the window is outside
|
||||
/// of the visible screen region, or on another monitor than the primary.
|
||||
/// The same conditions that apply to [`Window::outer_position`] apply to this method.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS:** Returns the top left coordinates of the window's [safe area] in the screen space
|
||||
/// coordinate system.
|
||||
/// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns
|
||||
/// the same value as [`Window::outer_position`]._
|
||||
/// - **Android / Wayland:** Always returns [`RequestError::NotSupported`].
|
||||
///
|
||||
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
|
||||
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError>;
|
||||
|
||||
/// Returns the position of the top-left hand corner of the window relative to the
|
||||
/// top-left hand corner of the desktop.
|
||||
///
|
||||
/// Note that the top-left hand corner of the desktop is not necessarily the same as
|
||||
/// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner
|
||||
/// of the desktop is the top-left hand corner of the monitor at the top-left of the desktop.
|
||||
///
|
||||
/// The coordinates can be negative if the top-left hand corner of the window is outside
|
||||
/// of the visible screen region.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS:** Returns the top left coordinates of the window in the screen space coordinate
|
||||
/// system.
|
||||
/// - **Web:** Returns the top-left coordinates relative to the viewport.
|
||||
/// - **Android / Wayland:** Always returns [`RequestError::NotSupported`].
|
||||
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError>;
|
||||
|
||||
/// Sets the position of the window on the desktop.
|
||||
/// Modifies the position of the window.
|
||||
///
|
||||
/// See [`Window::outer_position`] for more information about the coordinates.
|
||||
/// This automatically un-maximizes the window if it's maximized.
|
||||
@@ -648,21 +645,16 @@ pub trait Window: AsAny + Send + Sync {
|
||||
|
||||
/// Returns the size of the window's render-able surface.
|
||||
///
|
||||
/// This is the dimensions you should pass to things like Wgpu or Glutin when configuring the
|
||||
/// surface for drawing. See [`WindowEvent::SurfaceResized`] for listening to changes to this
|
||||
/// field.
|
||||
///
|
||||
/// Note that to ensure that your content is not obscured by things such as notches or the title
|
||||
/// bar, you will likely want to only draw important content inside a specific area of the
|
||||
/// surface, see [`safe_area()`] for details.
|
||||
/// This is the dimensions you should pass to things like Wgpu or Glutin when configuring.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS:** Returns the `PhysicalSize` of the window's [safe area] in screen space
|
||||
/// coordinates.
|
||||
/// - **Web:** Returns the size of the canvas element. Doesn't account for CSS [`transform`].
|
||||
///
|
||||
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
|
||||
/// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||
/// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized
|
||||
/// [`safe_area()`]: Window::safe_area
|
||||
fn surface_size(&self) -> PhysicalSize<u32>;
|
||||
|
||||
/// Request the new size for the surface.
|
||||
@@ -709,53 +701,11 @@ pub trait Window: AsAny + Send + Sync {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS:** Returns the [`PhysicalSize`] of the window in screen space coordinates.
|
||||
/// - **Web:** Returns the size of the canvas element. _Note: this returns the same value as
|
||||
/// [`Window::surface_size`]._
|
||||
fn outer_size(&self) -> PhysicalSize<u32>;
|
||||
|
||||
/// The inset area of the surface that is unobstructed.
|
||||
///
|
||||
/// On some devices, especially mobile devices, the screen is not a perfect rectangle, and may
|
||||
/// have rounded corners, notches, bezels, and so on. When drawing your content, you usually
|
||||
/// want to draw your background and other such unimportant content on the entire surface, while
|
||||
/// you will want to restrict important content such as text, interactable or visual indicators
|
||||
/// to the part of the screen that is actually visible; for this, you use the safe area.
|
||||
///
|
||||
/// The safe area is a rectangle that is defined relative to the origin at the top-left corner
|
||||
/// of the surface, and the size extending downwards to the right. The area will not extend
|
||||
/// beyond [the bounds of the surface][Window::surface_size].
|
||||
///
|
||||
/// Note that the safe area does not take occlusion from other windows into account; in a way,
|
||||
/// it is only a "hardware"-level occlusion.
|
||||
///
|
||||
/// If the entire content of the surface is visible, this returns `(0, 0, 0, 0)`.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **Android / Orbital / Wayland / Windows / X11:** Unimplemented, returns `(0, 0, 0, 0)`.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// Convert safe area insets to a size and a position.
|
||||
///
|
||||
/// ```
|
||||
/// use winit::dpi::{PhysicalPosition, PhysicalSize};
|
||||
///
|
||||
/// # let surface_size = dpi::PhysicalSize::new(0, 0);
|
||||
/// # #[cfg(requires_window)]
|
||||
/// let surface_size = window.surface_size();
|
||||
/// # let insets = dpi::PhysicalInsets::new(0, 0, 0, 0);
|
||||
/// # #[cfg(requires_window)]
|
||||
/// let insets = window.safe_area();
|
||||
///
|
||||
/// let origin = PhysicalPosition::new(insets.left, insets.top);
|
||||
/// let size = PhysicalSize::new(
|
||||
/// surface_size.width - insets.left - insets.right,
|
||||
/// surface_size.height - insets.top - insets.bottom,
|
||||
/// );
|
||||
/// ```
|
||||
fn safe_area(&self) -> PhysicalInsets<u32>;
|
||||
|
||||
/// Sets a minimum dimensions of the window's surface.
|
||||
///
|
||||
/// ```no_run
|
||||
@@ -1028,8 +978,8 @@ pub trait Window: AsAny + Send + Sync {
|
||||
fn set_window_icon(&self, window_icon: Option<Icon>);
|
||||
|
||||
/// Set the IME cursor editing area, where the `position` is the top left corner of that area
|
||||
/// in surface coordinates and `size` is the size of this area starting from the position. An
|
||||
/// example of such area could be a input field in the UI or line in the editor.
|
||||
/// and `size` is the size of this area starting from the position. An example of such area
|
||||
/// could be a input field in the UI or line in the editor.
|
||||
///
|
||||
/// The windowing system could place a candidate box close to that area, but try to not obscure
|
||||
/// the specified area, so the user input to it stays visible.
|
||||
@@ -1062,8 +1012,7 @@ pub trait Window: AsAny + Send + Sync {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **X11:** Area is not supported, only position. The bottom-right corner of the provided
|
||||
/// area is reported as the position.
|
||||
/// - **X11:** - area is not supported, only position.
|
||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||
///
|
||||
/// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0
|
||||
@@ -1086,8 +1035,8 @@ pub trait Window: AsAny + Send + Sync {
|
||||
///
|
||||
/// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are
|
||||
/// combined.
|
||||
/// - **iOS / Android:** This will show / hide the soft keyboard.
|
||||
/// - **Web / Orbital:** Unsupported.
|
||||
/// - **iOS:** This will show / hide the soft keyboard.
|
||||
/// - **Android / Web / Orbital:** Unsupported.
|
||||
/// - **X11**: Enabling IME will disable dead keys reporting during compose.
|
||||
///
|
||||
/// [`Ime`]: crate::event::WindowEvent::Ime
|
||||
@@ -1260,7 +1209,7 @@ pub trait Window: AsAny + Send + Sync {
|
||||
/// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`].
|
||||
fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError>;
|
||||
|
||||
/// Show [window menu] at a specified position in surface coordinates.
|
||||
/// Show [window menu] at a specified position .
|
||||
///
|
||||
/// This is the context menu that is normally shown when interacting with
|
||||
/// the title bar. This is useful when implementing custom decorations.
|
||||
@@ -1327,9 +1276,11 @@ pub trait Window: AsAny + Send + Sync {
|
||||
fn primary_monitor(&self) -> Option<MonitorHandle>;
|
||||
|
||||
/// Get the raw-window-handle v0.6 display handle.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle;
|
||||
|
||||
/// Get the raw-window-handle v0.6 window handle.
|
||||
#[cfg(feature = "rwh_06")]
|
||||
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle;
|
||||
}
|
||||
|
||||
@@ -1355,12 +1306,14 @@ impl std::hash::Hash for dyn Window + '_ {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasDisplayHandle for dyn Window + '_ {
|
||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||
self.rwh_06_display_handle().display_handle()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
impl rwh_06::HasWindowHandle for dyn Window + '_ {
|
||||
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
||||
self.rwh_06_window_handle().window_handle()
|
||||
|
||||
@@ -5,6 +5,3 @@ TME_LEAVE = "TME_LEAVE" # From windows_sys::Win32::UI::Input::Keyboa
|
||||
XF86_Calculater = "XF86_Calculater" # From xkbcommon_dl::keysyms::XF86_Calculater
|
||||
ptd = "ptd" # From windows_sys::Win32::System::Com::FORMATETC { ptd, ..}
|
||||
requestor = "requestor" # From x11_dl::xlib::XSelectionEvent { requestor ..}
|
||||
|
||||
[files]
|
||||
extend-exclude = ["*.drawio"]
|
||||
|
||||
Reference in New Issue
Block a user