Skip to content

Commit

Permalink
wf-panel: hot-reload css (#240)
Browse files Browse the repository at this point in the history
* wf-shell-app: create user css directory
wf-shell-app: watch user css directory for changes
wf-panel: on css file change load changes to css

* uncrustify

* uncrustify

* panel: populate default css on first run
panel: build default css to prefix

* uncrustify
  • Loading branch information
trigg authored Apr 22, 2024
1 parent 9a30c24 commit 5e6898d
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 13 deletions.
9 changes: 9 additions & 0 deletions data/css/default.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.wf-panel .launcher image {
transition: 500ms linear;
-gtk-icon-transform: scale(0.8);
}

.wf-panel .launcher:hover image {
transition: 500ms linear;
-gtk-icon-transform: scale(1.2);
}
1 change: 1 addition & 0 deletions data/css/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
install_data('default.css', install_dir: join_paths(resource_dir, 'css'))
2 changes: 2 additions & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ install_data(join_paths('icons', '192x192', 'wayfire.png'), install_dir: join_pa
install_data(join_paths('icons', '256x256', 'wayfire.png'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '256x256', 'apps'))
install_data(join_paths('icons', '512x512', 'wayfire.png'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', '512x512', 'apps'))
install_data(join_paths('icons', 'scalable', 'wayfire.svg'), install_dir: join_paths(get_option('prefix'), 'share', 'icons', 'hicolor', 'scalable', 'apps'))

subdir('css')
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ sysconf_dir = join_paths(get_option('prefix'), get_option('sysconfdir'))

icon_dir = join_paths(get_option('prefix'), 'share', 'wayfire', 'icons')
add_project_arguments('-DICONDIR="' + icon_dir + '"', language : 'cpp')
add_project_arguments('-DRESOURCEDIR="' + resource_dir + '"', language : 'cpp')
add_project_arguments('-DMETADATA_DIR="' + metadata_dir + '"', language : 'cpp')
add_project_arguments('-DSYSCONF_DIR="' + sysconf_dir + '"', language : 'cpp')

Expand Down
64 changes: 51 additions & 13 deletions src/panel/panel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sstream>

#include <map>
#include <filesystem>

#include "panel.hpp"
#include "../util/gtk-utils.hpp"
Expand Down Expand Up @@ -103,7 +104,6 @@ class WayfirePanel::impl
};

WfOption<int> minimal_panel_height{"panel/minimal_height"};
WfOption<std::string> css_path{"panel/css_path"};

void create_window()
{
Expand All @@ -119,18 +119,6 @@ class WayfirePanel::impl
bg_color.set_callback(on_window_color_updated);
on_window_color_updated(); // set initial color

if ((std::string)css_path != "")
{
auto css = load_css_from_path(css_path);
if (css)
{
auto screen = Gdk::Screen::get_default();
auto style_context = Gtk::StyleContext::create();
style_context->add_provider_for_screen(
screen, css, GTK_STYLE_PROVIDER_PRIORITY_USER);
}
}

window->show_all();
init_widgets();
init_layout();
Expand Down Expand Up @@ -390,6 +378,56 @@ void WayfirePanelApp::on_config_reload()
}
}

void WayfirePanelApp::on_css_reload()
{
clear_css_rules();
/* Add user directory */
std::string ext(".css");
for (auto & p : std::filesystem::directory_iterator(get_css_config_dir()))
{
if (p.path().extension() == ext)
{
add_css_file(p.path().string());
}
}

/* Add one user file */
auto custom_css_config = WfOption<std::string>{"panel/css_path"};
std::string custom_css = custom_css_config;
if (custom_css != "")
{
add_css_file(custom_css);
}
}

void WayfirePanelApp::clear_css_rules()
{
auto screen = Gdk::Screen::get_default();
auto style_context = Gtk::StyleContext::create();
for (auto css_provider : css_rules)
{
style_context->remove_provider_for_screen(screen, css_provider);
}

css_rules.clear();
}

void WayfirePanelApp::add_css_file(std::string file)
{
auto screen = Gdk::Screen::get_default();
auto style_context = Gtk::StyleContext::create();
if (file != "")
{
auto css_provider = load_css_from_path(file);
if (css_provider)
{
style_context->add_provider_for_screen(
screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER);
css_rules.push_back(css_provider);
}
}
}

void WayfirePanelApp::handle_new_output(WayfireOutput *output)
{
priv->panels[output] = std::unique_ptr<WayfirePanel>(
Expand Down
6 changes: 6 additions & 0 deletions src/panel/panel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <memory>
#include <wayland-client.h>
#include <gtkmm/window.h>
#include <gtkmm/cssprovider.h>

#include "wf-shell-app.hpp"

Expand Down Expand Up @@ -35,11 +36,16 @@ class WayfirePanelApp : public WayfireShellApp
void handle_new_output(WayfireOutput *output) override;
void handle_output_removed(WayfireOutput *output) override;
void on_config_reload() override;
void on_css_reload() override;

private:
WayfirePanelApp(int argc, char **argv);

void clear_css_rules();
void add_css_file(std::string file);

class impl;
std::vector<Glib::RefPtr<Gtk::CssProvider>> css_rules;
std::unique_ptr<impl> priv;
};

Expand Down
68 changes: 68 additions & 0 deletions src/util/wf-shell-app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <sys/inotify.h>
#include <gdk/gdkwayland.h>
#include <iostream>
#include <filesystem>
#include <memory>
#include <wayfire/config/file.hpp>

Expand All @@ -29,6 +30,40 @@ std::string WayfireShellApp::get_config_file()
return config_dir + "/wf-shell.ini";
}

std::string WayfireShellApp::get_css_config_dir()
{
if (cmdline_css.has_value())
{
return cmdline_config.value();
}

std::string config_dir;

char *config_home = getenv("XDG_CONFIG_HOME");
if (config_home == NULL)
{
config_dir = std::string(getenv("HOME")) + "/.config";
} else
{
config_dir = std::string(config_home);
}

auto css_directory = config_dir + "/wf-shell/css/";
/* Ensure it exists */
bool created = std::filesystem::create_directories(css_directory);
if (created)
{
std::string default_css = (std::string)RESOURCEDIR + "/css/default.css";
std::string destination = css_directory + "default.css";
if (std::filesystem::exists(default_css))
{
std::filesystem::copy(default_css, destination);
}
}

return css_directory;
}

bool WayfireShellApp::parse_cfgfile(const Glib::ustring & option_name,
const Glib::ustring & value, bool has_value)
{
Expand All @@ -37,9 +72,25 @@ bool WayfireShellApp::parse_cfgfile(const Glib::ustring & option_name,
return true;
}

bool WayfireShellApp::parse_cssfile(const Glib::ustring & option_name,
const Glib::ustring & value, bool has_value)
{
std::cout << "Using custom css directory " << value << std::endl;
cmdline_css = value;
return true;
}

#define INOT_BUF_SIZE (1024 * sizeof(inotify_event))
char buf[INOT_BUF_SIZE];

static void do_reload_css(WayfireShellApp *app)
{
app->on_css_reload();
inotify_add_watch(app->inotify_css_fd,
app->get_css_config_dir().c_str(),
IN_CREATE | IN_MODIFY | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE);
}

/* Reload file and add next inotify watch */
static void do_reload_config(WayfireShellApp *app)
{
Expand All @@ -59,6 +110,15 @@ static bool handle_inotify_event(WayfireShellApp *app, Glib::IOCondition cond)
return true;
}

static bool handle_css_inotify_event(WayfireShellApp *app, Glib::IOCondition cond)
{
/* read, but don't use */
read(app->inotify_css_fd, buf, INOT_BUF_SIZE);
do_reload_css(app);

return true;
}

static void registry_add_object(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
Expand Down Expand Up @@ -107,10 +167,15 @@ void WayfireShellApp::on_activate()

inotify_fd = inotify_init();
do_reload_config(this);
inotify_css_fd = inotify_init();
do_reload_css(this);

Glib::signal_io().connect(
sigc::bind<0>(&handle_inotify_event, this),
inotify_fd, Glib::IO_IN | Glib::IO_HUP);
Glib::signal_io().connect(
sigc::bind<0>(&handle_css_inotify_event, this),
inotify_css_fd, Glib::IO_IN | Glib::IO_HUP);

// Hook up monitor tracking
auto display = Gdk::Display::get_default();
Expand Down Expand Up @@ -155,6 +220,9 @@ WayfireShellApp::WayfireShellApp(int argc, char **argv)
app->add_main_option_entry(
sigc::mem_fun(this, &WayfireShellApp::parse_cfgfile),
"config", 'c', "config file to use", "file");
app->add_main_option_entry(
sigc::mem_fun(this, &WayfireShellApp::parse_cssfile),
"css", 's', "css style directory to use", "directory");

// Activate app after parsing command line
app->signal_command_line().connect_notify([=] (auto&)
Expand Down
8 changes: 8 additions & 0 deletions src/util/wf-shell-app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class WayfireShellApp
* wf-shell-app */
static std::unique_ptr<WayfireShellApp> instance;
std::optional<std::string> cmdline_config;
std::optional<std::string> cmdline_css;

Glib::RefPtr<Gtk::Application> app;

Expand All @@ -53,25 +54,32 @@ class WayfireShellApp
virtual void on_activate();
virtual bool parse_cfgfile(const Glib::ustring & option_name,
const Glib::ustring & value, bool has_value);
virtual bool parse_cssfile(const Glib::ustring & option_name,
const Glib::ustring & value, bool has_value);
virtual void handle_new_output(WayfireOutput *output)
{}
virtual void handle_output_removed(WayfireOutput *output)
{}

public:
int inotify_fd;
int inotify_css_fd;
wf::config::config_manager_t config;
zwf_shell_manager_v2 *wf_shell_manager = nullptr;

WayfireShellApp(int argc, char **argv);
virtual ~WayfireShellApp();

virtual std::string get_config_file();
virtual std::string get_css_config_dir();
virtual void run();

virtual void on_config_reload()
{}

virtual void on_css_reload()
{}

/**
* WayfireShellApp is a singleton class.
* Using this function, any part of the application can get access to the
Expand Down

0 comments on commit 5e6898d

Please sign in to comment.