druid_shell/backend/gtk/
application.rs

1// Copyright 2019 The Druid Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! GTK implementation of features at the application scope.
16
17use gtk::gio::prelude::ApplicationExtManual;
18use gtk::gio::{ApplicationFlags, Cancellable};
19use gtk::Application as GtkApplication;
20
21use gtk::prelude::{ApplicationExt, GtkApplicationExt};
22
23use crate::application::AppHandler;
24
25use super::clipboard::Clipboard;
26use super::error::Error;
27
28#[derive(Clone)]
29pub(crate) struct Application {
30    gtk_app: GtkApplication,
31}
32
33impl Application {
34    pub fn new() -> Result<Application, Error> {
35        // TODO: we should give control over the application ID to the user
36        let gtk_app = GtkApplication::new(
37            Some("com.github.linebender.druid"),
38            // TODO we set this to avoid connecting to an existing running instance
39            // of "com.github.linebender.druid" after which we would never receive
40            // the "Activate application" below. See pull request druid#384
41            // Which shows another way once we have in place a mechanism for
42            // communication with remote instances.
43            ApplicationFlags::NON_UNIQUE,
44        );
45
46        gtk_app.connect_activate(|_app| {
47            tracing::info!("gtk: Activated application");
48        });
49
50        if let Err(err) = gtk_app.register(None as Option<&Cancellable>) {
51            return Err(Error::Error(err));
52        }
53
54        Ok(Application { gtk_app })
55    }
56
57    #[inline]
58    pub fn gtk_app(&self) -> &GtkApplication {
59        &self.gtk_app
60    }
61
62    pub fn run(self, _handler: Option<Box<dyn AppHandler>>) {
63        self.gtk_app.run();
64    }
65
66    pub fn quit(&self) {
67        match self.gtk_app.active_window() {
68            None => {
69                // no application is running, main is not running
70            }
71            Some(_) => {
72                // we still have an active window, close the run loop
73                self.gtk_app.quit();
74            }
75        }
76    }
77
78    pub fn clipboard(&self) -> Clipboard {
79        Clipboard {
80            selection: gtk::gdk::SELECTION_CLIPBOARD,
81        }
82    }
83
84    pub fn get_locale() -> String {
85        let mut locale: String = gtk::glib::language_names()[0].as_str().into();
86        // This is done because the locale parsing library we use expects an unicode locale, but these vars have an ISO locale
87        if let Some(idx) = locale.chars().position(|c| c == '.' || c == '@') {
88            locale.truncate(idx);
89        }
90        locale
91    }
92}
93
94impl crate::platform::linux::ApplicationExt for crate::Application {
95    fn primary_clipboard(&self) -> crate::Clipboard {
96        crate::Clipboard(Clipboard {
97            selection: gtk::gdk::SELECTION_PRIMARY,
98        })
99    }
100}