@@ -4,21 +4,29 @@ use crate::DesktopEntry;
44use std:: convert:: TryFrom ;
55use std:: path:: PathBuf ;
66use std:: process:: Command ;
7+ use zbus:: blocking:: Connection ;
78
9+ mod dbus;
810pub mod error;
911mod graphics;
1012
1113impl DesktopEntry < ' _ > {
1214 /// Execute the given desktop entry `Exec` key with either the default gpu or
1315 /// the alternative one if available.
14- pub fn launch (
15- & self ,
16- filename : Option < & str > ,
17- filenames : & [ & str ] ,
18- url : Option < & str > ,
19- urls : & [ & str ] ,
20- prefer_non_default_gpu : bool ,
21- ) -> Result < ( ) , ExecError > {
16+ pub fn launch ( & self , uris : & [ & str ] , prefer_non_default_gpu : bool ) -> Result < ( ) , ExecError > {
17+ match Connection :: session ( ) {
18+ Ok ( conn) => {
19+ if self . is_bus_actionable ( & conn) {
20+ self . dbus_launch ( & conn, uris, prefer_non_default_gpu)
21+ } else {
22+ self . shell_launch ( uris, prefer_non_default_gpu)
23+ }
24+ }
25+ Err ( _) => self . shell_launch ( uris, prefer_non_default_gpu) ,
26+ }
27+ }
28+
29+ fn shell_launch ( & self , uris : & [ & str ] , prefer_non_default_gpu : bool ) -> Result < ( ) , ExecError > {
2230 let exec = self . exec ( ) ;
2331 if exec. is_none ( ) {
2432 return Err ( ExecError :: MissingExecKey ( self . path ) ) ;
@@ -42,7 +50,7 @@ impl DesktopEntry<'_> {
4250 exec_args. push ( arg) ;
4351 }
4452
45- let exec_args = self . get_args ( filename , filenames , url , urls , exec_args) ;
53+ let exec_args = self . get_args ( uris , exec_args) ;
4654
4755 if exec_args. is_empty ( ) {
4856 return Err ( ExecError :: EmptyExecString ) ;
@@ -63,8 +71,8 @@ impl DesktopEntry<'_> {
6371 cmd
6472 }
6573 . args ( args)
66- . output ( ) ?
67- . status
74+ . spawn ( ) ?
75+ . try_wait ( ) ?
6876 } else {
6977 let mut cmd = Command :: new ( shell) ;
7078
@@ -74,44 +82,33 @@ impl DesktopEntry<'_> {
7482 cmd
7583 }
7684 . args ( & [ "-c" , & exec_args] )
77- . output ( ) ?
78- . status
85+ . spawn ( ) ?
86+ . try_wait ( ) ?
7987 } ;
8088
81- if !status. success ( ) {
82- return Err ( ExecError :: NonZeroStatusCode {
83- status : status. code ( ) ,
84- exec : exec. to_string ( ) ,
85- } ) ;
89+ if let Some ( status) = status {
90+ if !status. success ( ) {
91+ return Err ( ExecError :: NonZeroStatusCode {
92+ status : status. code ( ) ,
93+ exec : exec. to_string ( ) ,
94+ } ) ;
95+ }
8696 }
8797
8898 Ok ( ( ) )
8999 }
90100
91101 // Replace field code with their values and ignore deprecated and unknown field codes
92- fn get_args (
93- & self ,
94- filename : Option < & str > ,
95- filenames : & [ & str ] ,
96- url : Option < & str > ,
97- urls : & [ & str ] ,
98- exec_args : Vec < ArgOrFieldCode > ,
99- ) -> Vec < String > {
102+ fn get_args ( & self , uris : & [ & str ] , exec_args : Vec < ArgOrFieldCode > ) -> Vec < String > {
100103 exec_args
101104 . iter ( )
102105 . filter_map ( |arg| match arg {
103- ArgOrFieldCode :: SingleFileName => filename. map ( |filename| filename. to_string ( ) ) ,
104- ArgOrFieldCode :: FileList => {
105- if !filenames. is_empty ( ) {
106- Some ( filenames. join ( " " ) )
107- } else {
108- None
109- }
106+ ArgOrFieldCode :: SingleFileName | ArgOrFieldCode :: SingleUrl => {
107+ uris. get ( 0 ) . map ( |filename| filename. to_string ( ) )
110108 }
111- ArgOrFieldCode :: SingleUrl => url. map ( |url| url. to_string ( ) ) ,
112- ArgOrFieldCode :: UrlList => {
113- if !urls. is_empty ( ) {
114- Some ( urls. join ( " " ) )
109+ ArgOrFieldCode :: FileList | ArgOrFieldCode :: UrlList => {
110+ if !uris. is_empty ( ) {
111+ Some ( uris. join ( " " ) )
115112 } else {
116113 None
117114 }
@@ -129,7 +126,6 @@ impl DesktopEntry<'_> {
129126 ArgOrFieldCode :: DesktopFileLocation => {
130127 Some ( self . path . to_string_lossy ( ) . to_string ( ) )
131128 }
132- // Ignore deprecated field-codes
133129 ArgOrFieldCode :: Arg ( arg) => Some ( arg. to_string ( ) ) ,
134130 } )
135131 . collect ( )
@@ -222,7 +218,7 @@ mod test {
222218 let path = PathBuf :: from ( "tests/entries/unmatched-quotes.desktop" ) ;
223219 let input = fs:: read_to_string ( & path) . unwrap ( ) ;
224220 let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
225- let result = de. launch ( None , & [ ] , None , & [ ] , false ) ;
221+ let result = de. launch ( & [ ] , false ) ;
226222
227223 assert_that ! ( result)
228224 . is_err ( )
@@ -234,7 +230,7 @@ mod test {
234230 let path = PathBuf :: from ( "tests/entries/empty-exec.desktop" ) ;
235231 let input = fs:: read_to_string ( & path) . unwrap ( ) ;
236232 let de = DesktopEntry :: decode ( Path :: new ( path. as_path ( ) ) , & input) . unwrap ( ) ;
237- let result = de. launch ( None , & [ ] , None , & [ ] , false ) ;
233+ let result = de. launch ( & [ ] , false ) ;
238234
239235 assert_that ! ( result)
240236 . is_err ( )
@@ -247,7 +243,7 @@ mod test {
247243 let path = PathBuf :: from ( "tests/entries/alacritty-simple.desktop" ) ;
248244 let input = fs:: read_to_string ( & path) . unwrap ( ) ;
249245 let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
250- let result = de. launch ( None , & [ ] , None , & [ ] , false ) ;
246+ let result = de. launch ( & [ ] , false ) ;
251247
252248 assert_that ! ( result) . is_ok ( ) ;
253249 }
@@ -258,7 +254,7 @@ mod test {
258254 let path = PathBuf :: from ( "tests/entries/non-terminal-cmd.desktop" ) ;
259255 let input = fs:: read_to_string ( & path) . unwrap ( ) ;
260256 let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
261- let result = de. launch ( None , & [ ] , None , & [ ] , false ) ;
257+ let result = de. launch ( & [ ] , false ) ;
262258
263259 assert_that ! ( result) . is_ok ( ) ;
264260 }
@@ -269,7 +265,43 @@ mod test {
269265 let path = PathBuf :: from ( "tests/entries/non-terminal-cmd.desktop" ) ;
270266 let input = fs:: read_to_string ( & path) . unwrap ( ) ;
271267 let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
272- let result = de. launch ( None , & [ ] , None , & [ ] , false ) ;
268+ let result = de. launch ( & [ ] , false ) ;
269+
270+ assert_that ! ( result) . is_ok ( ) ;
271+ }
272+
273+ #[ test]
274+ #[ ignore = "Needs a desktop environment with nvim installed, run locally only" ]
275+ fn should_launch_with_field_codes ( ) {
276+ let path = PathBuf :: from ( "/usr/share/applications/nvim.desktop" ) ;
277+ let input = fs:: read_to_string ( & path) . unwrap ( ) ;
278+ let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
279+ let result = de. launch ( & [ "src/lib.rs" ] , false ) ;
280+
281+ assert_that ! ( result) . is_ok ( ) ;
282+ }
283+
284+ #[ test]
285+ #[ ignore = "Needs a desktop environment with gnome Books installed, run locally only" ]
286+ fn should_launch_with_dbus ( ) {
287+ let path = PathBuf :: from ( "/usr/share/applications/org.gnome.Books.desktop" ) ;
288+ let input = fs:: read_to_string ( & path) . unwrap ( ) ;
289+ let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
290+ let result = de. launch ( & [ ] , false ) ;
291+
292+ assert_that ! ( result) . is_ok ( ) ;
293+ }
294+
295+ #[ test]
296+ #[ ignore = "Needs a desktop environment with Nautilus installed, run locally only" ]
297+ fn should_launch_with_dbus_and_field_codes ( ) {
298+ let path = PathBuf :: from ( "/usr/share/applications/org.gnome.Nautilus.desktop" ) ;
299+ let input = fs:: read_to_string ( & path) . unwrap ( ) ;
300+ let de = DesktopEntry :: decode ( path. as_path ( ) , & input) . unwrap ( ) ;
301+ let path = std:: env:: current_dir ( ) . unwrap ( ) ;
302+ let path = path. to_string_lossy ( ) ;
303+ let path = format ! ( "file:///{path}" ) ;
304+ let result = de. launch ( & [ path. as_str ( ) ] , false ) ;
273305
274306 assert_that ! ( result) . is_ok ( ) ;
275307 }
0 commit comments