layershellev 0.15.1

extra shell binding for layershell with winit like eventloop
Documentation
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
use wayland_protocols_wlr::layer_shell::v1::client::{
    zwlr_layer_shell_v1::Layer,
    zwlr_layer_surface_v1::{Anchor, KeyboardInteractivity},
};

use wayland_client::{
    QueueHandle, WEnum,
    globals::GlobalList,
    protocol::{
        wl_buffer::WlBuffer,
        wl_compositor::WlCompositor,
        wl_output::{self, WlOutput},
        wl_pointer::{self, ButtonState, WlPointer},
        wl_shm::WlShm,
    },
};

use crate::{id, xkb_keyboard::KeyEvent};

use crate::keyboard::ModifiersState;

use super::WindowState;

use crate::id::Id;

use std::{fmt::Debug, fs::File};

/// tell program what event is happened
///
/// InitRequest will tell the program is inited, you can request to Bind other wayland-protocols
/// there, with return [ReturnData::RequestBind]
///
/// RequestBuffer request to get the wl-buffer, so you init a buffer_pool here. It return a
/// GlobalList and a QueueHandle. This will enough for bind a extra wayland-protocol, and also,
/// seat can be gotten directly from [WindowState]
///
/// RequestMessages store the DispatchMessage, you can know what happened during dispatch with this
/// event.
pub enum LayerShellEvent<'a, T, Message> {
    /// the first event when start a new gui, program. you can return [ReturnData::None] or
    /// [ReturnData::RequestBind], then it will continue to the next request.
    /// Here only the above two [ReturnData] are acceptable.
    InitRequest,
    /// if the info of the XdgOutput is changed, it will send the event
    XdgInfoChanged(XdgInfoChangedType),
    /// After you return [ReturnData::RequestBind] in the [LayerShellEvent::InitRequest] stage, next
    /// event is [LayerShellEvent::BindProvide], you can use the GlobalList and QueueHandle to create
    /// new wayland objects.
    BindProvide(&'a GlobalList, &'a QueueHandle<WindowState<T>>),
    /// After you return [ReturnData::RequestCompositor] in the init stage, next
    /// event is [LayerShellEvent::CompositorProvide], you can use the WlCompositor and QueueHandle to
    /// create new wayland objects.
    CompositorProvide(&'a WlCompositor, &'a QueueHandle<WindowState<T>>),
    /// create a new buffer after request. if you use display_handle, you do not need to care about
    /// it.
    RequestBuffer(
        &'a mut File,
        &'a WlShm,
        &'a QueueHandle<WindowState<T>>,
        u32,
        u32,
    ),
    /// Some thing KeyboardEvent, TouchEvent, MouseEvent and etc.
    RequestMessages(&'a DispatchMessage),
    /// Nothing happened, you can do some other things after it, like to refresh the ui, and etc.
    NormalDispatch,
    /// It return the event you passed with message_receiver, and return it back.
    UserEvent(Message),
}

/// Define the output for new layershell
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum OutputOption {
    LastOutput,

    OutputName(String),

    /// NOTE: The output should be in the same connection with the layershellev, that means if you
    /// want to pass a [wl_output::WlOutput] to create a new layershell, you need to pass your
    /// connection to layershellev first
    Output(wl_output::WlOutput),
    #[default]
    None,
}

/// layershell settings to create a new layershell surface
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NewLayerShellSettings {
    /// the size of the layershell, optional.
    pub size: Option<(u32, u32)>,
    pub layer: Layer,
    pub anchor: Anchor,
    pub exclusive_zone: Option<i32>,
    pub margin: Option<(i32, i32, i32, i32)>,
    pub keyboard_interactivity: KeyboardInteractivity,
    /// follow the last output of the activated surface, used to create some thing like mako, who
    /// will show on the same window, only when the notifications is cleared, it will change the
    /// wl_output.
    pub output_option: OutputOption,
    pub events_transparent: bool,
    pub namespace: Option<String>,
}

/// be used to create a new popup
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct NewPopUpSettings {
    /// the size of the popup
    pub size: (u32, u32),
    /// the position of the popup, relative to the he layersurface
    pub position: (i32, i32),
    /// It means where the popup is, on which surface. It is the id of that layershell
    pub id: id::Id,
}
/// be used to create a new popup
#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct NewXdgWindowSettings {
    /// the size of the popup
    pub title: Option<String>,
    pub size: Option<(u32, u32)>,
}

/// input panel settings to create a new input panel surface
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NewInputPanelSettings {
    pub size: (u32, u32),
    /// set the surface type as a keyboard
    pub keyboard: bool,
    /// follow the last output of the activated surface, used to create some thing like mako, who
    /// will show on the same window, only when the notifications is cleared, it will change the
    /// wl_output.
    pub use_last_output: bool,
}

impl Default for NewLayerShellSettings {
    fn default() -> Self {
        NewLayerShellSettings {
            anchor: Anchor::Bottom | Anchor::Left | Anchor::Right,
            layer: Layer::Top,
            exclusive_zone: None,
            size: None,
            margin: Some((0, 0, 0, 0)),
            keyboard_interactivity: KeyboardInteractivity::OnDemand,
            output_option: OutputOption::None,
            events_transparent: false,
            namespace: None,
        }
    }
}

/// the return data
/// Note: when event is RequestBuffer, you must return WlBuffer
/// Note: when receive InitRequest, you can request to bind extra wayland-protocols. this time you
/// can bind virtual-keyboard. you can take startcolorkeyboard as reference, or the simple.rs. Also,
/// it should can bind with text-input, but I am not fully understand about this, maybe someone
/// familiar with it can do
///
/// When send RequestExit, it will tell the event to finish.
///
/// When send RequestSetCursorShape, you can set current pointer shape. please take
/// [cursor-shape](https://wayland.app/protocols/cursor-shape-v1#wp_cursor_shape_device_v1:enum:shape) as reference.
///
/// None means nothing will happened, no request, and no return data
#[derive(Debug, PartialEq, Eq)]
pub enum ReturnData<INFO> {
    WlBuffer(WlBuffer),
    RequestBind,
    RequestExit,
    RequestCompositor,
    RedrawAllRequest,
    RedrawIndexRequest(Id),
    RequestSetCursorShape((String, WlPointer)),
    NewLayerShell((NewLayerShellSettings, id::Id, Option<INFO>)),
    NewPopUp((NewPopUpSettings, id::Id, Option<INFO>)),
    NewXdgBase((NewXdgWindowSettings, id::Id, Option<INFO>)),
    NewInputPanel((NewInputPanelSettings, id::Id, Option<INFO>)),
    None,
}

/// this tell the what kind of information passed by [LayerShellEvent::XdgInfoChanged]
#[derive(Debug, Clone, Copy)]
pub enum XdgInfoChangedType {
    Position,
    Size,
    Name,
    Description,
}

/// Describes a scroll along one axis
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct AxisScroll {
    /// The scroll measured in pixels.
    pub absolute: f64,

    /// The scroll measured in steps.
    ///
    /// Note: this might always be zero if the scrolling is due to a touchpad or other continuous
    /// source.
    pub discrete: i32,

    /// The scroll was stopped.
    ///
    /// Generally this is encountered when hardware indicates the end of some continuous scrolling.
    pub stop: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Ime {
    /// Notifies when the IME was enabled.
    ///
    /// After getting this event you could receive [`Preedit`][Self::Preedit] and
    /// [`Commit`][Self::Commit] events. You should also start performing IME related requests
    Enabled,

    /// Notifies when a new composing text should be set at the cursor position.
    ///
    /// The value represents a pair of the preedit string and the cursor begin position and end
    /// position. When it's `None`, the cursor should be hidden. When `String` is an empty string
    /// this indicates that preedit was cleared.
    ///
    /// The cursor position is byte-wise indexed.
    Preedit(String, Option<(usize, usize)>),

    /// Notifies when text should be inserted into the editor widget.
    ///
    /// Right before this event winit will send empty [`Self::Preedit`] event.
    Commit(String),

    /// Notifies when the IME was disabled.
    ///
    /// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or
    /// [`Commit`][Self::Commit] events until the next [`Enabled`][Self::Enabled] event. You should
    /// also stop issuing IME related requests and clear
    /// pending preedit text.
    Disabled,
}

#[allow(unused)]
#[derive(Debug, Clone)]
pub(crate) enum DispatchMessageInner {
    NewDisplay(WlOutput),
    MouseButton {
        state: WEnum<ButtonState>,
        serial: u32,
        button: u32,
        time: u32,
    },
    MouseLeave,
    MouseEnter {
        pointer: WlPointer,
        serial: u32,
        surface_x: f64,
        surface_y: f64,
    },
    MouseMotion {
        time: u32,
        surface_x: f64,
        surface_y: f64,
    },
    Axis {
        time: u32,
        scale: f64,
        horizontal: AxisScroll,
        vertical: AxisScroll,
        source: Option<wl_pointer::AxisSource>,
    },
    TouchDown {
        serial: u32,
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    TouchUp {
        serial: u32,
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    TouchMotion {
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    TouchCancel {
        id: i32,
        x: f64,
        y: f64,
    },

    ModifiersChanged(ModifiersState),
    Focused(Id),
    Unfocus,
    KeyboardInput {
        event: KeyEvent,

        /// If `true`, the event was generated synthetically by winit
        /// in one of the following circumstances:
        ///
        /// * Synthetic key press events are generated for all keys pressed when a window gains
        ///   focus. Likewise, synthetic key release events are generated for all keys pressed when
        ///   a window goes out of focus. ***Currently, this is only functional on X11 and
        ///   Windows***
        ///
        /// Otherwise, this value is always `false`.
        is_synthetic: bool,
    },
    PreferredScale {
        scale_u32: u32,
        scale_float: f64,
    },
    XdgInfoChanged(XdgInfoChangedType),
    Ime(Ime),
}

/// This tell the DispatchMessage by dispatch
#[derive(Debug)]
pub enum DispatchMessage {
    /// forward the event of wayland-mouse
    MouseButton {
        state: WEnum<ButtonState>,
        serial: u32,
        button: u32,
        time: u32,
    },
    /// Mouse leave the surface
    MouseLeave,
    /// forward the event of wayland-mouse
    MouseEnter {
        pointer: WlPointer,
        serial: u32,
        surface_x: f64,
        surface_y: f64,
    },
    /// forward the event of wayland-mouse
    MouseMotion {
        time: u32,
        surface_x: f64,
        surface_y: f64,
    },
    /// About the scroll
    Axis {
        time: u32,
        scale: f64,
        horizontal: AxisScroll,
        vertical: AxisScroll,
        source: Option<wl_pointer::AxisSource>,
    },
    /// forward the event of wayland-touch
    TouchDown {
        serial: u32,
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    /// forward the event of wayland-touch
    TouchUp {
        serial: u32,
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    /// forward the event of wayland-touch
    TouchMotion {
        time: u32,
        id: i32,
        x: f64,
        y: f64,
    },
    /// TouchEvent is cancelled
    TouchCancel {
        id: i32,
        x: f64,
        y: f64,
    },
    Focused(Id),
    Unfocus,
    /// Keyboard ModifiersChanged.
    ModifiersChanged(ModifiersState),
    /// Keyboard Event about input.
    KeyboardInput {
        event: KeyEvent,

        /// If `true`, the event was generated synthetically by winit
        /// in one of the following circumstances:
        ///
        /// * Synthetic key press events are generated for all keys pressed when a window gains
        ///   focus. Likewise, synthetic key release events are generated for all keys pressed when
        ///   a window goes out of focus. ***Currently, this is only functional on X11 and
        ///   Windows***
        ///
        /// Otherwise, this value is always `false`.
        is_synthetic: bool,
    },
    /// this will request to do refresh the whole screen, because the layershell tell that a new
    /// configure happened
    RequestRefresh {
        width: u32,
        height: u32,
        scale_float: f64,
        is_created: bool,
    },
    /// fractal scale handle
    PreferredScale {
        scale_u32: u32,
        scale_float: f64,
    },
    Ime(Ime),
    Closed,
}

impl From<DispatchMessageInner> for DispatchMessage {
    fn from(val: DispatchMessageInner) -> Self {
        match val {
            DispatchMessageInner::NewDisplay(_) => unimplemented!(),
            DispatchMessageInner::MouseButton {
                state,
                serial,
                button,
                time,
            } => DispatchMessage::MouseButton {
                state,
                serial,
                button,
                time,
            },
            DispatchMessageInner::MouseLeave => DispatchMessage::MouseLeave,
            DispatchMessageInner::MouseEnter {
                pointer,
                serial,
                surface_x,
                surface_y,
            } => DispatchMessage::MouseEnter {
                pointer,
                serial,
                surface_x,
                surface_y,
            },
            DispatchMessageInner::MouseMotion {
                time,
                surface_x,
                surface_y,
            } => DispatchMessage::MouseMotion {
                time,
                surface_x,
                surface_y,
            },
            DispatchMessageInner::TouchDown {
                serial,
                time,
                id,
                x,
                y,
            } => DispatchMessage::TouchDown {
                serial,
                time,
                id,
                x,
                y,
            },
            DispatchMessageInner::TouchUp {
                serial,
                time,
                id,
                x,
                y,
            } => DispatchMessage::TouchUp {
                serial,
                time,
                id,
                x,
                y,
            },
            DispatchMessageInner::TouchMotion { time, id, x, y } => {
                DispatchMessage::TouchMotion { time, id, x, y }
            }
            DispatchMessageInner::TouchCancel { id, x, y } => {
                DispatchMessage::TouchCancel { id, x, y }
            }
            DispatchMessageInner::Axis {
                time,
                scale,
                horizontal,
                vertical,
                source,
            } => DispatchMessage::Axis {
                time,
                scale,
                horizontal,
                vertical,
                source,
            },
            DispatchMessageInner::Focused(id) => DispatchMessage::Focused(id),
            DispatchMessageInner::Unfocus => DispatchMessage::Unfocus,
            DispatchMessageInner::ModifiersChanged(modifier) => {
                DispatchMessage::ModifiersChanged(modifier)
            }
            DispatchMessageInner::KeyboardInput {
                event,
                is_synthetic,
            } => DispatchMessage::KeyboardInput {
                event,
                is_synthetic,
            },
            DispatchMessageInner::PreferredScale {
                scale_u32,
                scale_float,
            } => DispatchMessage::PreferredScale {
                scale_u32,
                scale_float,
            },
            DispatchMessageInner::Ime(ime) => DispatchMessage::Ime(ime),
            DispatchMessageInner::XdgInfoChanged(_) => unimplemented!(),
        }
    }
}