├── .github └── workflows │ ├── Deploy2OM-README.ja.yml │ └── Deploy2OM-README.yml ├── LICENSE.md ├── LICENSE.md.meta ├── README.ja.md ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── AppWindowUtility.cs ├── AppWindowUtility.cs.meta ├── IPlatformDependent.cs ├── IPlatformDependent.cs.meta ├── InitializeOnLoad.cs ├── InitializeOnLoad.cs.meta ├── WindowGrabber.cs ├── WindowGrabber.cs.meta ├── Windows.meta └── Windows │ ├── WinApi.cs │ ├── WinApi.cs.meta │ ├── Windows.cs │ └── Windows.cs.meta ├── SatorImaging.AppWindowUtility.asmdef ├── SatorImaging.AppWindowUtility.asmdef.meta ├── package.json └── package.json.meta /.github/workflows/Deploy2OM-README.ja.yml: -------------------------------------------------------------------------------- 1 | name: Deploy2OM-README.ja 2 | 3 | on: 4 | workflow_dispatch: # Allows you to run this workflow manually from the Actions tab 5 | push: 6 | branches: [ main ] 7 | paths: 8 | - 'README.ja.md' # limit trigger to the target-filepath. 9 | # It's not elegant to set same value in two options but 10 | # there is no way to retrieve this value in composite action. 11 | 12 | jobs: 13 | main: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: sator-imaging/Copy-to-Another-Repository@v1 17 | with: 18 | 19 | # required parameters 20 | target-filepath: 'README.ja.md' # file path to copy 21 | output-branch: 'master' # branch name to create pull request 22 | output-repo: 'SatorImaging/OpenManual' 23 | git-token: ${{ secrets.Deploy2OM }} 24 | -------------------------------------------------------------------------------- /.github/workflows/Deploy2OM-README.yml: -------------------------------------------------------------------------------- 1 | name: Deploy2OM-README 2 | 3 | on: 4 | workflow_dispatch: # Allows you to run this workflow manually from the Actions tab 5 | push: 6 | branches: [ main ] 7 | paths: 8 | - 'README.md' # limit trigger to the target-filepath. 9 | # It's not elegant to set same value in two options but 10 | # there is no way to retrieve this value in composite action. 11 | 12 | jobs: 13 | main: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: sator-imaging/Copy-to-Another-Repository@v1 17 | with: 18 | 19 | # required parameters 20 | target-filepath: 'README.md' # file path to copy 21 | output-branch: 'master' # branch name to create pull request 22 | output-repo: 'SatorImaging/OpenManual' 23 | git-token: ${{ secrets.Deploy2OM }} 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Sator Imaging 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 75cda0b705c535d4c92faa19625a4760 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.ja.md: -------------------------------------------------------------------------------- 1 | App Window Utility (日本語マニュアル) 2 | ====================================== 3 | 4 | このライブラリは、Unity で作成されたアプリのウインドウスタイルをカスタマイズする為のものです。 5 | このライブラリを使用することでアプリのウインドウを透過させたり、フレームを非表示にすること等が可能です。 6 | 7 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Opacity.gif?raw=true) 8 | 9 | 10 | 11 | # 制作・著作 12 | 13 | Copyright © 2022-2023 Sator Imaging, all rights reserved. 14 | 15 | 16 | 17 | # ライセンス 18 | 19 |

20 |

21 | 上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。 22 | 23 | ```text 24 | MIT License 25 | 26 | Copyright (c) 2022-2023 Sator Imaging 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in all 36 | copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 44 | SOFTWARE. 45 | ``` 46 | 47 |
48 |

49 | 50 | 51 | 52 | 53 | # 機能 54 | 55 | 以下の機能は Unity 2020.3 LTS と HDRP 10.3.2 を Windows 10 64-bit 上で実行して動作確認しています。 56 | 57 | 58 | #### 事前準備 59 | 60 | 以下のサンプルを動作させるには、`using SatorImaging.AppWindowUtility;` を追加して名前空間を参照しておく必要があります。 61 | 62 | 63 | 64 | 65 | # サンプル 66 | 67 | サンプルはコチラ。その他の機能については以下のセクションをご覧ください。 68 | 69 | ```csharp 70 | using UnityEngine; 71 | using SatorImaging.AppWindowUtility; 72 | 73 | public class MyTest : MonoBehaviour 74 | { 75 | void Start() 76 | { 77 | AppWindowUtility.Transparent = true; 78 | } 79 | } 80 | ``` 81 | 82 | 83 | 84 | ## 透過ウインドウ 85 | 86 | `bool AppWindowUtility.Transparent { get; set; }` 87 | 88 | アプリを透過ウインドウに設定します。ウインドウの後ろにある別のウインドウが透けて見えるようになります。 89 | 90 | 透明度は Unity のレンダリング結果に依存しているので、カメラの `Background` を **Solid Color** に設定してアルファをゼロにする必要があります。 91 | 92 | > 注: High-Definition Render Pipeline (HDRP) やその他の Scriptable Render Pipeline (SRP) ベースのレンダラーを使っている場合、Color Frame Buffer をデフォルトの RGB 10bit から RGB 16bit(8bit があればそちらでも可)に設定する必要があります。 93 | 94 | 95 | 96 | 97 | 98 | ## ウインドウの不透明度 99 | 100 | `AppWindowUtility.SetWindowOpacity(byte opacity)` 101 | 102 | ウインドウ全体の不透明度を設定します。透過ウインドウと組み合わせて使うこともできます。 103 | 104 | 105 | 106 | 107 | 108 | ## `WindowGrabber` コンポーネント 109 | 110 | 透過ウインドウが有効になっているとタイトルバーが消えてしまうので、ウインドウを移動することが出来なくなってしまいます。 111 | 112 | `WindowGrabber` を空の `GameObject` に追加することで、アプリのウインドウのどこかをドラッグすれば移動できるようになります。 113 | 114 | 115 | 116 | 117 | 118 | ※ `WindowGrabber` が有効な間も uGUI を使うことが出来ます。 119 | 120 | 121 | 122 | 123 | ## フルスクリーンモード 124 | 125 | `bool AppWindowUtility.FullScreen { get; set; }` 126 | 127 | ウインドウをフルスクリーンに設定します。 128 | 129 | > 注: Unity 標準の `UnityEngine.Screen.SetResolution(width, height, isFullScreen)` ではなくコチラを使った方が App Window Utility との相性が良いです。 130 | 131 | 132 | 133 | 134 | ## 常に手前に表示(Always on Top) 135 | 136 | `bool AppWindowUtility.AlwaysOnTop { get; set; }` 137 | 138 | ウインドウがフォーカスを失っても、常に最前面に表示されるようになります。 139 | 140 | 141 | 142 | 143 | 144 | ## クリックスルーモード 145 | 146 | `bool AppWindowUtility.ClickThrough { get; set; }` 147 | 148 | アプリケーションがマウスのクリックを受け付けなくなります。 149 | 150 | > 注: マウスを使わずにこの機能をオフにする方法を実装する必要があります。実装しなかった場合、二度とアプリに触れなくなります。 151 | 152 | 153 | 154 | 155 | 156 | ## ウインドウフレームの表示 157 | 158 | `bool AppWindowUtility.FrameVisibility { get; set; }` 159 | 160 | ウインドウのフレームを表示・非表示に設定します。 161 | 162 | ※ 透過ウインドウに設定すると、同時にフレームの表示もオフに設定されます。 163 | 164 | 165 | 166 | ## カラーキーイングウインドウ 167 | 168 | `AppWindowUtility.SetKeyingColor(byte red, byte green, byte blue)` 169 | 170 | アプリのウインドウ全体に対して、特定の色を透過させる機能を有効にします。 171 | かなり特殊なので、`AppWindowUtility.Transparent` を使った方が良いです。 172 | 173 | 174 | 175 | ## 加算合成モード 176 | 177 | Windows の場合、`AppWindowUtility.SetKeyingColor(0, 0, 0)` を設定した後に `AppWindowUtility.Transparent = true` を設定すると、透過ウインドウが加算合成モードになります。 178 | 179 | ※注※ これは Windows のバグの可能性があります。 180 | 181 | 182 | 183 | 184 | 185 | # 注意点 186 | 187 | 188 | ## プレイヤー設定(Player Settings) 189 | 190 | 正しく動作させるためには、`Use DXGI Flip Model Swapchain for D3D11` をオフに設定する必要があります。 191 | 192 | ※ App Window Utility が期待通りに動作しない場合、以下のプレイヤー設定を参考にしてください。 193 | 194 | 195 | 196 | 197 | 198 | ## High-Definition Render Pipeline (HDRP) と同時に使用する場合 199 | 200 | `Color Buffer Format` は必ず RGB 16bit(またはホスト OS が対応しているフォーマット)に設定する必要があります。 201 | Scriptable Render Pipeline (SRP) ベースのレンダラーは同様の設定が必要になります。 202 | 203 | 204 | 205 | 206 | 207 | ## 透過ウインドウとウィンドウフレームの表示 208 | 209 | `Transparent = true` を設定した後に `FrameVisibility = true` を設定すると、アプリの背景が非表示になった状態でウインドウフレームが表示されます。結果としてウインドウ全体がフレームの色で塗りつぶされることになります。 210 | 211 | 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | App Window Utility 2 | ================== 3 | 4 | This utility is for Unity to configure application window style. 5 | With this utility, you can make your application window transparent, frameless and more. 6 | 7 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Opacity.gif?raw=true) 8 | 9 | 10 | 11 | 12 | Copyright 13 | ========= 14 | 15 | Copyright © 2022-2023 Sator Imaging, all rights reserved. 16 | 17 | 18 | 19 | License 20 | ======= 21 | 22 |

23 |

24 | The above copyright notice and this permission notice shall be included in all 25 | copies or substantial portions of the Software. 26 | 27 | ```text 28 | MIT License 29 | 30 | Copyright (c) 2022-2023 Sator Imaging 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy 33 | of this software and associated documentation files (the "Software"), to deal 34 | in the Software without restriction, including without limitation the rights 35 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 36 | copies of the Software, and to permit persons to whom the Software is 37 | furnished to do so, subject to the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be included in all 40 | copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 43 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 44 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 45 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 46 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 47 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 48 | SOFTWARE. 49 | ``` 50 | 51 |
52 |

53 | 54 | 55 | 56 | 57 | Features 58 | ======== 59 | 60 | Features are tested with Unity 2020.3 LTS and HDRP 10.3.2 on Windows 10 64-bit. 61 | 62 | 63 | #### Prerequisites 64 | 65 | `using SatorImaging.AppWindowUtility;` is required to make the following examples work. 66 | 67 | 68 | 69 | Sample 70 | ====== 71 | 72 | Here is a sample code. See the following sections for more options. 73 | 74 | 75 | ```csharp 76 | using UnityEngine; 77 | using SatorImaging.AppWindowUtility; 78 | 79 | public class MyTest : MonoBehaviour 80 | { 81 | void Start() 82 | { 83 | AppWindowUtility.Transparent = true; 84 | } 85 | } 86 | ``` 87 | 88 | 89 | 90 | ## Transparent Window 91 | 92 | `bool AppWindowUtility.Transparent { get; set; }` 93 | 94 | This will make application window transparent. In other words, you can see behind through application window. 95 | 96 | Transparency is based on Unity's rendering result. So that you need to set camera background to **Solid Color** with alpha is set to zero. 97 | 98 | > NOTE: If you use High-Definition Render Pipeline (HDRP) or something based on Scriptable Render Pipeline (SRP), Color Frame Buffer setting needs to be set to RGB 16bit (or 8bit if available). Unity's default is RGB 10bit that Operating System doesn't support. 99 | 100 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Transparent.gif?raw=true) 101 | 102 | 103 | 104 | ## Window Opacity 105 | 106 | `AppWindowUtility.SetWindowOpacity(byte opacity)` 107 | 108 | This will set overall window opacity. It works with see-thru window. 109 | 110 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Opacity.gif?raw=true) 111 | 112 | 113 | 114 | ## `WindowGrabber` Component 115 | 116 | With Transparent enabled, window has no title bar so that you need a way to move window. 117 | 118 | `WindowGrabber` adds an ability to move window by dragging any area of application window. 119 | To add this feature, create empty GameObject and attach `WindowGrabber` component. 120 | 121 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/MoveWindow_WindowGrabber.png?raw=true) 122 | 123 | > You can still use uGUI controls if WindowGrabber is used. 124 | 125 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/MoveWindow.gif?raw=true) 126 | 127 | 128 | 129 | ## Full Screen Mode 130 | 131 | `bool AppWindowUtility.FullScreen { get; set; }` 132 | 133 | This will make window full screen or not. 134 | 135 | > NOTE: Use this instead of Unity's built-in `UnityEngine.Screen.SetResolution(width, height, isFullScreen)` and `UnityEngine.Screen.fullScreen` to work better with App Window Utility. 136 | 137 | 138 | 139 | 140 | ## Always on Top 141 | 142 | `bool AppWindowUtility.AlwaysOnTop { get; set; }` 143 | 144 | This will make application window stay on top of other windows while another application has focus. 145 | 146 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/AlwaysOnTop.gif?raw=true) 147 | 148 | 149 | 150 | ## Click-Thru Mode 151 | 152 | `bool AppWindowUtility.ClickThrough { get; set; }` 153 | 154 | This make application window non-clickable. 155 | 156 | > NOTE: You must implement a way to disable this feature not using mouse click. If not implemented, you cannot touch your application anymore. 157 | 158 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/ClickThru_B.gif?raw=true) 159 | 160 | 161 | 162 | ## Window Frame Visibility 163 | 164 | `bool AppWindowUtility.FrameVisibility { get; set; }` 165 | 166 | This will set window frame visibile or invisible. 167 | 168 | > NOTE: When enable transparent window, window frame will be automatically hidden. 169 | 170 | 171 | 172 | ## Color-Keying Window 173 | 174 | `AppWindowUtility.SetKeyingColor(byte red, byte green, byte blue)` 175 | 176 | This will **Keying** specified color from application window. 177 | It's strongly recommended to use `AppWindowUtility.Transparent` instead of this. 178 | 179 | 180 | 181 | ## Additive Composition Mode 182 | 183 | On Windows, applying `AppWindowUtility.SetKeyingColor(0, 0, 0)` and then `AppWindowUtility.Transparent = true` will change window composition mode to "Additive". 184 | 185 | > NOTE: This behaviour could be a bug of Windows. 186 | 187 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/AdditiveComposition.gif?raw=true) 188 | 189 | 190 | 191 | Important Notes 192 | =============== 193 | 194 | 195 | ## Player Settings 196 | 197 | **Use DXGI Flip Model Swapchain for D3D11** must be turned off to work correctly. 198 | 199 | > If App Window Utility doesn't work as you expected, see Player Settings below for reference. 200 | 201 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Notes_PlayerSettings.png?raw=true) 202 | 203 | 204 | 205 | ## Using with High-Definition Render Pipeline (HDRP) 206 | 207 | **Color Buffer Format** must be RGB 16bit (or something supported on Host OS) to work correctly. 208 | Other renderer based on Scriptable Render Pipeline (SRP) needs setting like this too. 209 | 210 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Notes_HDRP.png?raw=true) 211 | 212 | 213 | 214 | ## Transparent and Frame Visibility 215 | 216 | If you apply `Transparent = true` and then `FrameVisibility = true`, it will remove background filling from application window. Result is below, as you can see, background is filled with window frame color. 217 | 218 | ![](https://github.com/sator-imaging/sator-imaging.github.io/blob/master/AppWindowUtility/images/Notes_TransparentThenShowFrame.gif?raw=true) 219 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cdd8ee2bf33993e488e1c424e31bb637 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad51b1d2ac33ed143b5f846b075be634 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/AppWindowUtility.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | 4 | namespace SatorImaging.AppWindowUtility 5 | { 6 | public static class AppWindowUtility 7 | { 8 | public static IPlatformDependent platform; 9 | 10 | 11 | public static bool AlwaysOnTopSupported { get => platform?.AlwaysOnTopSupported ?? false; } 12 | public static bool AlwaysOnTop 13 | { 14 | get => platform?.GetAlwaysOnTop() ?? false; 15 | set => platform?.SetAlwaysOnTop(value); 16 | } 17 | 18 | public static bool TransparentSupported { get => platform?.TransparentSupported ?? false; } 19 | public static bool Transparent 20 | { 21 | get => platform?.GetTransparent() ?? false; 22 | set => platform?.SetTransparent(value); 23 | } 24 | 25 | public static bool FrameVisiblitySupported { get => platform?.FrameVisibilitySupported ?? false; } 26 | public static bool FrameVisibility 27 | { 28 | get => platform?.GetFrameVisibility() ?? true; 29 | set => platform?.SetFrameVisibility(value); 30 | } 31 | 32 | public static bool ClickThroughSupported { get => platform?.ClickThroughSupported ?? false; } 33 | public static bool ClickThrough 34 | { 35 | get => platform?.GetClickThrough() ?? false; 36 | set => platform?.SetClickThrough(value); 37 | } 38 | 39 | public static bool AsWallpaperSupported { get => platform?.AsWallpaperSupported ?? false; } 40 | public static bool AsWallpaper 41 | { 42 | get => platform?.GetAsWallpaper() ?? false; 43 | set => platform?.SetAsWallpaper(value); 44 | } 45 | 46 | 47 | 48 | public static bool KeyingColorSupported { get => platform?.KeyingColorSupported ?? false; } 49 | public static void SetKeyingColor(byte red, byte green, byte blue) 50 | => platform?.SetKeyingColor(red, green, blue); 51 | 52 | public static bool WindowOpacitySupported { get => platform?.WindowOpacitySupported ?? false; } 53 | public static void SetWindowOpacity(byte opacity) 54 | => platform?.SetWindowOpacity(opacity); 55 | 56 | 57 | 58 | 59 | public static bool WindowPlacementSupported { get => platform?.WindowPlacementSupported ?? false; } 60 | public static void MoveWindowRelative(int pixelX, int pixelY) 61 | => platform?.MoveWindowRelative(pixelX, pixelY); 62 | 63 | 64 | 65 | // fullscreen 66 | private static int[] lastScreenSize = new int[] { 640, 480 }; 67 | private static bool isFullScreen = (Screen.width == Screen.currentResolution.width && Screen.height == Screen.currentResolution.height); 68 | 69 | public static bool FullScreen 70 | { 71 | get { return isFullScreen; } 72 | set 73 | { 74 | if (isFullScreen == value) return; 75 | 76 | if (value) 77 | { 78 | // unity turns window frame visible when returned from fullscreen. 79 | // so match the status BEFORE going to full screen. 80 | FrameVisibility = true; 81 | 82 | lastScreenSize = new int[] { Screen.width, Screen.height }; 83 | Screen.SetResolution(Screen.currentResolution.width, Screen.currentResolution.height, true);// FullScreenMode.FullScreenWindow); 84 | } 85 | else 86 | { 87 | Screen.SetResolution(lastScreenSize[0], lastScreenSize[1], false);// FullScreenMode.Windowed); 88 | } 89 | 90 | isFullScreen = value; 91 | 92 | // no way to control SetResolution update timing. it's done at next frame. 93 | // so FrameVisibility done BEFORE full screen disabled no matter when it invoked in setter. 94 | // to make it better, simply, reset transparent state. 95 | if (!isFullScreen) Transparent = false; 96 | 97 | }//set 98 | }// 99 | 100 | 101 | 102 | 103 | }//class 104 | }//namespace 105 | -------------------------------------------------------------------------------- /Runtime/AppWindowUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1f147022b54faec44aa2bf93bc5c5737 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/IPlatformDependent.cs: -------------------------------------------------------------------------------- 1 | namespace SatorImaging.AppWindowUtility 2 | { 3 | public interface IPlatformDependent 4 | { 5 | bool AlwaysOnTopSupported { get; } 6 | bool GetAlwaysOnTop(); 7 | void SetAlwaysOnTop(bool enable); 8 | 9 | bool TransparentSupported { get; } 10 | bool GetTransparent(); 11 | void SetTransparent(bool enable); 12 | 13 | bool FrameVisibilitySupported { get; } 14 | bool GetFrameVisibility(); 15 | void SetFrameVisibility(bool visible); 16 | 17 | bool ClickThroughSupported { get; } 18 | bool GetClickThrough(); 19 | void SetClickThrough(bool enable); 20 | 21 | bool AsWallpaperSupported { get; } 22 | bool GetAsWallpaper(); 23 | void SetAsWallpaper(bool enable); 24 | 25 | 26 | 27 | bool KeyingColorSupported { get; } 28 | void SetKeyingColor(byte red, byte green, byte blue); 29 | 30 | bool WindowOpacitySupported { get; } 31 | void SetWindowOpacity(byte opacity); 32 | 33 | 34 | bool WindowPlacementSupported { get; } 35 | void MoveWindowRelative(int pixelX, int pixelY); 36 | 37 | }// 38 | 39 | }//namespace 40 | -------------------------------------------------------------------------------- /Runtime/IPlatformDependent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c91b36bb61130ec4aa52b609135aa56e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/InitializeOnLoad.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | 4 | namespace SatorImaging.AppWindowUtility 5 | { 6 | static class InitializeOnLoad 7 | { 8 | 9 | #if UNITY_EDITOR 10 | //[UnityEditor.InitializeOnLoadMethod] 11 | #endif 12 | [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] 13 | static void Install() 14 | { 15 | 16 | #if UNITY_STANDALONE_WIN 17 | AppWindowUtility.platform = new Windows(); 18 | #endif 19 | 20 | } 21 | 22 | 23 | }//class 24 | }//namespace 25 | -------------------------------------------------------------------------------- /Runtime/InitializeOnLoad.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 127a7c2393583d743bd2bb10e100a3cf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/WindowGrabber.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | 5 | 6 | namespace SatorImaging.AppWindowUtility 7 | { 8 | public class WindowGrabber : MonoBehaviour 9 | { 10 | public enum MouseButton 11 | { 12 | Left = 0, 13 | Right = 1, 14 | Middle = 2, 15 | } 16 | public MouseButton mouseButton; 17 | public KeyCode modifierKey = KeyCode.None; 18 | public KeyCode[] temporarilyDisableIfKeyPressed; 19 | 20 | 21 | private bool isDragging = false; 22 | Vector2 targetPosition = Vector2.zero; 23 | 24 | 25 | void Update() 26 | { 27 | #if UNITY_EDITOR 28 | if(isDragging.Equals(isDragging)) return; // to avoid CS0162 warning 29 | #endif 30 | 31 | // do nothing if any uGUI is in use. 32 | if (EventSystem.current?.currentSelectedGameObject) return; 33 | 34 | 35 | // initialize dragging state. don't check modifier key. 36 | if (Input.GetMouseButtonUp((int)mouseButton)) isDragging = false; 37 | 38 | // key check. 39 | foreach (var k in temporarilyDisableIfKeyPressed) if (Input.GetKey(k)) return; 40 | if (modifierKey != KeyCode.None && !Input.GetKey(modifierKey)) return; 41 | 42 | 43 | 44 | if (Input.GetMouseButtonDown((int)mouseButton)) 45 | { 46 | targetPosition = Event.current.mousePosition; 47 | isDragging = true; 48 | } 49 | 50 | if (isDragging && Input.GetMouseButton((int)mouseButton)) 51 | { 52 | // do NOT use Event.current.delta. it's sampled in local window coordinate. 53 | // and moving window while mouse dragging changes coordinate sample by sample. 54 | // just remove the gap between current mouse position and drag starting position. 55 | AppWindowUtility.MoveWindowRelative( 56 | (int)(Event.current.mousePosition.x - targetPosition.x), 57 | (int)(Event.current.mousePosition.y - targetPosition.y) 58 | ); 59 | 60 | } 61 | 62 | }// 63 | 64 | 65 | }//class 66 | }//namespace 67 | -------------------------------------------------------------------------------- /Runtime/WindowGrabber.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1866eebb0b62a44da3196d0f2fb1b0c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Windows.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfd42f4c85ef7c248b021f4f37c70a4c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Windows/WinApi.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_STANDALONE_WIN 2 | 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using UnityEngine; 7 | 8 | 9 | 10 | namespace SatorImaging.AppWindowUtility 11 | { 12 | public static class WinApi 13 | { 14 | 15 | [StructLayout(LayoutKind.Sequential)] 16 | public struct DwmMargin 17 | { 18 | public int cxLeftWidth; 19 | public int cxRightWidth; 20 | public int cyTopHeight; 21 | public int cyBottomHeight; 22 | } 23 | 24 | [StructLayout(LayoutKind.Sequential)] 25 | public struct POINT 26 | { 27 | public int X; 28 | public int Y; 29 | } 30 | 31 | [StructLayout(LayoutKind.Sequential)] 32 | public struct RECT 33 | { 34 | public int left; 35 | public int top; 36 | public int right; 37 | public int bottom; 38 | } 39 | 40 | 41 | 42 | [DllImport("user32.dll")] 43 | [return: MarshalAs(UnmanagedType.Bool)] 44 | public static extern bool GetCursorPos(out POINT lpPoint); 45 | 46 | public static Vector2 GetWindowsMousePosition() 47 | { 48 | POINT pos; 49 | if (GetCursorPos(out pos)) return new Vector2(pos.X, pos.Y); 50 | return Vector2.zero; 51 | } 52 | 53 | 54 | 55 | [DllImport("user32.dll")] 56 | public static extern IntPtr GetActiveWindow(); 57 | [DllImport("user32.dll")] 58 | public static extern IntPtr GetDesktopWindow(); 59 | [DllImport("user32.dll")] 60 | public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); 61 | [DllImport("user32.dll")] 62 | public static extern uint SendMessageTimeout(IntPtr hWnd, uint Msg, uint wParam, uint lParam, uint fuFlags, uint uTimeout, out uint lpdwResult); 63 | [DllImport("user32.dll")] 64 | public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 65 | [DllImport("user32.dll")] 66 | public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 67 | [DllImport("user32.dll")] 68 | public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChild, string lpszClass, string lpszWindow); 69 | 70 | 71 | 72 | [DllImport("user32.dll")] 73 | public static extern IntPtr FindWindow(string className, string windowName); 74 | 75 | public static IntPtr CurrentWindowHandle = IntPtr.Zero; 76 | public static IntPtr GetUnityWindowHandle() 77 | { 78 | if (CurrentWindowHandle == IntPtr.Zero) 79 | { 80 | CurrentWindowHandle = FindWindow(null, Application.productName); 81 | } 82 | return CurrentWindowHandle; 83 | 84 | } 85 | 86 | 87 | 88 | [DllImport("user32.dll")] 89 | public static extern IntPtr GetForegroundWindow(); 90 | 91 | public static bool IsWindowActive() 92 | { 93 | return GetUnityWindowHandle() == GetForegroundWindow(); 94 | } 95 | 96 | 97 | 98 | [DllImport("user32.dll")] 99 | public static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong); /*x uint o int unchecked*/ 100 | [DllImport("user32.dll")] 101 | public static extern uint GetWindowLong(IntPtr hWnd, int nIndex); 102 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 103 | public static extern bool SetWindowText(IntPtr hwnd, String lpString); 104 | [DllImport("user32.dll", SetLastError = true)] 105 | public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); 106 | [DllImport("user32.dll")] 107 | public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect); 108 | [DllImport("user32.dll")] 109 | public static extern bool GetClientRect(IntPtr hWnd, out RECT rect); 110 | 111 | public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 112 | public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); 113 | public static readonly IntPtr HWND_TOP = new IntPtr(0); 114 | public static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 115 | 116 | 117 | 118 | [Flags()] 119 | public enum SetWindowPosFlags : uint 120 | { 121 | AsynchronousWindowPosition = 0x4000, 122 | DeferErase = 0x2000, 123 | DrawFrame = 0x0020, 124 | FrameChanged = 0x0020, 125 | HideWindow = 0x0080, 126 | DoNotActivate = 0x0010, 127 | DoNotCopyBits = 0x0100, 128 | IgnoreMove = 0x0002, 129 | DoNotChangeOwnerZOrder = 0x0200, 130 | DoNotRedraw = 0x0008, 131 | DoNotReposition = 0x0200, 132 | DoNotSendChangingEvent = 0x0400, 133 | IgnoreResize = 0x0001, 134 | IgnoreZOrder = 0x0004, 135 | ShowWindow = 0x0040, 136 | NoFlag = 0x0000, 137 | } 138 | 139 | 140 | 141 | 142 | 143 | 144 | [DllImport("Dwmapi.dll")] 145 | public static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref DwmMargin margins); 146 | public static void SetDwmTransparent(bool enable) 147 | { 148 | var margins = new DwmMargin() 149 | { 150 | cxLeftWidth = enable ? -1 : 0, 151 | }; 152 | DwmExtendFrameIntoClientArea(GetUnityWindowHandle(), ref margins); 153 | } 154 | 155 | 156 | 157 | 158 | 159 | public const int GWL_STYLE = -16; 160 | public const uint WS_POPUP = 0x80000000; 161 | public const uint WS_BORDER = 0x00800000; 162 | public const uint WS_VISIBLE = 0x10000000; 163 | public const uint WS_CAPTION = 0x00C00000; 164 | public const uint WS_THICKFRAME = 0x00040000; 165 | public const int GWL_EXSTYLE = -20; 166 | public const uint WS_EX_LAYERED = 0x00080000; 167 | public const uint WS_EX_TRANSPARENT = 0x00000020; 168 | public const uint WS_EX_DLGMODALFRAME = 0x00000001; 169 | public const uint WS_EX_WINDOWEDGE = 0x00000100; 170 | public const uint WS_EX_CLIENTEDGE = 0x00000200; 171 | public const uint WS_EX_STATICEDGE = 0x00020000; 172 | 173 | 174 | public const int LWA_COLORKEY = 0x00000001; 175 | public const int LWA_ALPHA = 0x00000002; 176 | 177 | 178 | 179 | 180 | 181 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 182 | private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 183 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 184 | private static extern int GetWindowTextLength(IntPtr hWnd); 185 | 186 | 187 | 188 | 189 | [DllImport("user32.dll", SetLastError = true)] 190 | public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags); 191 | [DllImport("user32.dll", SetLastError = true)] 192 | public static extern bool GetLayeredWindowAttributes(IntPtr hwnd, out uint crKey, out byte bAlpha, out uint dwFlags); 193 | 194 | 195 | 196 | 197 | 198 | 199 | }//class 200 | }//namespace 201 | #endif 202 | -------------------------------------------------------------------------------- /Runtime/Windows/WinApi.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8438e9a2634454429f47962402d6be3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Windows/Windows.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_STANDALONE_WIN 2 | 3 | using System; 4 | using UnityEngine; 5 | 6 | 7 | 8 | namespace SatorImaging.AppWindowUtility 9 | { 10 | public class Windows : IPlatformDependent 11 | { 12 | static IntPtr hWnd; 13 | 14 | static uint defaultWindowStyle; 15 | static uint defaultExWindowStyle; 16 | 17 | // unity's shader error color. 18 | static uint defaultKeyingColor = 0xFF00FF; 19 | static int borderWidth; 20 | static int titleBarHeight; 21 | 22 | 23 | private static bool isAlwaysOnTop = false; 24 | private static bool isTransparent = false; 25 | private static bool isFrameVisible = true; 26 | private static bool isClickThrough = false; 27 | private static bool isWallpaper = false; 28 | 29 | private static bool isInitialized = false; 30 | private static WinApi.RECT lastClientRect = new WinApi.RECT { left = 32, top = 64, right = 640, bottom = 480 }; 31 | 32 | 33 | 34 | // features supported 35 | public bool AlwaysOnTopSupported { get; } = true; 36 | public bool TransparentSupported { get; } = true; 37 | public bool FrameVisibilitySupported { get; } = true; 38 | public bool ClickThroughSupported { get; } = true; 39 | public bool AsWallpaperSupported { get; } = true; 40 | public bool KeyingColorSupported { get; } = true; 41 | public bool WindowOpacitySupported { get; } = true; 42 | public bool WindowPlacementSupported { get; } = true; 43 | 44 | 45 | 46 | public Windows() 47 | { 48 | if (isInitialized) return; 49 | 50 | hWnd = WinApi.GetUnityWindowHandle(); 51 | defaultWindowStyle = WinApi.GetWindowLong(WinApi.GetUnityWindowHandle(), WinApi.GWL_STYLE); 52 | defaultExWindowStyle = WinApi.GetWindowLong(WinApi.GetUnityWindowHandle(), WinApi.GWL_EXSTYLE); 53 | 54 | // initialize client rect. 55 | WinApi.GetClientRect(hWnd, out lastClientRect); 56 | 57 | // calculate title bar and frame size 58 | WinApi.RECT windowRect; 59 | WinApi.GetWindowRect(hWnd, out windowRect); 60 | WinApi.RECT clientRect; 61 | WinApi.GetClientRect(hWnd, out clientRect); 62 | borderWidth = (windowRect.right - windowRect.left) - clientRect.right; 63 | borderWidth = (int)(borderWidth * 0.5f); 64 | titleBarHeight = (windowRect.bottom - windowRect.top) - clientRect.bottom - borderWidth; 65 | 66 | 67 | //Debug.Log($"{typeof(AppWindowUtility).FullName}.Initialize: Title Bar {titleBarHeight}px / Border {borderWidth}px"); 68 | 69 | isInitialized = true; 70 | }// 71 | 72 | 73 | 74 | 75 | public void ResetStyle() 76 | { 77 | WinApi.SetWindowLong(hWnd, WinApi.GWL_STYLE, defaultWindowStyle); 78 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, defaultExWindowStyle); 79 | }// 80 | 81 | 82 | 83 | 84 | 85 | public bool GetAlwaysOnTop() => isAlwaysOnTop; 86 | public void SetAlwaysOnTop(bool enable) 87 | { 88 | WinApi.SetWindowPos( 89 | hWnd, 90 | enable ? WinApi.HWND_TOPMOST : WinApi.HWND_NOTOPMOST, 91 | 0, 0, 0, 0, 92 | WinApi.SetWindowPosFlags.IgnoreMove | WinApi.SetWindowPosFlags.IgnoreResize 93 | ); 94 | 95 | isAlwaysOnTop = enable; 96 | }// 97 | 98 | 99 | public bool GetTransparent() => isTransparent; 100 | public void SetTransparent(bool enable) 101 | { 102 | if (enable) 103 | { 104 | SetFrameVisibility(false); 105 | 106 | var currExStyle = WinApi.GetWindowLong(hWnd, WinApi.GWL_EXSTYLE); 107 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, currExStyle & ~WinApi.WS_EX_LAYERED); 108 | WinApi.SetDwmTransparent(true); 109 | 110 | } 111 | else 112 | { 113 | SetFrameVisibility(true); 114 | WinApi.SetDwmTransparent(false); 115 | } 116 | 117 | isTransparent = enable; 118 | }// 119 | 120 | 121 | 122 | 123 | public void SetKeyingColor(byte red, byte green, byte blue) 124 | { 125 | var currExStyle = WinApi.GetWindowLong(hWnd, WinApi.GWL_EXSTYLE); 126 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, currExStyle | WinApi.WS_EX_LAYERED);// | WindowsApi.WS_EX_TRANSPARENT); 127 | 128 | var color = (uint)(blue + (green << 8) + (red << 16)); 129 | WinApi.SetLayeredWindowAttributes(hWnd, color, 0xFF, WinApi.LWA_COLORKEY); 130 | }// 131 | 132 | 133 | 134 | 135 | public bool GetFrameVisibility() => isFrameVisible; 136 | public void SetFrameVisibility(bool visible) 137 | { 138 | if (AppWindowUtility.FullScreen) return; 139 | if (visible == isFrameVisible) return; 140 | 141 | if (visible) 142 | { 143 | // must be done BEFORE SetWindowLong 144 | MoveWindowRelative(-borderWidth, -titleBarHeight); 145 | //ResizeWindowRelative(borderWidth * 2, titleBarHeight + borderWidth); 146 | 147 | WinApi.SetWindowLong(hWnd, WinApi.GWL_STYLE, defaultWindowStyle); 148 | 149 | // to make uGUI correct. 150 | WinApi.SetWindowPos(hWnd, IntPtr.Zero, 151 | lastClientRect.left - borderWidth, 152 | lastClientRect.top - titleBarHeight, 153 | lastClientRect.right - lastClientRect.left + borderWidth * 2, 154 | lastClientRect.bottom - lastClientRect.top + titleBarHeight + borderWidth, 155 | WinApi.SetWindowPosFlags.FrameChanged | WinApi.SetWindowPosFlags.IgnoreMove 156 | ); 157 | 158 | } 159 | else 160 | { 161 | // store last client size for showing frame again 162 | if (!AppWindowUtility.FullScreen) 163 | { 164 | WinApi.GetClientRect(hWnd, out lastClientRect); 165 | //Debug.Log($"SetFrameVisibility: Client Rect stored."); 166 | } 167 | 168 | var currStyle = WinApi.GetWindowLong(hWnd, WinApi.GWL_STYLE); 169 | WinApi.SetWindowLong(hWnd, WinApi.GWL_STYLE, currStyle & ~WinApi.WS_BORDER & ~WinApi.WS_THICKFRAME & ~WinApi.WS_CAPTION); 170 | 171 | //// must be done AFTER SetWindowLong 172 | MoveWindowRelative(borderWidth, titleBarHeight); 173 | // must be change window size 2 times to work correctly, idk why. 174 | WinApi.SetWindowPos(hWnd, IntPtr.Zero, 175 | lastClientRect.left - borderWidth, 176 | lastClientRect.top - titleBarHeight, 177 | lastClientRect.right, 178 | lastClientRect.bottom + 1, 179 | WinApi.SetWindowPosFlags.FrameChanged | WinApi.SetWindowPosFlags.IgnoreMove 180 | ); 181 | WinApi.SetWindowPos(hWnd, IntPtr.Zero, 182 | lastClientRect.left - borderWidth, 183 | lastClientRect.top - titleBarHeight, 184 | lastClientRect.right, 185 | lastClientRect.bottom - 1, 186 | WinApi.SetWindowPosFlags.FrameChanged | WinApi.SetWindowPosFlags.IgnoreMove 187 | ); 188 | 189 | } 190 | 191 | isFrameVisible = visible; 192 | 193 | }// 194 | 195 | 196 | 197 | 198 | 199 | public bool GetClickThrough() => isClickThrough; 200 | public void SetClickThrough(bool enable) 201 | { 202 | if (enable) 203 | { 204 | var currExStyle = WinApi.GetWindowLong(hWnd, WinApi.GWL_EXSTYLE); 205 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, currExStyle | WinApi.WS_EX_LAYERED | WinApi.WS_EX_TRANSPARENT); 206 | } 207 | else 208 | { 209 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, defaultExWindowStyle); 210 | } 211 | 212 | isClickThrough = enable; 213 | }// 214 | 215 | 216 | 217 | public void SetWindowOpacity(byte opacity) 218 | { 219 | ////////if(0xFF == opacity) 220 | { 221 | var currExStyle = WinApi.GetWindowLong(hWnd, WinApi.GWL_EXSTYLE); 222 | WinApi.SetWindowLong(hWnd, WinApi.GWL_EXSTYLE, currExStyle | WinApi.WS_EX_LAYERED); 223 | WinApi.SetLayeredWindowAttributes(hWnd, defaultKeyingColor, opacity, WinApi.LWA_ALPHA); 224 | } 225 | 226 | /* do not reset for combination with Transparent 227 | else 228 | { 229 | ResetStyle(); 230 | } 231 | */ 232 | }// 233 | 234 | 235 | 236 | public bool GetAsWallpaper() => isWallpaper; 237 | public void SetAsWallpaper(bool enable) 238 | { 239 | }// 240 | 241 | 242 | 243 | public void MoveWindowRelative(int relativeX, int relativeY) 244 | { 245 | if (AppWindowUtility.FullScreen) return; 246 | 247 | WinApi.RECT rect; 248 | WinApi.GetWindowRect(hWnd, out rect); 249 | WinApi.SetWindowPos(hWnd, IntPtr.Zero, 250 | rect.left + relativeX, 251 | rect.top + relativeY, 252 | rect.right - rect.left, 253 | rect.bottom - rect.top, 254 | WinApi.SetWindowPosFlags.NoFlag //ApiWindows.SetWindowPosFlags.IgnoreResize 255 | ); 256 | }// 257 | 258 | 259 | 260 | public void ResizeWindowRelative(int relativeWidth, int relativeHeight) 261 | { 262 | if (AppWindowUtility.FullScreen) return; 263 | 264 | WinApi.RECT rect; 265 | WinApi.GetWindowRect(hWnd, out rect); 266 | WinApi.SetWindowPos(hWnd, IntPtr.Zero, 267 | rect.left, 268 | rect.top, 269 | rect.right - rect.left + relativeWidth, 270 | rect.bottom - rect.top + relativeHeight, 271 | WinApi.SetWindowPosFlags.NoFlag //ApiWindows.SetWindowPosFlags.IgnoreMove 272 | ); 273 | 274 | }// 275 | 276 | 277 | 278 | 279 | 280 | }//class 281 | }//namespace 282 | #endif 283 | -------------------------------------------------------------------------------- /Runtime/Windows/Windows.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 00a74ea748d2df149864a0f9d4455e24 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /SatorImaging.AppWindowUtility.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SatorImaging.AppWindowUtility", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /SatorImaging.AppWindowUtility.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1220ccfff01d26041a9bb8cd7ae584af 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.sator-imaging.app-window-utility", 3 | "displayName": "App Window Utility", 4 | "version": "1.0.0", 5 | "unity": "2018.3", 6 | "description": "Utility for configuring application window style. With this utility, you can make application window transparent, frameless and more.\n\nCopyright (c) 2021 Sator Imaging, all rights reserved.", 7 | 8 | "author": { 9 | "name": "Sator Imaging", 10 | "url": "https://www.sator-imaging.com/" 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9b6e7f857b825e749abd98ad9af4e67b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------