mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			dev
			...
			gpauth_win
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3175d1083a | 
							
								
								
									
										10
									
								
								.github/workflows/build.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/build.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -152,13 +152,11 @@ jobs: | ||||
|     - name: Build ${{ matrix.package }} package in Docker | ||||
|       run: | | ||||
|         docker run --pull=always --rm \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \ | ||||
|           yuezk/gpdev:${{ matrix.package }}-builder-tauri2 | ||||
|     - name: Install ${{ matrix.package }} package in Docker | ||||
|       run: | | ||||
|         docker run --pull=always --rm \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -e GPGUI_INSTALLED=0 \ | ||||
|           -v $(pwd)/build-gp-${{ matrix.package }}:/${{ matrix.package }} \ | ||||
|           yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \ | ||||
| @@ -207,16 +205,12 @@ jobs: | ||||
|       run: echo ${{ secrets.DOCKER_HUB_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin | ||||
|     - name: Build gpgui in Docker | ||||
|       run: | | ||||
|         docker run --pull=always --rm \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -v $(pwd)/gpgui-source:/gpgui yuezk/gpdev:gpgui-builder-tauri2 | ||||
|         docker run --pull=always --rm -v $(pwd)/gpgui-source:/gpgui yuezk/gpdev:gpgui-builder-tauri2 | ||||
|     - name: Install gpgui in Docker | ||||
|       run: | | ||||
|         cd gpgui-source | ||||
|         tar -xJf *.bin.tar.xz | ||||
|         docker run --pull=always --rm \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -v $(pwd):/gpgui yuezk/gpdev:gpgui-builder-tauri2 \ | ||||
|         docker run --pull=always --rm -v $(pwd):/gpgui yuezk/gpdev:gpgui-builder-tauri2 \ | ||||
|           bash -c "cd /gpgui/gpgui_*/ && ./gpgui --version" | ||||
|     - name: Upload gpgui | ||||
|       uses: actions/upload-artifact@v4 | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -112,14 +112,12 @@ jobs: | ||||
|       run: | | ||||
|         docker run --pull=always --rm \ | ||||
|           -v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -e INCLUDE_GUI=1 \ | ||||
|           yuezk/gpdev:${{ matrix.package }}-builder-tauri2 | ||||
|  | ||||
|     - name: Install ${{ matrix.package }} package in Docker | ||||
|       run: | | ||||
|         docker run --pull=always --rm \ | ||||
|           -e COREPACK_INTEGRITY_KEYS=0 \ | ||||
|           -v $(pwd)/build-${{ matrix.package }}:/${{ matrix.package }} \ | ||||
|           yuezk/gpdev:${{ matrix.package }}-builder-tauri2 \ | ||||
|           bash install.sh | ||||
|   | ||||
							
								
								
									
										457
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										457
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -11,7 +11,7 @@ members = [ | ||||
|  | ||||
| [workspace.package] | ||||
| rust-version = "1.80" | ||||
| version = "2.4.4" | ||||
| version = "2.4.3" | ||||
| authors = ["Kevin Yue <k3vinyue@gmail.com>"] | ||||
| homepage = "https://github.com/yuezk/GlobalProtect-openconnect" | ||||
| edition = "2021" | ||||
|   | ||||
							
								
								
									
										193
									
								
								apps/gpgui-helper/dist/assets/main-CQPVXkdn.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								apps/gpgui-helper/dist/assets/main-CQPVXkdn.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										228
									
								
								apps/gpgui-helper/dist/assets/main-sEPcTvJX.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										228
									
								
								apps/gpgui-helper/dist/assets/main-sEPcTvJX.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								apps/gpgui-helper/dist/index.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								apps/gpgui-helper/dist/index.html
									
									
									
									
										vendored
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
|     <link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
|     <title>GlobalProtect</title> | ||||
|     <script type="module" crossorigin src="/assets/main-sEPcTvJX.js"></script> | ||||
|     <script type="module" crossorigin src="/assets/main-CQPVXkdn.js"></script> | ||||
|     <link rel="stylesheet" crossorigin href="/assets/main-B3YRsHQ2.css"> | ||||
|   </head> | ||||
|   <body> | ||||
|   | ||||
| @@ -11,27 +11,27 @@ | ||||
|   "dependencies": { | ||||
|     "@emotion/react": "^11.14.0", | ||||
|     "@emotion/styled": "^11.14.0", | ||||
|     "@mui/icons-material": "^6.4.3", | ||||
|     "@mui/material": "^6.4.3", | ||||
|     "@tauri-apps/api": "^2.2.0", | ||||
|     "@mui/icons-material": "^6.3.0", | ||||
|     "@mui/material": "^6.3.0", | ||||
|     "@tauri-apps/api": "^2.1.1", | ||||
|     "react": "^19.0.0", | ||||
|     "react-dom": "^19.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@tauri-apps/cli": "^2.2.7", | ||||
|     "@types/node": "^22.13.1", | ||||
|     "@types/react": "^19.0.8", | ||||
|     "@types/react-dom": "^19.0.3", | ||||
|     "@typescript-eslint/eslint-plugin": "^8.23.0", | ||||
|     "@typescript-eslint/parser": "^8.23.0", | ||||
|     "@tauri-apps/cli": "^2.1.0", | ||||
|     "@types/node": "^22.10.2", | ||||
|     "@types/react": "^19.0.2", | ||||
|     "@types/react-dom": "^19.0.2", | ||||
|     "@typescript-eslint/eslint-plugin": "^8.18.2", | ||||
|     "@typescript-eslint/parser": "^8.18.2", | ||||
|     "@vitejs/plugin-react": "^4.3.4", | ||||
|     "eslint": "^9.20.0", | ||||
|     "eslint": "^9.17.0", | ||||
|     "eslint-config-prettier": "^9.1.0", | ||||
|     "eslint-plugin-react": "^7.37.4", | ||||
|     "eslint-plugin-react": "^7.37.3", | ||||
|     "eslint-plugin-react-hooks": "^5.1.0", | ||||
|     "prettier": "3.4.2", | ||||
|     "typescript": "^5.7.3", | ||||
|     "vite": "^6.1.0" | ||||
|     "typescript": "^5.7.2", | ||||
|     "vite": "^6.0.5" | ||||
|   }, | ||||
|   "packageManager": "pnpm@9.15.1" | ||||
| } | ||||
|   | ||||
							
								
								
									
										1412
									
								
								apps/gpgui-helper/pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1412
									
								
								apps/gpgui-helper/pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,10 +1,5 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2.4.4 - 2025-02-09 | ||||
|  | ||||
| - GUI: fix multiple tray icons issue (fix [#464](https://github.com/yuezk/GlobalProtect-openconnect/issues/464)) | ||||
| - CLI: check the cli running state before running the `gpclient` command (fix [#447](https://github.com/yuezk/GlobalProtect-openconnect/issues/447)) | ||||
|  | ||||
| ## 2.4.3 - 2025-01-21 | ||||
|  | ||||
| - Do not use static default value for `--os-version` option. | ||||
|   | ||||
| @@ -28,7 +28,7 @@ regex = { workspace = true, optional = true } | ||||
| tokio-util = { workspace = true, optional = true } | ||||
| html-escape = { version = "0.2.13", optional = true } | ||||
|  | ||||
| [target.'cfg(not(target_os = "macos"))'.dependencies] | ||||
| [target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies] | ||||
| webkit2gtk = { version = "2", optional = true } | ||||
|  | ||||
| [target.'cfg(target_os="macos")'.dependencies] | ||||
| @@ -37,6 +37,12 @@ objc2 = { version = "0.5", optional = true } | ||||
| objc2-foundation = { version = "0.2", optional = true } | ||||
| objc2-web-kit = { version = "0.2", optional = true } | ||||
|  | ||||
| [target.'cfg(target_os="windows")'.dependencies] | ||||
| webview2-com = { version = "0.34", optional = true } | ||||
| windows-core = { version = "0.58", optional = true } | ||||
| windows = { version = "0.58", optional = true } | ||||
| serde_json = { workspace = true, optional = true } | ||||
|  | ||||
| [features] | ||||
| browser-auth = [ | ||||
|   "dep:webbrowser", | ||||
| @@ -56,4 +62,8 @@ webview-auth = [ | ||||
|   "dep:objc2", | ||||
|   "dep:objc2-foundation", | ||||
|   "dep:objc2-web-kit", | ||||
|   "dep:webview2-com", | ||||
|   "dep:windows-core", | ||||
|   "dep:windows", | ||||
|   "dep:serde_json", | ||||
| ] | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use std::{env::temp_dir, fs, os::unix::fs::PermissionsExt}; | ||||
| use std::{env::temp_dir, fs}; | ||||
|  | ||||
| use gpapi::{auth::SamlAuthData, GP_CALLBACK_PORT_FILENAME}; | ||||
| use log::info; | ||||
| @@ -96,7 +96,11 @@ async fn wait_auth_data() -> anyhow::Result<SamlAuthData> { | ||||
|  | ||||
|   // Write the port to a file | ||||
|   fs::write(&port_file, port.to_string())?; | ||||
|   #[cfg(unix)] | ||||
|   { | ||||
|     use os::unix::fs::PermissionsExt; | ||||
|     fs::set_permissions(&port_file, fs::Permissions::from_mode(0o600))?; | ||||
|   } | ||||
|  | ||||
|   // Remove the previous log file | ||||
|   let callback_log = temp_dir().join("gpcallback.log"); | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| mod auth_messenger; | ||||
| mod webview_auth; | ||||
|  | ||||
| #[cfg_attr(not(target_os = "macos"), path = "webview/unix.rs")] | ||||
| #[cfg_attr(not(any(target_os = "macos", target_os = "windows")), path = "webview/unix.rs")] | ||||
| #[cfg_attr(target_os = "macos", path = "webview/macos.rs")] | ||||
| #[cfg_attr(windows, path = "webview/windows.rs")] | ||||
| mod platform_impl; | ||||
|  | ||||
| pub use webview_auth::WebviewAuthenticator; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ pub(crate) enum AuthDataLocation { | ||||
| #[derive(Debug)] | ||||
| pub(crate) enum AuthError { | ||||
|   /// Failed to load page due to TLS error | ||||
|   #[cfg(not(target_os = "macos"))] | ||||
|   #[cfg(not(any(target_os = "macos", target_os = "windows")))] | ||||
|   TlsError, | ||||
|   /// 1. Found auth data in headers/body but it's invalid | ||||
|   /// 2. Loaded an empty page, failed to load page. etc. | ||||
|   | ||||
| @@ -115,7 +115,7 @@ impl<'a> WebviewAuthenticator<'a> { | ||||
|       match auth_messenger.subscribe().await? { | ||||
|         AuthEvent::Close => bail!("Authentication cancelled"), | ||||
|         AuthEvent::RaiseWindow => self.raise_window(&auth_window), | ||||
|         #[cfg(not(target_os = "macos"))] | ||||
|         #[cfg(not(any(target_os = "macos", target_os = "windows")))] | ||||
|         AuthEvent::Error(AuthError::TlsError) => bail!(gpapi::error::PortalError::TlsError), | ||||
|         AuthEvent::Error(AuthError::NotFound(location)) => { | ||||
|           info!( | ||||
| @@ -261,10 +261,10 @@ impl<'a> WebviewAuthenticator<'a> { | ||||
|  | ||||
|     info!("Raising auth window..."); | ||||
|  | ||||
|     #[cfg(target_os = "macos")] | ||||
|     #[cfg(any(target_os = "macos", target_os = "windows"))] | ||||
|     let result = auth_window.show(); | ||||
|  | ||||
|     #[cfg(not(target_os = "macos"))] | ||||
|     #[cfg(not(any(target_os = "macos", target_os = "windows")))] | ||||
|     let result = { | ||||
|       use gpapi::utils::window::WindowExt; | ||||
|       auth_window.raise() | ||||
|   | ||||
							
								
								
									
										142
									
								
								crates/auth/src/webview/windows.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								crates/auth/src/webview/windows.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| use log::warn; | ||||
| use tauri::webview::PlatformWebview; | ||||
| use webview2_com::{ | ||||
|   pwstr_from_str, take_pwstr, ExecuteScriptCompletedHandler, | ||||
|   Microsoft::Web::WebView2::Win32::{ | ||||
|     ICoreWebView2WebResourceResponseView, ICoreWebView2_14, ICoreWebView2_2, | ||||
|     COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW, | ||||
|   }, | ||||
|   ServerCertificateErrorDetectedEventHandler, WebResourceResponseReceivedEventHandler, | ||||
| }; | ||||
| use windows_core::{Interface, PWSTR}; | ||||
|  | ||||
| use super::{ | ||||
|   auth_messenger::AuthError, | ||||
|   webview_auth::{GetHeader, PlatformWebviewExt}, | ||||
| }; | ||||
|  | ||||
| impl PlatformWebviewExt for PlatformWebview { | ||||
|   fn ignore_tls_errors(&self) -> anyhow::Result<()> { | ||||
|     unsafe { | ||||
|       let wv = self.controller().CoreWebView2()?.cast::<ICoreWebView2_14>()?; | ||||
|       let handler = ServerCertificateErrorDetectedEventHandler::create(Box::new(|_, e| { | ||||
|         if let Some(e) = e { | ||||
|           let _ = e.SetAction(COREWEBVIEW2_SERVER_CERTIFICATE_ERROR_ACTION_ALWAYS_ALLOW); | ||||
|         } | ||||
|         Ok(()) | ||||
|       })); | ||||
|  | ||||
|       wv.add_ServerCertificateErrorDetected(&handler, &mut Default::default())?; | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
|   } | ||||
|  | ||||
|   fn load_url(&self, url: &str) -> anyhow::Result<()> { | ||||
|     let url = pwstr_from_str(url); | ||||
|  | ||||
|     unsafe { self.controller().CoreWebView2()?.Navigate(url)? } | ||||
|  | ||||
|     Ok(()) | ||||
|   } | ||||
|  | ||||
|   fn load_html(&self, html: &str) -> anyhow::Result<()> { | ||||
|     let html = pwstr_from_str(html); | ||||
|  | ||||
|     unsafe { self.controller().CoreWebView2()?.NavigateToString(html)? } | ||||
|  | ||||
|     Ok(()) | ||||
|   } | ||||
|  | ||||
|   fn get_html(&self, callback: Box<dyn Fn(anyhow::Result<String>) + 'static>) { | ||||
|     unsafe { | ||||
|       match self.controller().CoreWebView2() { | ||||
|         Ok(wv) => { | ||||
|           let js = "document.documentElement.outerHTML"; | ||||
|           let js = pwstr_from_str(js); | ||||
|  | ||||
|           let handler = ExecuteScriptCompletedHandler::create(Box::new(move |err, html| { | ||||
|             if let Err(err) = err { | ||||
|               callback(Err(anyhow::anyhow!(err))); | ||||
|               return Ok(()); | ||||
|             } | ||||
|  | ||||
|             // The returned HTML is JSON.stringify'd string, so we need to parse it | ||||
|             let res = match serde_json::from_str(&html) { | ||||
|               Ok(Some(html)) => Ok(html), | ||||
|               Ok(None) => Err(anyhow::anyhow!("No HTML returned")), | ||||
|               Err(err) => Err(anyhow::anyhow!(err)), | ||||
|             }; | ||||
|             callback(res); | ||||
|  | ||||
|             Ok(()) | ||||
|           })); | ||||
|  | ||||
|           if let Err(err) = wv.ExecuteScript(js, &handler) { | ||||
|             warn!("Failed to execute script: {}", err); | ||||
|           } | ||||
|         } | ||||
|         Err(err) => callback(Err(anyhow::anyhow!(err))), | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| impl GetHeader for ICoreWebView2WebResourceResponseView { | ||||
|   fn get_header(&self, key: &str) -> Option<String> { | ||||
|     unsafe { | ||||
|       let headers = self.Headers().ok()?; | ||||
|       let key = pwstr_from_str(key); | ||||
|  | ||||
|       let mut contains = Default::default(); | ||||
|       headers.Contains(key, &mut contains).ok()?; | ||||
|  | ||||
|       if contains.as_bool() { | ||||
|         let mut value = PWSTR::null(); | ||||
|         headers.GetHeader(key, &mut value).ok()?; | ||||
|         let value = take_pwstr(value); | ||||
|  | ||||
|         Some(value) | ||||
|       } else { | ||||
|         None | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| pub trait PlatformWebviewOnResponse { | ||||
|   fn on_response( | ||||
|     &self, | ||||
|     callback: Box<dyn Fn(anyhow::Result<ICoreWebView2WebResourceResponseView, AuthError>) + 'static>, | ||||
|   ); | ||||
| } | ||||
|  | ||||
| impl PlatformWebviewOnResponse for PlatformWebview { | ||||
|   fn on_response( | ||||
|     &self, | ||||
|     callback: Box<dyn Fn(anyhow::Result<ICoreWebView2WebResourceResponseView, AuthError>) + 'static>, | ||||
|   ) { | ||||
|     unsafe { | ||||
|       let _ = self | ||||
|         .controller() | ||||
|         .CoreWebView2() | ||||
|         .and_then(|wv| wv.cast::<ICoreWebView2_2>()) | ||||
|         .map(|wv| { | ||||
|           let handler = WebResourceResponseReceivedEventHandler::create(Box::new(move |_, e| { | ||||
|             let Some(e) = e else { | ||||
|               return Ok(()); | ||||
|             }; | ||||
|  | ||||
|             match e.Response() { | ||||
|               Ok(res) => callback(Ok(res)), | ||||
|               Err(err) => warn!("Failed to get response: {}", err), | ||||
|             } | ||||
|  | ||||
|             Ok(()) | ||||
|           })); | ||||
|  | ||||
|           let _ = wv.add_WebResourceResponseReceived(&handler, &mut Default::default()); | ||||
|         }); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -27,7 +27,7 @@ chacha20poly1305 = { version = "0.10", features = ["std"] } | ||||
| redact-engine.workspace = true | ||||
| url.workspace = true | ||||
| regex.workspace = true | ||||
| uzers.workspace = true | ||||
|  | ||||
| serde_urlencoded.workspace = true | ||||
| md5.workspace = true | ||||
| sha256.workspace = true | ||||
| @@ -39,8 +39,8 @@ clap-verbosity-flag = { workspace = true, optional = true } | ||||
| env_logger = { workspace = true, optional = true } | ||||
| log-reload = { version = "0.1", optional = true } | ||||
|  | ||||
| [target.'cfg(not(any(target_os="macos", target_os="windows")))'.dependencies] | ||||
| gtk = "0.18" | ||||
| [target.'cfg(target_family="unix")'.dependencies] | ||||
| uzers.workspace = true | ||||
|  | ||||
| [features] | ||||
| tauri = ["dep:tauri"] | ||||
|   | ||||
| @@ -104,7 +104,7 @@ impl SamlAuthData { | ||||
|     } | ||||
|  | ||||
|     let auth_data = decode_to_string(auth_data).map_err(|e| { | ||||
|       warn!("Failed to decode SAML auth data: {}", e); | ||||
|       warn!("Failed to decode SAML auth data: {}", auth_data); | ||||
|       AuthDataParseError::Invalid(anyhow::anyhow!(e)) | ||||
|     })?; | ||||
|     let auth_data = Self::from_html(&auth_data)?; | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| mod login; | ||||
| mod parse_gateways; | ||||
|  | ||||
| #[cfg(unix)] | ||||
| pub mod hip; | ||||
|  | ||||
| pub use login::*; | ||||
|   | ||||
| @@ -4,7 +4,10 @@ pub mod error; | ||||
| pub mod gateway; | ||||
| pub mod gp_params; | ||||
| pub mod portal; | ||||
|  | ||||
| #[cfg(unix)] | ||||
| pub mod process; | ||||
|  | ||||
| pub mod service; | ||||
| pub mod utils; | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,11 @@ | ||||
| pub(crate) mod command_traits; | ||||
|  | ||||
| pub(crate) mod gui_helper_launcher; | ||||
|  | ||||
| pub mod auth_launcher; | ||||
| pub mod gui_launcher; | ||||
| pub mod hip_launcher; | ||||
| pub mod service_launcher; | ||||
|  | ||||
| #[cfg(unix)] | ||||
| pub mod users; | ||||
|   | ||||
| @@ -41,6 +41,12 @@ pub fn patch_gui_runtime_env(hidpi: bool) { | ||||
|   // This is to avoid blank screen on some systems | ||||
|   std::env::set_var("WEBKIT_DISABLE_COMPOSITING_MODE", "1"); | ||||
|  | ||||
|   // Workaround for https://github.com/tauri-apps/tao/issues/929 | ||||
|   let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland"; | ||||
|   if is_wayland { | ||||
|     env::set_var("GDK_BACKEND", "x11"); | ||||
|   } | ||||
|  | ||||
|   if hidpi { | ||||
|     info!("Setting GDK_SCALE=2 and GDK_DPI_SCALE=0.5"); | ||||
|     std::env::set_var("GDK_SCALE", "2"); | ||||
|   | ||||
| @@ -9,7 +9,7 @@ pub mod lock_file; | ||||
| pub mod openssl; | ||||
| pub mod redact; | ||||
| pub mod request; | ||||
| #[cfg(feature = "tauri")] | ||||
| #[cfg(all(feature = "tauri", not(any(target_os = "macos", target_os = "windows"))))] | ||||
| pub mod window; | ||||
|  | ||||
| mod shutdown_signal; | ||||
|   | ||||
| @@ -6,15 +6,21 @@ pub async fn shutdown_signal() { | ||||
|   }; | ||||
|  | ||||
|   #[cfg(unix)] | ||||
|   { | ||||
|     let terminate = async { | ||||
|       signal::unix::signal(signal::unix::SignalKind::terminate()) | ||||
|         .expect("failed to install signal handler") | ||||
|         .recv() | ||||
|         .await; | ||||
|     }; | ||||
|  | ||||
|     tokio::select! { | ||||
|         _ = ctrl_c => {}, | ||||
|         _ = terminate => {}, | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   #[cfg(not(unix))] | ||||
|   { | ||||
|     ctrl_c.await; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,49 +1,26 @@ | ||||
| use std::{process::ExitStatus, time::Duration}; | ||||
|  | ||||
| use anyhow::bail; | ||||
| use log::info; | ||||
| use tauri::WebviewWindow; | ||||
| use tokio::process::Command; | ||||
|  | ||||
| pub trait WindowExt { | ||||
|   fn raise(&self) -> anyhow::Result<()>; | ||||
| } | ||||
|  | ||||
| impl WindowExt for WebviewWindow { | ||||
|   #[cfg(any(target_os = "macos", target_os = "windows"))] | ||||
|   fn raise(&self) -> anyhow::Result<()> { | ||||
|     self.show()?; | ||||
|     Ok(()) | ||||
|   } | ||||
|  | ||||
|   #[cfg(not(any(target_os = "macos", target_os = "windows")))] | ||||
|   fn raise(&self) -> anyhow::Result<()> { | ||||
|     unix::raise_window(self) | ||||
|     raise_window(self) | ||||
|   } | ||||
| } | ||||
|  | ||||
| #[cfg(not(any(target_os = "macos", target_os = "windows")))] | ||||
| mod unix { | ||||
|   use std::{process::ExitStatus, time::Duration}; | ||||
|  | ||||
|   use anyhow::bail; | ||||
|   use gtk::{ | ||||
|     glib::Cast, | ||||
|     traits::{EventBoxExt, GtkWindowExt, WidgetExt}, | ||||
|     EventBox, | ||||
|   }; | ||||
|   use log::info; | ||||
|   use tauri::WebviewWindow; | ||||
|   use tokio::process::Command; | ||||
|  | ||||
| pub fn raise_window(win: &WebviewWindow) -> anyhow::Result<()> { | ||||
|   let is_wayland = std::env::var("XDG_SESSION_TYPE").unwrap_or_default() == "wayland"; | ||||
|  | ||||
|   if is_wayland { | ||||
|       let gtk_win = win.gtk_window()?; | ||||
|       if let Some(header) = gtk_win.titlebar() { | ||||
|         let _ = header.downcast::<EventBox>().map(|event_box| { | ||||
|           event_box.set_above_child(false); | ||||
|         }); | ||||
|       } | ||||
|  | ||||
|       gtk_win.hide(); | ||||
|       gtk_win.show_all(); | ||||
|     win.hide()?; | ||||
|     win.show()?; | ||||
|   } else { | ||||
|     if !win.is_visible()? { | ||||
|       win.show()?; | ||||
| @@ -56,7 +33,7 @@ mod unix { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|     // Calling window.show() on window object will cause the menu to be shown. | ||||
|   // Calling window.show() on Windows will cause the menu to be shown. | ||||
|   // We need to hide it again. | ||||
|   win.hide_menu()?; | ||||
|  | ||||
| @@ -94,4 +71,3 @@ mod unix { | ||||
|  | ||||
|   Ok(exit_status) | ||||
| } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user