use super::types::{LinuxHandleKind, LinuxPlatform};
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
use crate::core::MutexExt;
use crate::platform::{DropEvent, WidgetTriggerEvent, WidgetTriggerKind};
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
use gtk::prelude::*;
impl LinuxPlatform {
pub(crate) fn show_widget_impl(&self, widget_id: u64) {
self.state.set_visible(widget_id, true);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let native = self.native.lock_guard();
if let Some(window) = native.windows.get(&widget_id) {
window.show_all();
return;
}
if let Some(widget) = native.widgets.get(&widget_id) {
widget.show();
}
}
}
pub(crate) fn hide_widget_impl(&self, widget_id: u64) {
self.state.set_visible(widget_id, false);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let native = self.native.lock_guard();
if let Some(window) = native.windows.get(&widget_id) {
window.hide();
return;
}
if let Some(widget) = native.widgets.get(&widget_id) {
widget.hide();
}
}
}
pub(crate) fn set_widget_geometry_impl(
&self,
widget_id: u64,
x: i32,
y: i32,
width: u32,
height: u32,
) {
self.state.set_geometry(widget_id, x, y, width, height);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let parent_id = {
let menus = self.menus.lock().expect("linux menu lock poisoned");
menus.widget_parent.get(&widget_id).copied()
};
let native = self.native.lock_guard();
if let Some(window) = native.windows.get(&widget_id) {
window.move_(x, y);
window.resize(width as i32, height as i32);
return;
}
if let Some(widget) = native.widgets.get(&widget_id) {
widget.set_size_request(width as i32, height as i32);
if let Some(parent_id) = parent_id {
if let Some(container) = native.content_fixed.get(&parent_id) {
container.move_(widget, x, y);
}
}
}
}
}
pub(crate) fn set_widget_text_impl(&self, widget_id: u64, text: &str) {
if !self.state.set_text(widget_id, text) {
return;
}
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let native = self.native.lock_guard();
if let Some(window) = native.windows.get(&widget_id) {
window.set_title(text);
} else if let Some(widget) = native.widgets.get(&widget_id) {
if let Ok(menu_item) = widget.clone().downcast::<gtk::MenuItem>() {
menu_item.set_label(text);
} else if let Ok(spin) = widget.clone().downcast::<gtk::SpinButton>() {
if let Ok(value) = text.trim().parse::<f64>() {
spin.set_value(value);
}
} else if let Ok(check) = widget.clone().downcast::<gtk::CheckButton>() {
check.set_label(text);
} else if let Ok(radio) = widget.clone().downcast::<gtk::RadioButton>() {
radio.set_label(text);
} else if let Ok(button) = widget.clone().downcast::<gtk::Button>() {
button.set_label(text);
} else if let Ok(entry) = widget.clone().downcast::<gtk::Entry>() {
entry.set_text(text);
} else if let Ok(label) = widget.clone().downcast::<gtk::Label>() {
label.set_text(text);
} else if let Ok(frame) = widget.clone().downcast::<gtk::Frame>() {
frame.set_label(Some(text));
} else if let Ok(progress) = widget.clone().downcast::<gtk::ProgressBar>() {
if let Ok(value) = text.trim().parse::<f64>() {
progress.set_fraction(value.clamp(0.0, 1.0));
} else {
progress.set_show_text(true);
progress.set_text(Some(text));
}
}
}
}
if matches!(self.kind_of(widget_id), Some(LinuxHandleKind::LineEdit)) {
self.menus
.lock()
.expect("linux menu lock poisoned")
.pending_widget_events
.push_back(WidgetTriggerEvent { widget_id, kind: WidgetTriggerKind::ValueChanged });
}
}
pub(crate) fn get_widget_text_impl(&self, widget_id: u64) -> String {
self.state.text(widget_id)
}
pub(crate) fn set_widget_enabled_impl(&self, widget_id: u64, enabled: bool) {
self.state.set_enabled(widget_id, enabled);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let native = self.native.lock_guard();
if let Some(widget) = native.widgets.get(&widget_id) {
widget.set_sensitive(enabled);
}
}
}
pub(crate) fn is_widget_enabled_impl(&self, widget_id: u64) -> bool {
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let native = self.native.lock_guard();
if let Some(widget) = native.widgets.get(&widget_id) {
return widget.is_sensitive();
}
}
self.state.enabled(widget_id)
}
pub(crate) fn set_widget_visible_impl(&self, widget_id: u64, visible: bool) {
self.state.set_visible(widget_id, visible);
if visible {
self.show_widget_impl(widget_id);
} else {
self.hide_widget_impl(widget_id);
}
}
pub(crate) fn is_widget_visible_impl(&self, widget_id: u64) -> bool {
self.state.visible(widget_id)
}
pub(crate) fn set_widget_ime_enabled_impl(&self, widget_id: u64, enabled: bool) -> bool {
self.state.set_ime_enabled(widget_id, enabled)
}
pub(crate) fn is_widget_ime_enabled_impl(&self, widget_id: u64) -> bool {
self.state.ime_enabled(widget_id)
}
pub(crate) fn set_widget_accessibility_name_impl(&self, widget_id: u64, name: &str) -> bool {
if !self.state.set_accessibility_name(widget_id, name) {
return false;
}
#[cfg(target_os = "linux")]
if let Some(bridge) = crate::platform::Platform::accessibility_bridge(self) {
bridge.set_accessibility_name(widget_id, name);
bridge.notify_name_changed(widget_id);
}
true
}
pub(crate) fn get_widget_accessibility_name_impl(&self, widget_id: u64) -> String {
#[cfg(target_os = "linux")]
if let Some(bridge) = crate::platform::Platform::accessibility_bridge(self) {
if let Some(name) = bridge.accessibility_name(widget_id) {
return name;
}
}
self.state.accessibility_name(widget_id)
}
pub(crate) fn set_clipboard_text_impl(&self, text: &str) -> bool {
let stored = self.state.set_clipboard_text(text);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
if let Some(clipboard) = gtk_clipboard() {
clipboard.set_text(text);
clipboard.store();
return true;
}
}
stored
}
pub(crate) fn get_clipboard_text_impl(&self) -> String {
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
if let Some(clipboard) = gtk_clipboard() {
if let Some(text) = clipboard.wait_for_text() {
let text = text.to_string();
self.state.set_clipboard_text(&text);
return text;
}
}
}
self.state.clipboard_text()
}
pub(crate) fn begin_drag_impl(
&self,
source_widget_id: u64,
mime: &str,
payload: &[u8],
) -> bool {
self.state.begin_drag(source_widget_id, mime, payload)
}
pub(crate) fn poll_drop_event_impl(&self) -> Option<DropEvent> {
self.state.pop_drop_event()
}
pub(crate) fn inject_drop_event_impl(&self, event: DropEvent) -> bool {
self.state.inject_drop_event(event)
}
pub(crate) fn create_message_box_impl(
&self,
parent: u64,
title: &str,
text: &str,
x: i32,
y: i32,
width: u32,
height: u32,
) -> u64 {
let id = self.insert_widget(
LinuxHandleKind::MessageBox,
&format!("{}: {}", title, text),
x,
y,
width,
height,
);
self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let parent_window = self.native_parent_window(parent);
let dialog = gtk::MessageDialog::new(
parent_window.as_ref(),
gtk::DialogFlags::MODAL,
gtk::MessageType::Info,
gtk::ButtonsType::Ok,
text,
);
dialog.set_title(title);
dialog.set_default_size(width as i32, height as i32);
dialog.connect_response(|dialog, _| {
dialog.close();
});
let mut native = self.native.lock_guard();
native.widgets.insert(id, dialog.clone().upcast::<gtk::Widget>());
native.dialogs.insert(id, dialog.upcast::<gtk::Dialog>());
}
id
}
pub(crate) fn create_file_dialog_impl(
&self,
parent: u64,
x: i32,
y: i32,
width: u32,
height: u32,
) -> u64 {
let id = self.insert_widget(LinuxHandleKind::FileDialog, "FileDialog", x, y, width, height);
self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let parent_window = self.native_parent_window(parent);
let dialog = gtk::FileChooserDialog::new(
Some("File"),
parent_window.as_ref(),
gtk::FileChooserAction::Open,
);
dialog.add_buttons(&[
("Cancel", gtk::ResponseType::Cancel),
("Open", gtk::ResponseType::Accept),
]);
dialog.set_default_size(width as i32, height as i32);
let mut native = self.native.lock_guard();
native.widgets.insert(id, dialog.clone().upcast::<gtk::Widget>());
native.dialogs.insert(id, dialog.upcast::<gtk::Dialog>());
}
id
}
pub(crate) fn create_color_dialog_impl(
&self,
parent: u64,
x: i32,
y: i32,
width: u32,
height: u32,
) -> u64 {
let id =
self.insert_widget(LinuxHandleKind::ColorDialog, "ColorDialog", x, y, width, height);
self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let parent_window = self.native_parent_window(parent);
let dialog = gtk::ColorChooserDialog::new(Some("Color"), parent_window.as_ref());
dialog.set_default_size(width as i32, height as i32);
let mut native = self.native.lock_guard();
native.widgets.insert(id, dialog.clone().upcast::<gtk::Widget>());
native.color_choosers.insert(id, dialog.clone().upcast::<gtk::ColorChooser>());
native.dialogs.insert(id, dialog.upcast::<gtk::Dialog>());
}
id
}
pub(crate) fn create_font_dialog_impl(
&self,
parent: u64,
x: i32,
y: i32,
width: u32,
height: u32,
) -> u64 {
let id = self.insert_widget(LinuxHandleKind::FontDialog, "FontDialog", x, y, width, height);
self.menus.lock().expect("linux menu lock poisoned").widget_parent.insert(id, parent);
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
let parent_window = self.native_parent_window(parent);
let dialog = gtk::FontChooserDialog::new(Some("Font"), parent_window.as_ref());
dialog.set_default_size(width as i32, height as i32);
let mut native = self.native.lock_guard();
native.widgets.insert(id, dialog.clone().upcast::<gtk::Widget>());
native.font_choosers.insert(id, dialog.clone().upcast::<gtk::FontChooser>());
native.dialogs.insert(id, dialog.upcast::<gtk::Dialog>());
}
id
}
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
pub(crate) fn native_parent_window(&self, parent: u64) -> Option<gtk::Window> {
let native = self.native.lock_guard();
native.windows.get(&parent).cloned()
}
}
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
fn gtk_clipboard() -> Option<gtk::Clipboard> {
if !gtk::is_initialized_main_thread() {
return None;
}
let display = gtk::gdk::Display::default()?;
gtk::Clipboard::default(&display)
}