@@ -10,20 +10,25 @@ use crate::toplevel_subscription::ToplevelRequest;
10
10
use crate :: toplevel_subscription:: ToplevelUpdate ;
11
11
use calloop:: channel:: Sender ;
12
12
use cctk:: toplevel_info:: ToplevelInfo ;
13
+ use cctk:: wayland_client:: protocol:: wl_data_device_manager:: DndAction ;
13
14
use cctk:: wayland_client:: protocol:: wl_seat:: WlSeat ;
14
15
use cosmic:: applet:: cosmic_panel_config:: PanelAnchor ;
15
16
use cosmic:: applet:: CosmicAppletHelper ;
16
17
use cosmic:: iced;
18
+ use cosmic:: iced:: wayland:: actions:: data_device:: DataFromMimeType ;
19
+ use cosmic:: iced:: wayland:: actions:: data_device:: DndIcon ;
17
20
use cosmic:: iced:: wayland:: actions:: window:: SctkWindowSettings ;
18
21
use cosmic:: iced:: wayland:: popup:: destroy_popup;
19
22
use cosmic:: iced:: wayland:: popup:: get_popup;
23
+ use cosmic:: iced:: widget:: dnd_source;
20
24
use cosmic:: iced:: widget:: mouse_listener;
21
25
use cosmic:: iced:: widget:: { column, row} ;
22
26
use cosmic:: iced:: Settings ;
23
27
use cosmic:: iced:: { window, Application , Command , Subscription } ;
24
28
use cosmic:: iced_native:: alignment:: Horizontal ;
25
29
use cosmic:: iced_native:: subscription:: events_with;
26
30
use cosmic:: iced_native:: widget:: vertical_space;
31
+ use cosmic:: iced_sctk:: commands:: data_device:: start_drag;
27
32
use cosmic:: iced_sctk:: layout:: Limits ;
28
33
use cosmic:: iced_sctk:: settings:: InitialSurface ;
29
34
use cosmic:: iced_sctk:: widget:: vertical_rule;
@@ -42,6 +47,9 @@ use iced::Alignment;
42
47
use iced:: Background ;
43
48
use iced:: Length ;
44
49
use itertools:: Itertools ;
50
+ use url:: Url ;
51
+
52
+ static MIME_TYPE : & str = "text/uri-list" ;
45
53
46
54
pub fn run ( ) -> cosmic:: iced:: Result {
47
55
let helper = CosmicAppletHelper :: default ( ) ;
@@ -79,6 +87,22 @@ struct DockItem {
79
87
desktop_info : DesktopInfo ,
80
88
}
81
89
90
+ impl DataFromMimeType for DockItem {
91
+ fn from_mime_type ( & self , mime_type : & str ) -> Option < Vec < u8 > > {
92
+ if mime_type == MIME_TYPE {
93
+ Some (
94
+ Url :: from_file_path ( self . desktop_info . path . clone ( ) )
95
+ . ok ( ) ?
96
+ . to_string ( )
97
+ . as_bytes ( )
98
+ . to_vec ( ) ,
99
+ )
100
+ } else {
101
+ None
102
+ }
103
+ }
104
+ }
105
+
82
106
impl DockItem {
83
107
fn new (
84
108
id : usize ,
@@ -92,7 +116,12 @@ impl DockItem {
92
116
}
93
117
}
94
118
95
- fn as_icon ( & self , applet_helper : & CosmicAppletHelper , rectangle_tracker : Option < & RectangleTracker < usize > > , has_popup : bool ) -> Element < ' _ , Message > {
119
+ fn as_icon (
120
+ & self ,
121
+ applet_helper : & CosmicAppletHelper ,
122
+ rectangle_tracker : Option < & RectangleTracker < usize > > ,
123
+ has_popup : bool ,
124
+ ) -> Element < ' _ , Message > {
96
125
let DockItem {
97
126
toplevels,
98
127
desktop_info,
@@ -143,6 +172,7 @@ impl DockItem {
143
172
. spacing ( 4 )
144
173
. into ( ) ,
145
174
} ;
175
+
146
176
let mut icon_button = cosmic:: widget:: button ( Button :: Text )
147
177
. custom ( vec ! [ icon_wrapper] )
148
178
. padding ( 8 ) ;
@@ -156,8 +186,13 @@ impl DockItem {
156
186
}
157
187
158
188
// TODO tooltip on hover
159
- let icon_button = mouse_listener ( icon_button. width ( Length :: Shrink ) . height ( Length :: Shrink ) )
160
- . on_right_release ( Message :: Popup ( desktop_info. id . clone ( ) ) ) ;
189
+ let icon_button = dnd_source (
190
+ mouse_listener ( icon_button. width ( Length :: Shrink ) . height ( Length :: Shrink ) )
191
+ . on_right_release ( Message :: Popup ( desktop_info. id . clone ( ) ) ) ,
192
+ )
193
+ . on_drag ( Message :: StartDrag ( * id) )
194
+ . on_cancelled ( Message :: DragFinished )
195
+ . on_finished ( Message :: DragFinished ) ;
161
196
if let Some ( tracker) = rectangle_tracker {
162
197
tracker. container ( * id, icon_button) . into ( )
163
198
} else {
@@ -174,6 +209,7 @@ struct CosmicAppList {
174
209
subscription_ctr : u32 ,
175
210
active_list : Vec < DockItem > ,
176
211
favorite_list : Vec < DockItem > ,
212
+ dnd_source : Option < ( window:: Id , DockItem , DndAction ) > ,
177
213
dnd_preview : Option < ( bool , DockItem ) > , // TODO allow non-toplevels to be dragged
178
214
config : AppListConfig ,
179
215
toplevel_sender : Option < Sender < ToplevelRequest > > ,
@@ -198,6 +234,8 @@ enum Message {
198
234
NewSeat ( WlSeat ) ,
199
235
RemovedSeat ( WlSeat ) ,
200
236
Rectangle ( RectangleUpdate < usize > ) ,
237
+ StartDrag ( usize ) , // id of the DockItem
238
+ DragFinished
201
239
}
202
240
203
241
#[ derive( Debug , Clone , Default ) ]
@@ -206,6 +244,7 @@ struct DesktopInfo {
206
244
icon : PathBuf ,
207
245
exec : String ,
208
246
name : String ,
247
+ path : PathBuf ,
209
248
}
210
249
211
250
fn desktop_info_for_app_ids ( mut app_ids : Vec < String > ) -> Vec < DesktopInfo > {
@@ -226,6 +265,7 @@ fn desktop_info_for_app_ids(mut app_ids: Vec<String>) -> Vec<DesktopInfo> {
226
265
icon : buf,
227
266
exec : de. exec ( ) . unwrap_or_default ( ) . to_string ( ) ,
228
267
name : de. name ( None ) . unwrap_or_default ( ) . to_string ( ) ,
268
+ path : path. clone ( ) ,
229
269
} )
230
270
} else {
231
271
None
@@ -373,6 +413,28 @@ impl Application for CosmicAppList {
373
413
}
374
414
}
375
415
}
416
+ Message :: StartDrag ( id) => {
417
+ if let Some ( toplevel_group) = self
418
+ . active_list
419
+ . iter ( )
420
+ . chain ( self . favorite_list . iter ( ) )
421
+ . find ( |t| t. id == id)
422
+ {
423
+ self . surface_id_ctr += 1 ;
424
+ let icon_id = window:: Id :: new ( self . surface_id_ctr ) ;
425
+ self . dnd_source = Some ( ( icon_id, toplevel_group. clone ( ) , DndAction :: empty ( ) ) ) ;
426
+ return start_drag (
427
+ vec ! [ MIME_TYPE . to_string( ) ] ,
428
+ DndAction :: all ( ) ,
429
+ window:: Id :: new ( 0 ) ,
430
+ Some ( DndIcon :: Custom ( icon_id) ) ,
431
+ Box :: new ( toplevel_group. clone ( ) ) ,
432
+ ) ;
433
+ }
434
+ }
435
+ Message :: DragFinished => {
436
+ self . dnd_source = None ;
437
+ }
376
438
Message :: Toplevel ( event) => {
377
439
match event {
378
440
ToplevelUpdate :: AddToplevel ( handle, info) => {
@@ -477,8 +539,15 @@ impl Application for CosmicAppList {
477
539
}
478
540
479
541
fn view ( & self , id : window:: Id ) -> Element < Message > {
542
+ if let Some ( ( _, item, _) ) = self . dnd_source . as_ref ( ) . filter ( |s| s. 0 == id) {
543
+ return cosmic:: widget:: icon (
544
+ Path :: new ( & item. desktop_info . icon ) ,
545
+ self . applet_helper . suggested_size ( ) . 0 ,
546
+ )
547
+ . into ( ) ;
548
+ }
480
549
if let Some ( (
481
- popup_id ,
550
+ _popup_id ,
482
551
DockItem {
483
552
toplevels,
484
553
desktop_info,
@@ -539,35 +608,30 @@ impl Application for CosmicAppList {
539
608
. on_press ( Message :: Quit ( desktop_info. id . clone ( ) ) ) ,
540
609
) ,
541
610
} ;
542
- // return Container::new(Container::new(content.width(Length::Shrink).height(Length::Shrink)).style(
543
- // cosmic::Container::Custom(|theme| container::Appearance {
544
- // text_color: Some(theme.cosmic().on_bg_color().into()),
545
- // background: Some(theme.extended_palette().background.base.color.into()),
546
- // border_radius: 12.0,
547
- // border_width: 0.0,
548
- // border_color: Color::TRANSPARENT,
549
- // }),
550
- // )).into();
551
611
return self . applet_helper . popup_container ( content) . into ( ) ;
552
612
}
553
613
554
614
let favorites = self
555
615
. favorite_list
556
616
. iter ( )
557
- . map (
558
- |dock_item| {
559
- dock_item. as_icon ( & self . applet_helper , self . rectangle_tracker . as_ref ( ) , self . popup . is_some ( ) )
560
- } ,
561
- )
617
+ . map ( |dock_item| {
618
+ dock_item. as_icon (
619
+ & self . applet_helper ,
620
+ self . rectangle_tracker . as_ref ( ) ,
621
+ self . popup . is_some ( ) ,
622
+ )
623
+ } )
562
624
. collect ( ) ;
563
625
let active = self
564
626
. active_list
565
627
. iter ( )
566
- . map (
567
- |dock_item| {
568
- dock_item. as_icon ( & self . applet_helper , self . rectangle_tracker . as_ref ( ) , self . popup . is_some ( ) )
569
- } ,
570
- )
628
+ . map ( |dock_item| {
629
+ dock_item. as_icon (
630
+ & self . applet_helper ,
631
+ self . rectangle_tracker . as_ref ( ) ,
632
+ self . popup . is_some ( ) ,
633
+ )
634
+ } )
571
635
. collect ( ) ;
572
636
573
637
let ( w, h) = match self . applet_helper . anchor {
0 commit comments