Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add soft light border in dark theme #20

Merged
merged 2 commits into from Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions assets/handy-window-dark.css
@@ -0,0 +1,16 @@
window.csd.unified:not(.solid-csd):not(.fullscreen):not(.maximized) decoration-overlay {
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}

window.csd.unified:not(.solid-csd):not(.fullscreen):not(.maximized) headerbar {
box-shadow: none;
}

decoration {
box-shadow: 0 3px 9px 1px rgba(0,0,0,.5);
}

decoration:backdrop {
box-shadow: 0 3px 9px 1px transparent,
0 2px 6px 2px rgba(0,0,0,.2);
}
Empty file added assets/handy-window.css
Empty file.
4 changes: 4 additions & 0 deletions example/linux/flutter/generated_plugin_registrant.cc
Expand Up @@ -8,6 +8,7 @@

#include <handy_window/handy_window_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <yaru/yaru_plugin.h>

void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) handy_window_registrar =
Expand All @@ -16,4 +17,7 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
g_autoptr(FlPluginRegistrar) yaru_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "YaruPlugin");
yaru_plugin_register_with_registrar(yaru_registrar);
}
1 change: 1 addition & 0 deletions example/linux/flutter/generated_plugins.cmake
Expand Up @@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
handy_window
url_launcher_linux
yaru
)

list(APPEND FLUTTER_FFI_PLUGIN_LIST
Expand Down
5 changes: 5 additions & 0 deletions linux/CMakeLists.txt
Expand Up @@ -8,12 +8,17 @@ set(PLUGIN_NAME "handy_window_plugin")

add_library(${PLUGIN_NAME} SHARED
"handy_window_plugin.cc"
"settings/handy_gnome_settings.cc"
"settings/handy_settings_portal.cc"
"settings/handy_settings.cc"
)
apply_standard_settings(${PLUGIN_NAME})
set_target_properties(${PLUGIN_NAME} PROPERTIES
CXX_VISIBILITY_PRESET hidden)
target_compile_options(${PLUGIN_NAME} PRIVATE -Wall -Wextra -Werror)
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
target_include_directories(${PLUGIN_NAME} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/settings")
target_include_directories(${PLUGIN_NAME} INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter)
Expand Down
39 changes: 39 additions & 0 deletions linux/handy_window_plugin.cc
Expand Up @@ -8,6 +8,8 @@

#include <functional>

#include "handy_settings.h"

#define _HANDY_INSIDE
#include "hdy-window-mixin-private.h"
#undef _HANDY_INSIDE
Expand Down Expand Up @@ -163,6 +165,37 @@ static gboolean use_csd(GtkWidget* window) {
return true;
}

static void load_css(HandySettings* settings) {
GdkScreen* screen = gdk_screen_get_default();
gpointer css_provider =
g_object_get_data(G_OBJECT(screen), "_handy_window_css_provider_");

if (css_provider == nullptr) {
css_provider = gtk_css_provider_new();
gtk_style_context_add_provider_for_screen(
screen, GTK_STYLE_PROVIDER(css_provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_set_data_full(G_OBJECT(screen), "_handy_window_css_provider_",
css_provider, g_object_unref);
}

HandyColorScheme color_scheme = handy_settings_get_color_scheme(settings);

g_autoptr(GError) error = nullptr;
g_autofree gchar* exe_path = g_file_read_link("/proc/self/exe", &error);
g_autofree gchar* app_path = g_path_get_dirname(exe_path);
const gchar* asset_path = "data/flutter_assets/packages/handy_window/assets";
const gchar* css_file = color_scheme == HANDY_COLOR_SCHEME_DARK
? "handy-window-dark.css"
: "handy-window.css";
g_autofree gchar* css_path =
g_build_filename(app_path, asset_path, css_file, nullptr);
if (!gtk_css_provider_load_from_path(GTK_CSS_PROVIDER(css_provider), css_path,
&error)) {
g_warning("%s: %s", css_path, error->message);
}
}

static void setup_handy_window(FlView* view) {
GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(view));

Expand Down Expand Up @@ -242,6 +275,12 @@ static void setup_handy_window(FlView* view) {
gtk_widget_show(header_bar);
}
gtk_widget_show(GTK_WIDGET(view));

// css
HandySettings* settings = handy_settings_new();
load_css(settings);
g_signal_connect_object(settings, "changed", G_CALLBACK(load_css), settings,
G_CONNECT_SWAPPED);
}

void handy_window_plugin_register_with_registrar(FlPluginRegistrar* registrar) {
Expand Down
25 changes: 25 additions & 0 deletions linux/settings/LICENCE
@@ -0,0 +1,25 @@
Copyright 2013 The Flutter Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4 changes: 4 additions & 0 deletions linux/settings/README.md
@@ -0,0 +1,4 @@
# HandySettings

Based on FlSettings, FlSettingsPortal, and FlGnomeSettings:
https://github.com/flutter/engine/tree/main/shell/platform/linux
120 changes: 120 additions & 0 deletions linux/settings/handy_gnome_settings.cc
@@ -0,0 +1,120 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "handy_gnome_settings.h"

#include <gio/gio.h>
#include <glib.h>

static constexpr char kDesktopInterfaceSchema[] = "org.gnome.desktop.interface";
static constexpr char kDesktopGtkThemeKey[] = "gtk-theme";

static constexpr char kGtkThemeDarkSuffix[] = "-dark";
static constexpr char kInterfaceSettings[] = "interface-settings";

struct _HandyGnomeSettings {
GObject parent_instance;

GSettings* interface_settings;
};

enum { kProp0, kPropInterfaceSettings, kPropLast };

static void handy_gnome_settings_iface_init(HandySettingsInterface* iface);

G_DEFINE_TYPE_WITH_CODE(HandyGnomeSettings, handy_gnome_settings, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(handy_settings_get_type(),
handy_gnome_settings_iface_init))

static HandyColorScheme handy_gnome_settings_get_color_scheme(
HandySettings* settings) {
HandyGnomeSettings* self = HANDY_GNOME_SETTINGS(settings);

HandyColorScheme color_scheme = HANDY_COLOR_SCHEME_LIGHT;

if (self->interface_settings != nullptr) {
// check whether org.gnome.desktop.interface.gtk-theme ends with "-dark"
g_autofree gchar* value =
g_settings_get_string(self->interface_settings, kDesktopGtkThemeKey);
if (g_str_has_suffix(value, kGtkThemeDarkSuffix)) {
color_scheme = HANDY_COLOR_SCHEME_DARK;
}
}
return color_scheme;
}

static void handy_gnome_settings_set_interface_settings(
HandyGnomeSettings* self, GSettings* settings) {
g_return_if_fail(G_IS_SETTINGS(settings));

g_signal_connect_object(settings, "changed::gtk-theme",
G_CALLBACK(handy_settings_emit_changed), self,
G_CONNECT_SWAPPED);

self->interface_settings = G_SETTINGS(g_object_ref(settings));
}

static void handy_gnome_settings_set_property(GObject* object, guint prop_id,
const GValue* value,
GParamSpec* pspec) {
HandyGnomeSettings* self = HANDY_GNOME_SETTINGS(object);
switch (prop_id) {
case kPropInterfaceSettings:
handy_gnome_settings_set_interface_settings(
self, G_SETTINGS(g_value_get_object(value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}

static void handy_gnome_settings_dispose(GObject* object) {
HandyGnomeSettings* self = HANDY_GNOME_SETTINGS(object);

g_clear_object(&self->interface_settings);

G_OBJECT_CLASS(handy_gnome_settings_parent_class)->dispose(object);
}

static void handy_gnome_settings_class_init(HandyGnomeSettingsClass* klass) {
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = handy_gnome_settings_dispose;
object_class->set_property = handy_gnome_settings_set_property;

g_object_class_install_property(
object_class, kPropInterfaceSettings,
g_param_spec_object(
kInterfaceSettings, kInterfaceSettings, kDesktopInterfaceSchema,
g_settings_get_type(),
static_cast<GParamFlags>(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)));
}

static void handy_gnome_settings_iface_init(HandySettingsInterface* iface) {
iface->get_color_scheme = handy_gnome_settings_get_color_scheme;
}

static void handy_gnome_settings_init(HandyGnomeSettings*) {}

static GSettings* create_settings(const gchar* schema_id) {
GSettings* settings = nullptr;
GSettingsSchemaSource* source = g_settings_schema_source_get_default();
if (source != nullptr) {
g_autoptr(GSettingsSchema) schema =
g_settings_schema_source_lookup(source, schema_id, TRUE);
if (schema != nullptr) {
settings = g_settings_new_full(schema, nullptr, nullptr);
}
}
return settings;
}

HandySettings* handy_gnome_settings_new() {
g_autoptr(GSettings) interface_settings =
create_settings(kDesktopInterfaceSchema);
return HANDY_SETTINGS(g_object_new(handy_gnome_settings_get_type(),
kInterfaceSettings, interface_settings,
nullptr));
}
26 changes: 26 additions & 0 deletions linux/settings/handy_gnome_settings.h
@@ -0,0 +1,26 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef HANDY_GNOME_SETTINGS_H_
#define HANDY_GNOME_SETTINGS_H_

#include "handy_settings.h"

G_BEGIN_DECLS

G_DECLARE_FINAL_TYPE(HandyGnomeSettings, handy_gnome_settings, HANDY,
GNOME_SETTINGS, GObject);

/**
* handy_gnome_settings_new:
*
* Creates a new settings instance for GNOME.
*
* Returns: a new #HandySettings.
*/
HandySettings* handy_gnome_settings_new();

G_END_DECLS

#endif // HANDY_GNOME_SETTINGS_H_
50 changes: 50 additions & 0 deletions linux/settings/handy_settings.cc
@@ -0,0 +1,50 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "handy_settings.h"

#include "handy_gnome_settings.h"
#include "handy_settings_portal.h"

G_DEFINE_INTERFACE(HandySettings, handy_settings, G_TYPE_OBJECT)

enum {
kSignalChanged,
kSignalLastSignal,
};

static guint signals[kSignalLastSignal];

static void handy_settings_default_init(HandySettingsInterface* iface) {
/**
* HandySettings::changed:
* @settings: an #HandySettings
*
* This signal is emitted after the settings have been changed.
*/
signals[kSignalChanged] =
g_signal_new("changed", G_TYPE_FROM_INTERFACE(iface), G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}

HandyColorScheme handy_settings_get_color_scheme(HandySettings* self) {
return HANDY_SETTINGS_GET_IFACE(self)->get_color_scheme(self);
}

void handy_settings_emit_changed(HandySettings* self) {
g_return_if_fail(HANDY_IS_SETTINGS(self));
g_signal_emit(self, signals[kSignalChanged], 0);
}

HandySettings* handy_settings_new() {
g_autoptr(HandySettingsPortal) portal = handy_settings_portal_new();

g_autoptr(GError) error = nullptr;
if (!handy_settings_portal_start(portal, &error)) {
g_debug("XDG desktop portal settings unavailable: %s", error->message);
return handy_gnome_settings_new();
}

return HANDY_SETTINGS(g_object_ref(portal));
}