nativeshell/shell/platform/linux/
size_widget.rs

1use std::{cmp::max, ffi::CString, mem, ptr};
2
3use glib::{
4    translate::{FromGlibPtrFull, FromGlibPtrNone},
5    ObjectExt,
6};
7use gtk::{prelude::WidgetExt, Widget};
8
9unsafe extern "C" fn class_init(class: glib_sys::gpointer, _class_data: glib_sys::gpointer) {
10    let widget_class = class as *mut gtk_sys::GtkWidgetClass;
11    let widget_class = &mut *widget_class;
12    widget_class.get_preferred_width = Some(get_preferred_width);
13    widget_class.get_preferred_height = Some(get_preferred_height);
14}
15
16unsafe extern "C" fn instance_init(
17    _instance: *mut gobject_sys::GTypeInstance,
18    _instance_data: glib_sys::gpointer,
19) {
20}
21
22fn size_widget_get_type() -> glib_sys::GType {
23    static ONCE: ::std::sync::Once = ::std::sync::Once::new();
24
25    static mut TYPE: glib_sys::GType = 0;
26
27    ONCE.call_once(|| unsafe {
28        let name = CString::new("NativeShellSizeWidget").unwrap();
29        TYPE = gobject_sys::g_type_register_static_simple(
30            gtk_sys::gtk_bin_get_type(),
31            name.as_ptr(),
32            mem::size_of::<gtk_sys::GtkBinClass>() as u32,
33            Some(class_init),
34            mem::size_of::<gtk_sys::GtkBin>() as u32,
35            Some(instance_init),
36            0,
37        );
38    });
39
40    unsafe { TYPE }
41}
42
43unsafe extern "C" fn get_preferred_width(
44    widget: *mut gtk_sys::GtkWidget,
45    minimum: *mut i32,
46    natural: *mut i32,
47) {
48    let widget = Widget::from_glib_none(widget);
49    let width: Option<ptr::NonNull<i32>> = widget.data("nativeshell_minimum_width");
50    if let Some(width) = width.map(|w| *w.as_ref()) {
51        *minimum = max(width, 1);
52        *natural = max(width, 1);
53    } else {
54        *minimum = 1;
55        *natural = 1;
56    }
57}
58
59unsafe extern "C" fn get_preferred_height(
60    widget: *mut gtk_sys::GtkWidget,
61    minimum: *mut i32,
62    natural: *mut i32,
63) {
64    let widget = Widget::from_glib_none(widget);
65    let height: Option<ptr::NonNull<i32>> = widget.data("nativeshell_minimum_height");
66    if let Some(height) = height.map(|h| *h.as_ref()) {
67        *minimum = max(height, 1);
68        *natural = max(height, 1);
69    } else {
70        *minimum = 1;
71        *natural = 1;
72    }
73}
74
75pub(super) fn create_size_widget() -> gtk::Widget {
76    unsafe {
77        let instance = gobject_sys::g_object_new(size_widget_get_type(), std::ptr::null_mut());
78        gobject_sys::g_object_ref_sink(instance);
79        gtk::Widget::from_glib_full(instance as *mut _)
80    }
81}
82
83pub(super) fn size_widget_set_min_size(widget: &gtk::Widget, width: i32, height: i32) {
84    unsafe {
85        widget.set_data("nativeshell_minimum_width", width);
86        widget.set_data("nativeshell_minimum_height", height);
87    }
88    widget.queue_resize();
89}