1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
//! Window abstraction
use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;
use std::sync::Arc;

use wayland_client::protocol::{
    wl_compositor, wl_output, wl_seat, wl_shm, wl_subcompositor, wl_surface,
};
use wayland_client::{Attached, DispatchData};

use wayland_protocols::xdg_shell::client::xdg_toplevel::ResizeEdge;
pub use wayland_protocols::xdg_shell::client::xdg_toplevel::State;

use wayland_protocols::unstable::xdg_decoration::v1::client::{
    zxdg_decoration_manager_v1::ZxdgDecorationManagerV1,
    zxdg_toplevel_decoration_v1::{self, ZxdgToplevelDecorationV1},
};

use crate::{
    environment::{Environment, GlobalHandler, MultiGlobalHandler},
    seat::pointer::ThemeManager,
    shell,
};

mod fallback_frame;
pub use self::fallback_frame::FallbackFrame;

// Defines the minimum window size. Minimum width is set to 2 pixels to circumvent
// a bug in mutter - https://gitlab.gnome.org/GNOME/mutter/issues/259
const MIN_WINDOW_SIZE: (u32, u32) = (2, 1);

/// Represents the status of a button
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ButtonState {
    /// Button is being hovered over by pointer
    Hovered,
    /// Button is not being hovered over by pointer
    Idle,
    /// Button is disabled
    Disabled,
}

/// Represents the status of a window
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum WindowState {
    /// The window is active, in the foreground
    Active,
    /// The window is inactive, in the background
    Inactive,
}

impl From<bool> for WindowState {
    fn from(b: bool) -> WindowState {
        if b {
            WindowState::Active
        } else {
            WindowState::Inactive
        }
    }
}

impl From<WindowState> for bool {
    fn from(s: WindowState) -> bool {
        match s {
            WindowState::Active => true,
            WindowState::Inactive => false,
        }
    }
}

/// Possible events generated by a window that you need to handle
#[derive(Clone, Debug)]
pub enum Event {
    /// The state of your window has been changed
    Configure {
        /// Optional new size for your *inner* surface
        ///
        /// This is the new size of the contents of your window
        /// as suggested by the server. You can ignore it and choose
        /// a new size if you want better control on the possible
        /// sizes of your window.
        ///
        /// The size is expressed in logical pixels, you need to multiply it by
        /// your buffer scale to get the actual number of pixels to draw.
        ///
        /// In all cases, these events can be generated in large batches
        /// during an interactive resize, and you should buffer them before
        /// processing them. You only need to handle the last one of a batch.
        new_size: Option<(u32, u32)>,
        /// New combination of states of your window
        ///
        /// Typically tells you if your surface is active/inactive, maximized,
        /// etc...
        states: Vec<State>,
    },
    /// A close request has been received
    ///
    /// Most likely the user has clicked on the close button of the decorations
    /// or something equivalent
    Close,
    /// The decorations need to be refreshed
    Refresh,
}

/// Possible decoration modes for a Window
///
/// This represents what your application requests from the server.
///
/// In any case, the compositor may override your requests. In that case SCTK
/// will follow its decision.
///
/// If you don't care about it, you should use `FollowServer` (which is the
/// SCTK default). It'd be the most ergonomic for your users.
#[derive(Debug, PartialEq, Eq)]
pub enum Decorations {
    /// Request server-side decorations
    ServerSide,
    /// Force using the client-side `Frame`
    ClientSide,
    /// Follow the preference of the compositor
    FollowServer,
    /// Don't decorate the Window
    None,
}

struct WindowInner<F> {
    frame: Rc<RefCell<F>>,
    shell_surface: Arc<Box<dyn shell::ShellSurface>>,
    user_impl: Box<dyn FnMut(Event, DispatchData)>,
    min_size: (u32, u32),
    max_size: Option<(u32, u32)>,
    current_size: (u32, u32),
    old_size: Option<(u32, u32)>,
    decorated: bool,
}

impl<F> fmt::Debug for WindowInner<F>
where
    F: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("WindowInner")
            .field("frame", &self.frame)
            .field("shell_surface", &self.shell_surface)
            .field("user_impl", &"Fn() -> { ... }")
            .field("min_size", &self.min_size)
            .field("max_size", &self.max_size)
            .field("current_size", &self.current_size)
            .field("old_size", &self.old_size)
            .field("decorated", &self.decorated)
            .finish()
    }
}

/// A window
///
/// This wrapper handles for you the decoration of your window
/// and the interaction with the server regarding the shell protocol.
///
/// You are still entirely responsible for drawing the contents of your
/// window.
///
/// Note also that as the dimensions of wayland surfaces is defined by
/// their attached buffer, you need to keep the decorations in sync with
/// your contents via the `resize(..)` method.
///
/// Different kind of decorations can be used by customizing the type
/// parameter. A few are provided in this crate if the `frames` cargo feature
/// is enabled, but any type implementing the `Frame` trait can do.
pub struct Window<F: Frame> {
    frame: Rc<RefCell<F>>,
    surface: wl_surface::WlSurface,
    decoration: Option<ZxdgToplevelDecorationV1>,
    shell_surface: Arc<Box<dyn shell::ShellSurface>>,
    inner: Rc<RefCell<Option<WindowInner<F>>>>,
    _seat_listener: crate::seat::SeatListener,
}

impl<F: Frame + 'static> Window<F> {
    /// Create a new window wrapping a given wayland surface as its main content and
    /// following the compositor's preference regarding server-side decorations
    ///
    /// It can fail if the initialization of the frame fails (for example if the
    /// frame class fails to initialize its SHM).
    ///
    /// Providing non `None` value for `theme_manager` should prevent theming pointer
    /// over the `surface`.
    fn init_with_decorations<Impl, E>(
        env: &crate::environment::Environment<E>,
        surface: wl_surface::WlSurface,
        theme_manager: Option<ThemeManager>,
        initial_dims: (u32, u32),
        implementation: Impl,
    ) -> Result<Window<F>, F::Error>
    where
        Impl: FnMut(Event, DispatchData) + 'static,
        E: GlobalHandler<wl_compositor::WlCompositor>
            + GlobalHandler<wl_subcompositor::WlSubcompositor>
            + GlobalHandler<wl_shm::WlShm>
            + crate::shell::ShellHandling
            + MultiGlobalHandler<wl_seat::WlSeat>
            + GlobalHandler<ZxdgDecorationManagerV1>
            + crate::seat::SeatHandling,
    {
        let compositor = env.require_global::<wl_compositor::WlCompositor>();
        let subcompositor = env.require_global::<wl_subcompositor::WlSubcompositor>();
        let shm = env.require_global::<wl_shm::WlShm>();
        let shell = env
            .get_shell()
            .expect("[SCTK] Cannot create a window if the compositor advertized no shell.");

        let inner = Rc::new(RefCell::new(None::<WindowInner<F>>));
        let frame_inner = inner.clone();
        let shell_inner = inner.clone();
        let mut frame = F::init(
            &surface,
            &compositor,
            &subcompositor,
            &shm,
            theme_manager,
            Box::new(move |req, serial, ddata: DispatchData| {
                if let Some(ref mut inner) = *shell_inner.borrow_mut() {
                    match req {
                        FrameRequest::Minimize => inner.shell_surface.set_minimized(),
                        FrameRequest::Maximize => inner.shell_surface.set_maximized(),
                        FrameRequest::UnMaximize => inner.shell_surface.unset_maximized(),
                        FrameRequest::Move(seat) => inner.shell_surface.move_(&seat, serial),
                        FrameRequest::Resize(seat, edges) => {
                            inner.shell_surface.resize(&seat, serial, edges)
                        }
                        FrameRequest::ShowMenu(seat, x, y) => {
                            inner.shell_surface.show_window_menu(&seat, serial, x, y)
                        }
                        FrameRequest::Close => (inner.user_impl)(Event::Close, ddata),
                        FrameRequest::Refresh => (inner.user_impl)(Event::Refresh, ddata),
                    }
                }
            }) as Box<_>,
        )?;

        let decoration_mgr = env.get_global::<ZxdgDecorationManagerV1>();
        if decoration_mgr.is_none() {
            // We don't have ServerSide decorations, so we'll be using CSD, and so should
            // mark frame as not hidden.
            frame.set_hidden(false);
        }

        frame.resize(initial_dims);
        let frame = Rc::new(RefCell::new(frame));
        let shell_surface = Arc::new(shell::create_shell_surface(
            &shell,
            &surface,
            move |event, mut ddata: DispatchData| {
                let mut frame_inner = frame_inner.borrow_mut();
                let mut inner = match frame_inner.as_mut() {
                    Some(inner) => inner,
                    None => return,
                };

                match event {
                    shell::Event::Configure { states, mut new_size } => {
                        let mut frame = inner.frame.borrow_mut();

                        // Populate frame changes. We should do it before performing new_size
                        // recalculation, since we should account for a fullscreen state.
                        let need_refresh = frame.set_states(&states);

                        // Clamp size.
                        new_size = new_size.map(|(w, h)| {
                            use std::cmp::{max, min};
                            let (mut w, mut h) = frame.subtract_borders(w as i32, h as i32);
                            let (minw, minh) = inner.min_size;
                            w = max(w, minw as i32);
                            h = max(h, minh as i32);
                            if let Some((maxw, maxh)) = inner.max_size {
                                w = min(w, maxw as i32);
                                h = min(h, maxh as i32);
                            }
                            (max(w, 1) as u32, max(h, 1) as u32)
                        });

                        // Check whether we should save old size for later restoration.
                        let should_stash_size = states
                            .iter()
                            .find(|s| {
                                matches!(
                                    *s,
                                    State::Maximized
                                        | State::Fullscreen
                                        | State::TiledTop
                                        | State::TiledRight
                                        | State::TiledBottom
                                        | State::TiledLeft
                                )
                            })
                            .map(|_| true)
                            .unwrap_or(false);

                        if should_stash_size {
                            if inner.old_size.is_none() {
                                // We are getting maximized/fullscreened, store the size for
                                // restoration.
                                inner.old_size = Some(inner.current_size);
                            }
                        } else if new_size.is_none() {
                            // We are getting de-maximized/de-fullscreened/un-tiled, restore the
                            // size, if we were not previously maximized/fullscreened, old_size is
                            // None and this does nothing.
                            new_size = inner.old_size.take();
                        } else {
                            // We are neither maximized nor fullscreened, but are given a size,
                            // respect it and forget about the old size.
                            inner.old_size = None;
                        }

                        if need_refresh {
                            (inner.user_impl)(Event::Refresh, ddata.reborrow());
                        }
                        (inner.user_impl)(Event::Configure { states, new_size }, ddata);
                    }
                    shell::Event::Close => {
                        (inner.user_impl)(Event::Close, ddata);
                    }
                }
            },
        ));

        // setup size and geometry
        {
            let frame = frame.borrow_mut();
            let (minw, minh) =
                frame.add_borders(MIN_WINDOW_SIZE.0 as i32, MIN_WINDOW_SIZE.1 as i32);
            shell_surface.set_min_size(Some((minw, minh)));
            let (w, h) = frame.add_borders(initial_dims.0 as i32, initial_dims.1 as i32);
            let (x, y) = frame.location();
            shell_surface.set_geometry(x, y, w, h);
        }

        // initial seat setup
        let mut seats = Vec::<wl_seat::WlSeat>::new();
        for seat in env.get_all_seats() {
            crate::seat::with_seat_data(&seat, |seat_data| {
                if seat_data.has_pointer && !seat_data.defunct {
                    seats.push(seat.detach());
                    frame.borrow_mut().new_seat(&seat);
                }
            });
        }

        // setup seat_listener
        let seat_frame = frame.clone();
        let seat_listener = env.listen_for_seats(move |seat, seat_data, _| {
            let is_known = seats.contains(&seat);
            if !is_known && seat_data.has_pointer && !seat_data.defunct {
                seat_frame.borrow_mut().new_seat(&seat);
                seats.push(seat.detach());
            } else if is_known && ((!seat_data.has_pointer) || seat_data.defunct) {
                seat_frame.borrow_mut().remove_seat(&seat);
                seats.retain(|s| s != &*seat);
            }
        });

        *inner.borrow_mut() = Some(WindowInner {
            frame: frame.clone(),
            shell_surface: shell_surface.clone(),
            user_impl: Box::new(implementation) as Box<_>,
            min_size: (MIN_WINDOW_SIZE.0, MIN_WINDOW_SIZE.1),
            max_size: None,
            current_size: initial_dims,
            old_size: None,
            decorated: true,
        });

        // Setup window decorations if applicable.
        let decoration = Self::setup_decorations_handler(
            &decoration_mgr,
            &shell_surface,
            frame.clone(),
            inner.clone(),
        );

        let window = Window {
            frame,
            shell_surface,
            decoration,
            surface,
            inner,
            _seat_listener: seat_listener,
        };

        Ok(window)
    }

    /// Setup handling for zxdg_toplevel_decoration_v1 in case protocol is available.
    fn setup_decorations_handler(
        decoration_mgr: &Option<Attached<ZxdgDecorationManagerV1>>,
        shell_surface: &Arc<Box<dyn shell::ShellSurface>>,
        decoration_frame: Rc<RefCell<F>>,
        decoration_inner: Rc<RefCell<Option<WindowInner<F>>>>,
    ) -> Option<ZxdgToplevelDecorationV1> {
        let (toplevel, mgr) = match (shell_surface.get_xdg(), decoration_mgr) {
            (Some(toplevel), Some(ref mgr)) => (toplevel, mgr),
            _ => {
                return None;
            }
        };

        let decoration = mgr.get_toplevel_decoration(toplevel);

        decoration.quick_assign(move |_, event, _| {
            use self::zxdg_toplevel_decoration_v1::{Event, Mode};
            let mode = if let Event::Configure { mode } = event { mode } else { unreachable!() };

            match mode {
                Mode::ServerSide => {
                    decoration_frame.borrow_mut().set_hidden(true);
                }
                Mode::ClientSide => {
                    let want_decorate = decoration_inner
                        .borrow_mut()
                        .as_ref()
                        .map(|inner| inner.decorated)
                        .unwrap_or(false);
                    decoration_frame.borrow_mut().set_hidden(!want_decorate);
                }
                _ => unreachable!(),
            }
        });

        Some(decoration.detach())
    }

    /// Access the surface wrapped in this Window
    pub fn surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }

    /// Refreshes the frame
    ///
    /// Redraws the frame to match its requested state (dimensions, presence/
    /// absence of decorations, ...)
    ///
    /// You need to call this method after every change to the dimensions or state
    /// of the decorations of your window, otherwise the drawn decorations may go
    /// out of sync with the state of your content.
    ///
    /// Your implementation will also receive `Refresh` events when the frame requests
    /// to be redrawn (to provide some frame animations for example).
    pub fn refresh(&mut self) {
        self.frame.borrow_mut().redraw();
    }

    /// Set a short title for the window.
    ///
    /// This string may be used to identify the surface in a task bar, window list, or other
    /// user interface elements provided by the compositor.
    ///
    /// You need to call `refresh()` afterwards for this to properly
    /// take effect.
    pub fn set_title(&self, mut title: String) {
        // Truncate the title to at most 1024 bytes, so that it does not blow up the protocol
        // messages
        if title.len() > 1024 {
            let mut new_len = 1024;
            while !title.is_char_boundary(new_len) {
                new_len -= 1;
            }
            title.truncate(new_len);
        }
        self.frame.borrow_mut().set_title(title.clone());
        self.shell_surface.set_title(title);
    }

    /// Set an app id for the surface.
    ///
    /// The surface class identifies the general class of applications to which the surface
    /// belongs.
    ///
    /// Several wayland compositors will try to find a `.desktop` file matching this name
    /// to find metadata about your apps.
    pub fn set_app_id(&self, app_id: String) {
        self.shell_surface.set_app_id(app_id);
    }

    /// Set whether the window should be decorated or not.
    ///
    /// If `zxdg_toplevel_decoration_v1` object is presented and alive, requesting `None`
    /// decorations will result in setting `ClientSide` decorations with hidden frame, and if
    /// `ClientSide` decorations were requested, it'll result in destroying
    /// `zxdg_toplevel_decoration_v1` object, meaning that you won't be able to get `ServerSide`
    /// decorations back.
    ///
    /// In case `zxdg_toplevel_decoration_v1` is not available or the corresponding object is not
    /// alive anymore, `decorate` with `ServerSide` or `FollowServer` values will always result in
    /// `ClientSide` decorations being used.
    ///
    /// You need to call `refresh()` afterwards for this to properly
    /// take effect.
    pub fn set_decorate(&mut self, decorate: Decorations) {
        use self::zxdg_toplevel_decoration_v1::Mode;

        // Update inner.decorated state.
        if let Some(inner) = self.inner.borrow_mut().as_mut() {
            if Decorations::None == decorate {
                inner.decorated = false;
            } else {
                inner.decorated = true;
            }
        }

        match self.decoration.as_ref() {
            // Server side decorations are there.
            Some(decoration) => {
                match decorate {
                    Decorations::ClientSide => {
                        // The user explicitly requested `ClientSide` decorations, we should destroy
                        // the server side decorations if some are presented.
                        decoration.destroy();
                        self.decoration = None;
                        self.frame.borrow_mut().set_hidden(false);
                    }
                    Decorations::ServerSide => {
                        decoration.set_mode(Mode::ServerSide);
                    }
                    Decorations::FollowServer => {
                        decoration.unset_mode();
                    }
                    Decorations::None => {
                        // The user explicitly requested `None` decorations, however
                        // since we can't destroy and recreate decoration object on the fly switch
                        // them to `ClientSide` with the hidden frame. The server is free to ignore
                        // us with such request, but not that we can do much about it.
                        decoration.set_mode(Mode::ClientSide);
                        self.frame.borrow_mut().set_hidden(true);
                    }
                }
            }
            // Server side decorations are not presented or were destroyed.
            None => {
                match decorate {
                    // We map `ServerSide` and `FollowServer` decorations to `ClientSide`, since
                    // server side decorations are no longer available.
                    Decorations::ClientSide
                    | Decorations::ServerSide
                    | Decorations::FollowServer => {
                        self.frame.borrow_mut().set_hidden(false);
                    }
                    Decorations::None => {
                        self.frame.borrow_mut().set_hidden(true);
                    }
                }
            }
        }
    }

    /// Set whether the window should be resizeable by the user
    ///
    /// This is not an hard blocking, as the compositor can always
    /// resize you forcibly if it wants. However it signals it that
    /// you don't want this window to be resized.
    ///
    /// Additionally, the decorations will stop suggesting the user
    /// to resize by dragging the borders if you set the window as
    /// non-resizable.
    ///
    /// When re-activating resizability, any previously set min/max
    /// sizes are restored.
    pub fn set_resizable(&self, resizable: bool) {
        let mut frame = self.frame.borrow_mut();
        frame.set_resizable(resizable);
        let mut inner = self.inner.borrow_mut();
        if let Some(ref mut inner) = *inner {
            if resizable {
                // restore the min/max sizes
                self.shell_surface.set_min_size(
                    Some(inner.min_size).map(|(w, h)| frame.add_borders(w as i32, h as i32)),
                );
                self.shell_surface.set_max_size(
                    inner.max_size.map(|(w, h)| frame.add_borders(w as i32, h as i32)),
                );
            } else {
                // Lock the min/max sizes to current size.
                let (w, h) = inner.current_size;
                self.shell_surface.set_min_size(Some(frame.add_borders(w as i32, h as i32)));
                self.shell_surface.set_max_size(Some(frame.add_borders(w as i32, h as i32)));
            }
        }
    }

    /// Resize the decorations
    ///
    /// You should call this whenever you change the size of the contents
    /// of your window, with the new _inner size_ of your window.
    ///
    /// This size is expressed in logical pixels, like the one received
    /// in [`Event::Configure`](enum.Event.html).
    ///
    /// You need to call `refresh()` afterwards for this to properly
    /// take effect.
    pub fn resize(&mut self, w: u32, h: u32) {
        use std::cmp::max;
        let w = max(w, 1);
        let h = max(h, 1);
        if let Some(ref mut inner) = *self.inner.borrow_mut() {
            inner.current_size = (w, h);
        }
        let mut frame = self.frame.borrow_mut();
        frame.resize((w, h));
        let (w, h) = frame.add_borders(w as i32, h as i32);
        let (x, y) = frame.location();
        self.shell_surface.set_geometry(x, y, w, h);
    }

    /// Request the window to be maximized
    pub fn set_maximized(&self) {
        self.shell_surface.set_maximized();
    }

    /// Request the window to be un-maximized
    pub fn unset_maximized(&self) {
        self.shell_surface.unset_maximized();
    }

    /// Request the window to be minimized
    pub fn set_minimized(&self) {
        self.shell_surface.set_minimized();
    }

    /// Request the window to be set fullscreen
    ///
    /// Note: The decorations hiding behavior is `Frame` dependant.
    /// To check whether you need to hide them consult your frame documentation.
    pub fn set_fullscreen(&self, output: Option<&wl_output::WlOutput>) {
        self.shell_surface.set_fullscreen(output);
    }

    /// Request the window to quit fullscreen mode
    pub fn unset_fullscreen(&self) {
        self.shell_surface.unset_fullscreen();
    }

    /// Sets the minimum possible size for this window
    ///
    /// Provide either a tuple `Some((width, height))` or `None` to unset the
    /// minimum size.
    ///
    /// Setting either value in the tuple to `0` means that this axis should not
    /// be limited.
    ///
    /// The provided size is the interior size, not counting decorations.
    ///
    /// This size is expressed in logical pixels, like the one received
    /// in [`Event::Configure`](enum.Event.html).
    pub fn set_min_size(&mut self, size: Option<(u32, u32)>) {
        let (w, h) = size.unwrap_or(MIN_WINDOW_SIZE);
        let (w, h) = self.frame.borrow_mut().add_borders(w as i32, h as i32);
        self.shell_surface.set_min_size(Some((w, h)));
        if let Some(ref mut inner) = *self.inner.borrow_mut() {
            inner.min_size = size.unwrap_or(MIN_WINDOW_SIZE)
        }
    }

    /// Sets the maximum possible size for this window
    ///
    /// Provide either a tuple `Some((width, height))` or `None` to unset the
    /// maximum size.
    ///
    /// Setting either value in the tuple to `0` means that this axis should not
    /// be limited.
    ///
    /// The provided size is the interior size, not counting decorations.
    ///
    /// This size is expressed in logical pixels, like the one received
    /// in [`Event::Configure`](enum.Event.html).
    pub fn set_max_size(&mut self, size: Option<(u32, u32)>) {
        let max_size = size.map(|(w, h)| self.frame.borrow_mut().add_borders(w as i32, h as i32));
        self.shell_surface.set_max_size(max_size);
        if let Some(ref mut inner) = *self.inner.borrow_mut() {
            inner.max_size = size.map(|(w, h)| (w as u32, h as u32));
        }
    }

    /// Sets the frame configuration for the window
    ///
    /// This allows to configure the frame at runtime if it supports
    /// it. See the documentation of your `Frame` implementation for
    /// details about what configuration it supports.
    pub fn set_frame_config(&mut self, config: F::Config) {
        self.frame.borrow_mut().set_config(config)
    }

    /// Start an interactive, user-driven move of the surface
    ///
    /// This request must be used in response to some sort of user action
    /// like a button press, key press, or touch down event. The passed
    /// serial is used to determine the type of interactive move (touch,
    /// pointer, etc).
    ///
    /// The server may ignore move requests depending on the state of
    /// the surface (e.g. fullscreen or maximized), or if the passed serial
    /// is no longer valid.
    pub fn start_interactive_move(&self, seat: &wl_seat::WlSeat, serial: u32) {
        self.shell_surface.move_(seat, serial);
    }
}

impl<F: Frame> Drop for Window<F> {
    fn drop(&mut self) {
        self.inner.borrow_mut().take();

        // Destroy decorations manager, so the inner frame could be dropped.
        if let Some(decoration) = self.decoration.take() {
            decoration.destroy();
        }
    }
}

impl<F: Frame> fmt::Debug for Window<F>
where
    F: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Window")
            .field("frame", &self.frame)
            .field("surface", &self.surface)
            .field("decoration", &self.decoration)
            .field("shell_surface", &self.shell_surface)
            .field("inner", &self.inner)
            .field("_seat_listener", &self._seat_listener)
            .finish()
    }
}

/// Request generated by a Frame
///
/// These requests are generated by a Frame and the Window will
/// forward them appropriately to the server.
#[derive(Debug)]
pub enum FrameRequest {
    /// The window should be minimized
    Minimize,
    /// The window should be maximized
    Maximize,
    /// The window should be unmaximized
    UnMaximize,
    /// The window should be closed
    Close,
    /// An interactive move should be started
    Move(wl_seat::WlSeat),
    /// An interactive resize should be started
    Resize(wl_seat::WlSeat, ResizeEdge),
    /// Show window menu.
    ShowMenu(wl_seat::WlSeat, i32, i32),
    /// The frame requests to be refreshed
    Refresh,
}

/// Interface for defining the drawing of decorations
///
/// A type implementing this trait can be used to define custom
/// decorations additionnaly to the ones provided by this crate
/// and be used with `Window`.
pub trait Frame: Sized {
    /// Type of errors that may occur when attempting to create a frame
    type Error;
    /// Configuration for this frame
    type Config;
    /// Initialize the Frame.
    ///
    /// Providing non `None` to `theme_manager` should prevent `Frame` to theme pointer
    /// over `base_surface` surface.
    fn init(
        base_surface: &wl_surface::WlSurface,
        compositor: &Attached<wl_compositor::WlCompositor>,
        subcompositor: &Attached<wl_subcompositor::WlSubcompositor>,
        shm: &Attached<wl_shm::WlShm>,
        theme_manager: Option<ThemeManager>,
        callback: Box<dyn FnMut(FrameRequest, u32, DispatchData)>,
    ) -> Result<Self, Self::Error>;
    /// Set the Window XDG states for the frame
    ///
    /// This notably includes information about whether the window is
    /// maximized, active, or tiled, and can affect the way decorations
    /// are drawn.
    ///
    /// Calling this should *not* trigger a redraw, but return `true` if
    /// a redraw is needed.
    fn set_states(&mut self, states: &[State]) -> bool;
    /// Hide or show the decorations
    ///
    /// Calling this should *not* trigger a redraw
    fn set_hidden(&mut self, hidden: bool);
    /// Set whether interactive resize hints should be displayed
    /// and reacted to
    fn set_resizable(&mut self, resizable: bool);
    /// Notify that a new wl_seat should be handled
    ///
    /// This seat is guaranteed to have pointer capability
    fn new_seat(&mut self, seat: &Attached<wl_seat::WlSeat>);
    /// Notify that this seat has lost the pointer capability or
    /// has been lost
    fn remove_seat(&mut self, seat: &wl_seat::WlSeat);
    /// Change the size of the decorations
    ///
    /// Calling this should *not* trigger a redraw
    fn resize(&mut self, newsize: (u32, u32));
    /// Redraw the decorations
    fn redraw(&mut self);
    /// Subtracts the border dimensions from the given dimensions.
    fn subtract_borders(&self, width: i32, height: i32) -> (i32, i32);
    /// Adds the border dimensions to the given dimensions.
    fn add_borders(&self, width: i32, height: i32) -> (i32, i32);
    /// Returns the coordinates of the top-left corner of the borders relative to the content
    ///
    /// Values should thus be negative
    fn location(&self) -> (i32, i32) {
        (0, 0)
    }
    /// Sets the configuration for the frame
    fn set_config(&mut self, config: Self::Config);

    /// Sets the frames title
    fn set_title(&mut self, title: String);
}

impl<E> Environment<E>
where
    E: GlobalHandler<wl_compositor::WlCompositor>
        + GlobalHandler<wl_subcompositor::WlSubcompositor>
        + GlobalHandler<wl_shm::WlShm>
        + crate::shell::ShellHandling
        + MultiGlobalHandler<wl_seat::WlSeat>
        + GlobalHandler<ZxdgDecorationManagerV1>
        + crate::seat::SeatHandling,
{
    /// Create a new window wrapping given surface
    ///
    /// This window handles decorations for you, this includes
    /// drawing them if the compositor doe snot support them, resizing interactions
    /// and moving the window. It also provides close/maximize/minimize buttons.
    ///
    /// Many interactions still require your input, and are given to you via the
    /// callback you need to provide.
    pub fn create_window<F: Frame + 'static, CB>(
        &self,
        surface: wl_surface::WlSurface,
        theme_manager: Option<ThemeManager>,
        initial_dims: (u32, u32),
        callback: CB,
    ) -> Result<Window<F>, F::Error>
    where
        CB: FnMut(Event, DispatchData) + 'static,
    {
        Window::<F>::init_with_decorations(self, surface, theme_manager, initial_dims, callback)
    }
}