@@ -12,6 +12,7 @@ use std::{
12
12
borrow:: Cow ,
13
13
cell:: RefCell ,
14
14
collections:: VecDeque ,
15
+ env:: current_dir,
15
16
path:: { Path , PathBuf } ,
16
17
rc:: Rc ,
17
18
sync:: {
@@ -312,27 +313,49 @@ impl WebContextExt for super::WebContext {
312
313
) {
313
314
let context = & self . os . context ;
314
315
315
- let download_started_handler = RefCell :: new ( download_started_handler) ;
316
+ let download_started_handler = Rc :: new ( RefCell :: new ( download_started_handler) ) ;
316
317
let failed = Rc :: new ( RefCell :: new ( false ) ) ;
317
318
318
319
context. connect_download_started ( move |_context, download| {
319
- if let Some ( uri) = download. request ( ) . and_then ( |req| req. uri ( ) ) {
320
- let uri = uri. to_string ( ) ;
321
- let mut download_location = download
322
- . destination ( )
323
- . map ( PathBuf :: from)
324
- . unwrap_or_default ( ) ;
320
+ let download_started_handler = download_started_handler. clone ( ) ;
321
+ download. connect_decide_destination ( move |download, suggested_filename| {
322
+ if let Some ( uri) = download. request ( ) . and_then ( |req| req. uri ( ) ) {
323
+ let uri = uri. to_string ( ) ;
324
+
325
+ if let Some ( download_started_handler) = download_started_handler. borrow_mut ( ) . as_mut ( ) {
326
+ let mut download_location =
327
+ dirs:: download_dir ( ) . unwrap_or_else ( || current_dir ( ) . unwrap_or_default ( ) ) ;
328
+
329
+ let ( mut suggested_filename, mut ext) = suggested_filename
330
+ . split_once ( '.' )
331
+ . map ( |( base, ext) | ( base, format ! ( ".{ext}" ) ) )
332
+ . unwrap_or ( ( suggested_filename, "" . to_string ( ) ) ) ;
333
+
334
+ // for `data:` downloads, webkitgtk will suggest to use the raw data as the filename
335
+ // for example `"data:attachment/text,sometext"` will result in `text,sometext`
336
+ if uri. starts_with ( "data:" ) {
337
+ suggested_filename = "Unknown" ;
338
+ }
339
+
340
+ download_location. push ( format ! ( "{suggested_filename}{ext}" ) ) ;
341
+
342
+ // WebView2 does not overwrite files but appends numbers
343
+ let mut counter = 1 ;
344
+ while download_location. exists ( ) {
345
+ download_location. set_file_name ( format ! ( "{suggested_filename} ({counter}){ext}" ) ) ;
346
+ counter += 1 ;
347
+ }
325
348
326
- if let Some ( download_started_handler) = download_started_handler. borrow_mut ( ) . as_mut ( ) {
327
- if download_started_handler ( uri, & mut download_location) {
328
- download. connect_response_notify ( move |download| {
349
+ if download_started_handler ( uri, & mut download_location) {
329
350
download. set_destination ( & download_location. to_string_lossy ( ) ) ;
330
- } ) ;
331
- } else {
332
- download . cancel ( ) ;
351
+ } else {
352
+ download . cancel ( ) ;
353
+ }
333
354
}
334
355
}
335
- }
356
+ // TODO: check if we may also need `false`
357
+ true
358
+ } ) ;
336
359
337
360
download. connect_failed ( {
338
361
let failed = failed. clone ( ) ;
0 commit comments