theme: Use a matching layout theme for any widget theme
Dedicated styling is now possible for themes which have a corresponding style-theme.css file. Adwaita:dark gets one, whereas other themes use the new generic fallback theme.
This commit is contained in:
		@ -24,6 +24,7 @@ mod outputs;
 | 
			
		||||
mod popover;
 | 
			
		||||
mod resources;
 | 
			
		||||
mod submission;
 | 
			
		||||
mod style;
 | 
			
		||||
pub mod tests;
 | 
			
		||||
pub mod util;
 | 
			
		||||
mod xdg;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								src/style.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/style.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#ifndef __STYLE_H
 | 
			
		||||
#define __STYLE_H
 | 
			
		||||
#include "gtk/gtk.h"
 | 
			
		||||
 | 
			
		||||
GtkCssProvider *squeek_load_style();
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										139
									
								
								src/style.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/style.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,139 @@
 | 
			
		||||
/* 
 | 
			
		||||
 * Copyright (C) 2000 Red Hat, Inc.
 | 
			
		||||
 * Copyright (C) 2019 Purism, SPC
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*! CSS data loading */
 | 
			
		||||
 | 
			
		||||
use std::env;
 | 
			
		||||
 | 
			
		||||
use glib::object::ObjectExt;
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use gio;
 | 
			
		||||
    use gtk;
 | 
			
		||||
    use gtk_sys;
 | 
			
		||||
    
 | 
			
		||||
    use gtk::CssProviderExt;
 | 
			
		||||
    use glib::translate::ToGlibPtr;
 | 
			
		||||
 | 
			
		||||
    /// Loads the layout style based on current theme
 | 
			
		||||
    /// without having to worry about string allocation
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_load_style() -> *const gtk_sys::GtkCssProvider {
 | 
			
		||||
        unsafe { gtk::set_initialized() };
 | 
			
		||||
        let theme = gtk::Settings::get_default()
 | 
			
		||||
            .map(|settings| get_theme_name(&settings));
 | 
			
		||||
        
 | 
			
		||||
        let css_name = path_from_theme(theme);
 | 
			
		||||
 | 
			
		||||
        let resource_name = if gio::resources_get_info(
 | 
			
		||||
            &css_name,
 | 
			
		||||
            gio::ResourceLookupFlags::NONE
 | 
			
		||||
        ).is_ok() {
 | 
			
		||||
            css_name
 | 
			
		||||
        } else { // use default if this path doesn't exist
 | 
			
		||||
            path_from_theme(None)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let provider = gtk::CssProvider::new();
 | 
			
		||||
        provider.load_from_resource(&resource_name);
 | 
			
		||||
        provider.to_glib_full()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// not Adwaita, but rather fall back to default
 | 
			
		||||
const DEFAULT_THEME_NAME: &str = "";
 | 
			
		||||
 | 
			
		||||
/// Sugar for logging errors in results
 | 
			
		||||
trait Warn {
 | 
			
		||||
    type Value;
 | 
			
		||||
    fn ok_warn(self, msg: &str) -> Option<Self::Value>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T, E: std::error::Error> Warn for Result<T, E> {
 | 
			
		||||
    type Value = T;
 | 
			
		||||
    fn ok_warn(self, msg: &str) -> Option<T> {
 | 
			
		||||
        self.map_err(|e| {
 | 
			
		||||
            eprintln!("{}: {}", msg, e);
 | 
			
		||||
            e
 | 
			
		||||
        }).ok()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct GtkTheme {
 | 
			
		||||
    name: String,
 | 
			
		||||
    variant: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Gets theme as determined by the toolkit
 | 
			
		||||
/// Ported from GTK's gtksettings.c
 | 
			
		||||
fn get_theme_name(settings: >k::Settings) -> GtkTheme {
 | 
			
		||||
    let env_theme = env::var("GTK_THEME")
 | 
			
		||||
        .map(|theme| {
 | 
			
		||||
            let mut parts = theme.splitn(2, ":");
 | 
			
		||||
            GtkTheme {
 | 
			
		||||
                // guaranteed at least empty string
 | 
			
		||||
                // as the first result from splitting a string
 | 
			
		||||
                name: parts.next().unwrap().into(),
 | 
			
		||||
                variant: parts.next().map(String::from)
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            match &e {
 | 
			
		||||
                env::VarError::NotPresent => {},
 | 
			
		||||
                e => eprintln!("GTK_THEME variable invalid: {}", e),
 | 
			
		||||
            };
 | 
			
		||||
            e
 | 
			
		||||
        }).ok();
 | 
			
		||||
 | 
			
		||||
    match env_theme {
 | 
			
		||||
        Some(theme) => theme,
 | 
			
		||||
        None => GtkTheme {
 | 
			
		||||
            name: {
 | 
			
		||||
                settings.get_property("gtk-theme-name")
 | 
			
		||||
                    .ok_warn("No theme name")
 | 
			
		||||
                    .and_then(|value| value.get::<String>())
 | 
			
		||||
                    .unwrap_or(DEFAULT_THEME_NAME.into())
 | 
			
		||||
            },
 | 
			
		||||
            variant: {
 | 
			
		||||
                settings.get_property("gtk-application-prefer-dark-theme")
 | 
			
		||||
                    .ok_warn("No settings key")
 | 
			
		||||
                    .and_then(|value| value.get::<bool>())
 | 
			
		||||
                    .and_then(|dark_preferred| match dark_preferred {
 | 
			
		||||
                        true => Some("dark".into()),
 | 
			
		||||
                        false => None,
 | 
			
		||||
                    })
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn path_from_theme(theme: Option<GtkTheme>) -> String {
 | 
			
		||||
    format!(
 | 
			
		||||
        "/sm/puri/squeekboard/style{}.css",
 | 
			
		||||
        match theme {
 | 
			
		||||
            Some(GtkTheme { name, variant: Some(variant) }) => {
 | 
			
		||||
                format!("-{}:{}", name, variant)
 | 
			
		||||
            },
 | 
			
		||||
            Some(GtkTheme { name, variant: None }) => format!("-{}", name),
 | 
			
		||||
            None => "".into(),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user