Преглед на файлове

feat(core): implement windows icon with wry (#1272)

Lucas Fernandes Nogueira преди 4 години
родител
ревизия
8a120683b6

+ 1 - 0
tauri-api/src/lib.rs

@@ -55,5 +55,6 @@ pub mod private {
     fn raw_config() -> &'static str;
     fn assets() -> &'static crate::assets::Assets;
     fn raw_tauri_script() -> &'static str;
+    fn default_window_icon() -> Option<&'static [u8]>;
   }
 }

+ 5 - 0
tauri-macros/src/error.rs

@@ -63,6 +63,11 @@ impl Error {
         fn raw_tauri_script() -> &'static str {
           unimplemented!()
         }
+
+        /// The default window icon.
+        fn default_window_icon() -> Option<&'static [u8]> {
+          unimplemented()
+        }
       }
     }
   }

+ 17 - 0
tauri-macros/src/expand.rs

@@ -41,6 +41,18 @@ pub(crate) fn load_context(input: DeriveInput) -> Result<TokenStream, Error> {
 
   let tauri_script_path = dist_dir.join("__tauri.js");
 
+  #[cfg(windows)]
+  let default_window_icon = {
+    let icon_path = config_dir.join("./icons/icon.ico").display().to_string();
+    quote! {
+      Some(include_bytes!(#icon_path))
+    }
+  };
+  #[cfg(not(windows))]
+  let default_window_icon = quote! {
+    None
+  };
+
   // format paths into a string to use them in quote!
   let tauri_config_path = full_config_path.display().to_string();
   let tauri_script_path = tauri_script_path.display().to_string();
@@ -66,6 +78,11 @@ pub(crate) fn load_context(input: DeriveInput) -> Result<TokenStream, Error> {
           fn raw_tauri_script() -> &'static str {
             include_str!(#tauri_script_path)
           }
+
+          /// Default window icon function.
+          fn default_window_icon() -> Option<&'static [u8]> {
+            #default_window_icon
+          }
       }
   })
 }

+ 3 - 1
tauri/src/app.rs

@@ -28,6 +28,7 @@ type Setup<A> = dyn Fn(WebviewManager<A>) -> BoxFuture<'static, ()> + Send + Syn
 pub struct Context {
   pub(crate) config: Config,
   pub(crate) tauri_script: &'static str,
+  pub(crate) default_window_icon: Option<&'static [u8]>,
   pub(crate) assets: &'static tauri_api::assets::Assets,
 }
 
@@ -36,6 +37,7 @@ impl Context {
     Ok(Self {
       config: serde_json::from_str(Context::raw_config())?,
       tauri_script: Context::raw_tauri_script(),
+      default_window_icon: Context::default_window_icon(),
       assets: Context::assets(),
     })
   }
@@ -162,7 +164,7 @@ impl<A: ApplicationExt + 'static> WebviewInitializer<A> for Arc<App<A>> {
       &self.url,
       &self.window_labels.lock().await,
       &self.plugin_initialization_script,
-      &self.context.tauri_script,
+      &self.context,
     )
   }
 

+ 10 - 4
tauri/src/app/utils.rs

@@ -10,7 +10,7 @@ use crate::{
     config::WindowUrl,
     rpc::{format_callback, format_callback_result},
   },
-  app::InvokeResponse,
+  app::{Icon, InvokeResponse},
   ApplicationExt, WebviewBuilderExt,
 };
 
@@ -246,7 +246,7 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
   content_url: &str,
   window_labels: &[String],
   plugin_initialization_script: &str,
-  tauri_script: &str,
+  context: &Context,
 ) -> crate::Result<BuiltWebview<A>> {
   // TODO let debug = cfg!(debug_assertions);
   let webview_url = match &webview.url {
@@ -255,8 +255,8 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
   };
 
   let (webview_builder, callbacks) = if webview.url == WindowUrl::App {
-    let webview_builder = webview.builder.url(webview_url)
-        .initialization_script(&initialization_script(plugin_initialization_script, tauri_script))
+    let mut webview_builder = webview.builder.url(webview_url)
+        .initialization_script(&initialization_script(plugin_initialization_script, &context.tauri_script))
         .initialization_script(&format!(
           r#"
               window.__TAURI__.__windows = {window_labels_array}.map(function (label) {{ return {{ label: label }} }});
@@ -267,6 +267,12 @@ pub(super) fn build_webview<A: ApplicationExt + 'static>(
           current_window_label = webview.label,
         ));
 
+    if !webview_builder.has_icon() {
+      if let Some(default_window_icon) = &context.default_window_icon {
+        webview_builder = webview_builder.icon(Icon::Raw(default_window_icon.to_vec()))?;
+      }
+    }
+
     let webview_manager_ = webview_manager.clone();
     let tauri_invoke_handler = crate::Callback::<A::Dispatcher> {
       name: "__TAURI_INVOKE_HANDLER__".to_string(),

+ 6 - 0
tauri/src/app/webview.rs

@@ -147,6 +147,12 @@ pub trait WebviewBuilderExt: Sized {
   /// Whether the window should always be on top of other windows.
   fn always_on_top(self, always_on_top: bool) -> Self;
 
+  /// Sets the window icon.
+  fn icon(self, icon: Icon) -> crate::Result<Self>;
+
+  /// Whether the icon was set or not.
+  fn has_icon(&self) -> bool;
+
   /// Builds the webview instance.
   fn finish(self) -> crate::Result<Self::Webview>;
 }

+ 15 - 6
tauri/src/app/webview/wry.rs

@@ -8,18 +8,18 @@ use once_cell::sync::Lazy;
 use crate::plugin::PluginStore;
 
 use std::{
-  convert::TryInto,
+  convert::{TryFrom, TryInto},
   sync::{Arc, Mutex},
 };
 
-impl TryInto<wry::Icon> for Icon {
+impl TryFrom<Icon> for wry::Icon {
   type Error = crate::Error;
-  fn try_into(self) -> Result<wry::Icon, Self::Error> {
-    let icon = match self {
-      Self::File(path) => {
+  fn try_from(icon: Icon) -> Result<Self, Self::Error> {
+    let icon = match icon {
+      Icon::File(path) => {
         wry::Icon::from_file(path).map_err(|e| crate::Error::InvalidIcon(e.to_string()))?
       }
-      Self::Raw(raw) => {
+      Icon::Raw(raw) => {
         wry::Icon::from_bytes(raw).map_err(|e| crate::Error::InvalidIcon(e.to_string()))?
       }
     };
@@ -163,6 +163,15 @@ impl WebviewBuilderExt for wry::Attributes {
     self
   }
 
+  fn icon(mut self, icon: Icon) -> crate::Result<Self> {
+    self.icon = Some(icon.try_into()?);
+    Ok(self)
+  }
+
+  fn has_icon(&self) -> bool {
+    self.icon.is_some()
+  }
+
   fn finish(self) -> crate::Result<Self::Webview> {
     Ok(self)
   }

BIN
tauri/test/fixture/src-tauri/icons/icon.ico