33 windows_subsystem = "windows"
44) ]
55
6- use std:: env;
7- use std:: path:: PathBuf ;
8- use std:: process:: Command ;
6+ use std:: {
7+ env,
8+ path:: PathBuf ,
9+ process:: Command ,
10+ } ;
911
1012use freya:: {
1113 prelude:: * ,
12- winit:: { dpi:: LogicalPosition , window:: WindowLevel } ,
14+ winit:: {
15+ dpi:: LogicalPosition ,
16+ platform:: x11:: {
17+ WindowAttributesExtX11 ,
18+ WindowType ,
19+ } ,
20+ window:: WindowLevel ,
21+ } ,
1322} ;
1423
1524fn main ( ) {
16- let ( width, height) = ( 64 , 800 ) ;
1725 launch (
1826 LaunchConfig :: new ( ) . with_window (
1927 WindowConfig :: new ( app)
2028 . with_title ( "Dock" )
21- . with_size ( width as f64 , height as f64 )
29+ . with_size ( 50. , 800. )
2230 . with_decorations ( false )
2331 . with_resizable ( false )
24- . with_background ( Color :: from_rgb ( 30 , 30 , 30 ) )
25- . with_window_attributes ( move |attributes, el| {
26- let attributes = attributes. with_window_level ( WindowLevel :: AlwaysOnTop ) ;
27-
28- // Position on left side of screen, centered vertically
29- if let Some ( monitor) = el
30- . primary_monitor ( )
31- . or_else ( || el. available_monitors ( ) . next ( ) )
32- {
33- let size = monitor. size ( ) ;
34- attributes. with_position ( LogicalPosition {
35- x : 0 ,
36- y : size. height as i32 / 2 - height / 2 ,
37- } )
38- } else {
39- attributes
40- }
32+ . with_background ( Color :: TRANSPARENT )
33+ . with_transparency ( true )
34+ . with_window_attributes ( move |attributes, _| {
35+ attributes
36+ . with_x11_window_type ( vec ! [ WindowType :: Dock ] )
37+ . with_window_level ( WindowLevel :: AlwaysOnTop )
38+ . with_position ( LogicalPosition { x : 54 , y : 32 } )
4139 } ) ,
4240 ) ,
4341 )
@@ -47,58 +45,78 @@ fn app() -> impl IntoElement {
4745 let apps = use_hook ( get_pinned_apps) ;
4846
4947 rect ( )
50- . width ( Size :: fill ( ) )
51- . height ( Size :: fill ( ) )
52- . padding ( Gaps :: new_all ( 8. ) )
48+ . expanded ( )
49+ . padding ( 8. )
5350 . spacing ( 8. )
54- . background ( Color :: from_rgb ( 30 , 30 , 30 ) )
55- . corner_radius ( 8. )
51+ . background ( ( 30 , 30 , 30 , 0.8 ) )
5652 . children ( apps. iter ( ) . filter_map ( |app| {
5753 app. icon_path . as_ref ( ) . map ( |icon_path| {
58- dock_icon ( icon_path. clone ( ) , app. name . clone ( ) )
54+ DockIcon {
55+ icon_path : icon_path. clone ( ) ,
56+ name : app. name . clone ( ) ,
57+ }
58+ . into ( )
5959 } )
6060 } ) )
6161}
6262
63- fn dock_icon ( icon_path : PathBuf , name : String ) -> Element {
64- let mut hovered = use_state ( || false ) ;
65-
66- let background = if * hovered. read ( ) {
67- Color :: from_rgb ( 60 , 60 , 60 )
68- } else {
69- Color :: TRANSPARENT
70- } ;
63+ #[ derive( PartialEq ) ]
64+ struct DockIcon {
65+ icon_path : PathBuf ,
66+ name : String ,
67+ }
7168
72- let is_svg = icon_path
73- . extension ( )
74- . is_some_and ( |ext| ext. eq_ignore_ascii_case ( "svg" ) ) ;
75-
76- let icon_element: Element = if is_svg {
77- let svg_data = use_hook ( || {
78- std:: fs:: read ( & icon_path)
79- . map ( Bytes :: from)
80- . unwrap_or_default ( )
81- } ) ;
82- svg ( svg_data) . width ( Size :: px ( 40. ) ) . height ( Size :: px ( 40. ) ) . into ( )
83- } else {
84- ImageViewer :: new ( icon_path)
85- . width ( Size :: px ( 40. ) )
86- . height ( Size :: px ( 40. ) )
87- . into ( )
88- } ;
69+ impl Component for DockIcon {
70+ fn render ( & self ) -> impl IntoElement {
71+ let mut hovered = use_state ( || false ) ;
72+
73+ let is_svg = self
74+ . icon_path
75+ . extension ( )
76+ . is_some_and ( |ext| ext. eq_ignore_ascii_case ( "svg" ) ) ;
77+
78+ let icon_element: Element = if is_svg {
79+ let icon_path = self . icon_path . clone ( ) ;
80+ let svg_data = use_hook ( || {
81+ std:: fs:: read ( & icon_path)
82+ . map ( Bytes :: from)
83+ . unwrap_or_default ( )
84+ } ) ;
85+ svg ( svg_data)
86+ . width ( Size :: px ( 28. ) )
87+ . height ( Size :: px ( 28. ) )
88+ . into ( )
89+ } else {
90+ ImageViewer :: new ( self . icon_path . clone ( ) )
91+ . sampling_mode ( SamplingMode :: Trilinear )
92+ . width ( Size :: px ( 28. ) )
93+ . height ( Size :: px ( 28. ) )
94+ . into ( )
95+ } ;
96+
97+ let name = self . name . clone ( ) ;
98+ let background = if hovered ( ) {
99+ Color :: from_rgb ( 60 , 60 , 60 )
100+ } else {
101+ Color :: TRANSPARENT
102+ } ;
103+
104+ rect ( )
105+ . center ( )
106+ . padding ( 4. )
107+ . corner_radius ( 8. )
108+ . background ( background)
109+ . on_pointer_enter ( move |_| hovered. set ( true ) )
110+ . on_pointer_leave ( move |_| hovered. set ( false ) )
111+ . on_press ( move |_| {
112+ println ! ( "Clicked: {}" , name) ;
113+ } )
114+ . child ( icon_element)
115+ }
89116
90- rect ( )
91- . center ( )
92- . padding ( Gaps :: new_all ( 4. ) )
93- . corner_radius ( 8. )
94- . background ( background)
95- . on_pointer_enter ( move |_| hovered. set ( true ) )
96- . on_pointer_leave ( move |_| hovered. set ( false ) )
97- . on_mouse_up ( move |_| {
98- println ! ( "Clicked: {}" , name) ;
99- } )
100- . child ( icon_element)
101- . into ( )
117+ fn render_key ( & self ) -> DiffKey {
118+ DiffKey :: from ( & self . name )
119+ }
102120}
103121
104122#[ derive( Clone , Debug ) ]
@@ -151,7 +169,8 @@ fn parse_desktop_file(desktop_id: &str) -> (String, Option<String>) {
151169 Some ( PathBuf :: from ( "/usr/share/applications" ) ) ,
152170 Some ( PathBuf :: from ( "/var/lib/flatpak/exports/share/applications" ) ) ,
153171 home. as_ref ( ) . map ( |h| h. join ( ".local/share/applications" ) ) ,
154- home. as_ref ( ) . map ( |h| h. join ( ".local/share/flatpak/exports/share/applications" ) ) ,
172+ home. as_ref ( )
173+ . map ( |h| h. join ( ".local/share/flatpak/exports/share/applications" ) ) ,
155174 Some ( PathBuf :: from ( "/var/lib/snapd/desktop/applications" ) ) ,
156175 ] ;
157176
@@ -191,9 +210,12 @@ fn find_icon_path(icon_name: &str) -> Option<PathBuf> {
191210
192211 let icon_dirs = [
193212 Some ( PathBuf :: from ( "/usr/share/icons/hicolor" ) ) ,
194- Some ( PathBuf :: from ( "/var/lib/flatpak/exports/share/icons/hicolor" ) ) ,
213+ Some ( PathBuf :: from (
214+ "/var/lib/flatpak/exports/share/icons/hicolor" ,
215+ ) ) ,
195216 home. as_ref ( ) . map ( |h| h. join ( ".local/share/icons/hicolor" ) ) ,
196- home. as_ref ( ) . map ( |h| h. join ( ".local/share/flatpak/exports/share/icons/hicolor" ) ) ,
217+ home. as_ref ( )
218+ . map ( |h| h. join ( ".local/share/flatpak/exports/share/icons/hicolor" ) ) ,
197219 Some ( PathBuf :: from ( "/usr/share/pixmaps" ) ) ,
198220 ] ;
199221
@@ -203,7 +225,10 @@ fn find_icon_path(icon_name: &str) -> Option<PathBuf> {
203225 // First pass: look for PNG files only
204226 for dir in icon_dirs. iter ( ) . flatten ( ) {
205227 for size in & sizes {
206- let icon_path = dir. join ( size) . join ( "apps" ) . join ( format ! ( "{}.png" , icon_name) ) ;
228+ let icon_path = dir
229+ . join ( size)
230+ . join ( "apps" )
231+ . join ( format ! ( "{}.png" , icon_name) ) ;
207232 if icon_path. exists ( ) {
208233 return Some ( icon_path) ;
209234 }
@@ -219,7 +244,10 @@ fn find_icon_path(icon_name: &str) -> Option<PathBuf> {
219244 // Second pass: fall back to SVG if no PNG found
220245 for dir in icon_dirs. into_iter ( ) . flatten ( ) {
221246 for size in & sizes {
222- let icon_path = dir. join ( size) . join ( "apps" ) . join ( format ! ( "{}.svg" , icon_name) ) ;
247+ let icon_path = dir
248+ . join ( size)
249+ . join ( "apps" )
250+ . join ( format ! ( "{}.svg" , icon_name) ) ;
223251 if icon_path. exists ( ) {
224252 return Some ( icon_path) ;
225253 }
0 commit comments