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}