387 lines
11 KiB
C
387 lines
11 KiB
C
#include "shell-realms-window-frames.h"
|
|
#include "shell-realms.h"
|
|
|
|
#define CITADEL_SETTINGS_SCHEMA "com.subgraph.citadel"
|
|
#define FRAME_COLOR_LIST_KEY "frame-color-list"
|
|
#define REALM_FRAME_COLORS_KEY "realm-frame-colors"
|
|
|
|
#define REALM_FRAME_ALPHA 200
|
|
|
|
struct _ShellRealmsWindowFrames {
|
|
GObject parent;
|
|
GSettings *settings;
|
|
GHashTable *realm_frame_colors;
|
|
GList *default_colors;
|
|
GList *frame_disabled_windows;
|
|
};
|
|
|
|
G_DEFINE_TYPE (ShellRealmsWindowFrames, shell_realms_window_frames, G_TYPE_OBJECT);
|
|
|
|
enum {
|
|
REALM_FRAME_COLORS_CHANGED,
|
|
LAST_SIGNAL,
|
|
};
|
|
|
|
static guint shell_realms_window_frames_signals [LAST_SIGNAL] = { 0 };
|
|
|
|
static void
|
|
shell_realms_window_frames_process_color (ShellRealmsWindowFrames *frames, const char *entry)
|
|
{
|
|
GdkRGBA rgba;
|
|
|
|
gchar **split = g_strsplit (entry, ":", -1);
|
|
|
|
if (g_strv_length (split) != 2) {
|
|
g_warning("ShellRealmsWindowFrames: Unable to parse realm-frame-colors entry: %s", entry);
|
|
g_strfreev (split);
|
|
return;
|
|
}
|
|
|
|
if (!gdk_rgba_parse (&rgba, split[1])) {
|
|
g_warning("ShellRealmsWindowFrames: Failed to parse RGBA component of realm frame color entry: %s", entry);
|
|
} else {
|
|
g_hash_table_insert (frames->realm_frame_colors, g_strdup (split[0]), gdk_rgba_copy (&rgba));
|
|
}
|
|
g_strfreev (split);
|
|
}
|
|
|
|
static void
|
|
load_realm_frame_colors (ShellRealmsWindowFrames *frames)
|
|
{
|
|
guint n_entries, i;
|
|
char **entries;
|
|
|
|
entries = g_settings_get_strv (frames->settings, REALM_FRAME_COLORS_KEY);
|
|
n_entries = g_strv_length (entries);
|
|
|
|
for (i = 0; i < n_entries; i++) {
|
|
shell_realms_window_frames_process_color (frames, entries[i]);
|
|
}
|
|
g_strfreev (entries);
|
|
|
|
}
|
|
|
|
static void
|
|
on_realm_frame_colors_changed(GSettings *settings, const gchar *key, ShellRealmsWindowFrames *frames)
|
|
{
|
|
load_realm_frame_colors (frames);
|
|
g_signal_emit (frames, shell_realms_window_frames_signals[REALM_FRAME_COLORS_CHANGED], 0);
|
|
}
|
|
|
|
static void
|
|
load_default_colors (ShellRealmsWindowFrames *frames)
|
|
{
|
|
guint n_entries, i;
|
|
char **entries;
|
|
GdkRGBA rgba;
|
|
|
|
entries = g_settings_get_strv (frames->settings, FRAME_COLOR_LIST_KEY);
|
|
n_entries = g_strv_length (entries);
|
|
|
|
g_clear_list(&frames->default_colors, (GDestroyNotify) gdk_rgba_free);
|
|
|
|
for (i = 0; i < n_entries; i++) {
|
|
if (gdk_rgba_parse (&rgba, entries[i])) {
|
|
frames->default_colors = g_list_append (frames->default_colors, gdk_rgba_copy(&rgba));
|
|
}
|
|
}
|
|
g_strfreev (entries);
|
|
}
|
|
|
|
static void
|
|
on_frame_color_list_changed (GSettings *settings, const gchar *key, ShellRealmsWindowFrames *frames)
|
|
{
|
|
load_default_colors (frames);
|
|
}
|
|
|
|
static void
|
|
shell_realms_window_frames_init (ShellRealmsWindowFrames *frames)
|
|
{
|
|
frames->settings = g_settings_new (CITADEL_SETTINGS_SCHEMA);
|
|
frames->realm_frame_colors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gdk_rgba_free);
|
|
frames->default_colors = NULL;
|
|
frames->frame_disabled_windows = NULL;
|
|
|
|
g_signal_connect(frames->settings,
|
|
"changed::" FRAME_COLOR_LIST_KEY,
|
|
G_CALLBACK(on_frame_color_list_changed),
|
|
frames);
|
|
|
|
g_signal_connect(frames->settings,
|
|
"changed::" REALM_FRAME_COLORS_KEY,
|
|
G_CALLBACK(on_realm_frame_colors_changed),
|
|
frames);
|
|
|
|
|
|
load_default_colors (frames);
|
|
load_realm_frame_colors (frames);
|
|
}
|
|
|
|
static void
|
|
shell_realms_window_frames_finalize (GObject *obj)
|
|
{
|
|
ShellRealmsWindowFrames *frames = SHELL_REALMS_WINDOW_FRAMES (obj);
|
|
g_object_unref (frames->settings);
|
|
g_hash_table_destroy (frames->realm_frame_colors);
|
|
g_list_free_full (frames->default_colors, (GDestroyNotify) gdk_rgba_free);
|
|
g_list_free (frames->frame_disabled_windows);
|
|
G_OBJECT_CLASS (shell_realms_window_frames_parent_class)->finalize (obj);
|
|
}
|
|
|
|
static void
|
|
shell_realms_window_frames_class_init (ShellRealmsWindowFramesClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
object_class->finalize = shell_realms_window_frames_finalize;
|
|
|
|
shell_realms_window_frames_signals[REALM_FRAME_COLORS_CHANGED] =
|
|
g_signal_new ("realm-frame-colors-changed",
|
|
G_TYPE_FROM_CLASS(klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
}
|
|
|
|
static gboolean
|
|
disabled_list_contains (ShellRealmsWindowFrames *frames, guint32 window_id)
|
|
{
|
|
return g_list_find (frames->frame_disabled_windows, GUINT_TO_POINTER(window_id)) != NULL;
|
|
}
|
|
|
|
static bool
|
|
remove_from_disabled_list (ShellRealmsWindowFrames *frames, guint32 window_id)
|
|
{
|
|
if (disabled_list_contains (frames, window_id)) {
|
|
frames->frame_disabled_windows = g_list_remove (frames->frame_disabled_windows, GUINT_TO_POINTER(window_id));
|
|
g_signal_emit (frames, shell_realms_window_frames_signals[REALM_FRAME_COLORS_CHANGED], 0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static bool
|
|
add_to_disabled_list (ShellRealmsWindowFrames *frames, guint32 window_id)
|
|
{
|
|
if (!disabled_list_contains (frames, window_id)) {
|
|
frames->frame_disabled_windows = g_list_append (frames->frame_disabled_windows, GUINT_TO_POINTER(window_id));
|
|
g_signal_emit (frames, shell_realms_window_frames_signals[REALM_FRAME_COLORS_CHANGED], 0);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
color_compare(gconstpointer c1, gconstpointer c2) {
|
|
return gdk_rgba_equal (c1, c2) ? 0 : 1;
|
|
}
|
|
|
|
static GdkRGBA *
|
|
allocate_color (ShellRealmsWindowFrames *frames)
|
|
{
|
|
guint n_colors = g_list_length (frames->default_colors);
|
|
|
|
// 1) No default colors? return a built in color
|
|
if (n_colors == 0) {
|
|
GdkRGBA rgba;
|
|
gdk_rgba_parse (&rgba, "rgb(153, 193, 241)");
|
|
return gdk_rgba_copy (&rgba);
|
|
}
|
|
|
|
// 2) No default colors? Find first color on default color list that isn't used already
|
|
GList *used_colors = g_hash_table_get_values (frames->realm_frame_colors);
|
|
for (GList *iter = frames->default_colors; iter; iter = iter->next) {
|
|
GdkRGBA *rgba = iter->data;
|
|
if (!g_list_find_custom (used_colors, rgba, color_compare)) {
|
|
return rgba;
|
|
}
|
|
}
|
|
g_list_free (used_colors);
|
|
|
|
// 3) Choose a random element of the default list
|
|
guint index = (guint) g_random_int_range(0, (gint32) n_colors);
|
|
return g_list_nth_data (frames->default_colors, index);
|
|
}
|
|
|
|
static void
|
|
shell_realms_window_frames_store_colors (ShellRealmsWindowFrames *frames)
|
|
{
|
|
GHashTableIter iter;
|
|
gpointer key, value;
|
|
|
|
GPtrArray *entries = g_ptr_array_new_with_free_func(g_free);
|
|
|
|
g_hash_table_iter_init (&iter, frames->realm_frame_colors);
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
|
gchar *name = key;
|
|
GdkRGBA *rgba = value;
|
|
char *rgba_str = gdk_rgba_to_string (rgba);
|
|
gchar *entry = g_strconcat (name, ":", rgba_str, NULL);
|
|
g_ptr_array_add (entries, entry);
|
|
g_free (rgba_str);
|
|
}
|
|
|
|
g_ptr_array_sort (entries, (GCompareFunc) g_strcmp0);
|
|
g_ptr_array_add (entries, NULL);
|
|
g_settings_set_strv (frames->settings, REALM_FRAME_COLORS_KEY, (const gchar * const *) entries->pdata);
|
|
|
|
g_ptr_array_unref (entries);
|
|
}
|
|
|
|
static const char *
|
|
shell_realms_window_frames_realm_name_for_window (ShellRealmsWindowFrames *frames, ShellRealms *realms, MetaWindow *window)
|
|
{
|
|
|
|
ShellRealmItem *realm = shell_realms_realm_by_window (realms, window);
|
|
|
|
if (realm) {
|
|
return shell_realm_item_get_realm_name (realm);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_window_unmanaged (MetaWindow *window, ShellRealmsWindowFrames *frames)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_unmanaged), frames);
|
|
guint32 id = meta_window_get_stable_sequence (window);
|
|
remove_from_disabled_list (frames, id);
|
|
}
|
|
|
|
static gboolean
|
|
is_ignored_window (MetaWindow *window)
|
|
{
|
|
switch (meta_window_get_window_type (window)) {
|
|
case META_WINDOW_MENU:
|
|
case META_WINDOW_TOOLTIP:
|
|
case META_WINDOW_POPUP_MENU:
|
|
case META_WINDOW_DROPDOWN_MENU:
|
|
return TRUE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* shell_realms_window_frames_is_frame_enabled:
|
|
* @frames: a #ShellRealmsWindowFrames instance
|
|
* @window: a #MetaWindow
|
|
*
|
|
* Return #TRUE if frame has not been disabled for this window.
|
|
*
|
|
* Returns: #TRUE if frame has not been disabled for this window.
|
|
*/
|
|
gboolean
|
|
shell_realms_window_frames_is_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window)
|
|
{
|
|
guint32 id = meta_window_get_stable_sequence (window);
|
|
return !disabled_list_contains (frames, id);
|
|
}
|
|
|
|
/**
|
|
* shell_realms_window_frames_has_frame:
|
|
* @frames: a #ShellRealmsWindowFrames instance
|
|
* @window: a #MetaWindow
|
|
*
|
|
* Return #TRUE if this window needs a frame.
|
|
*
|
|
* Returns: #TRUE if a frame should be drawn for this window.
|
|
*/
|
|
gboolean
|
|
shell_realms_window_frames_has_frame (ShellRealmsWindowFrames *frames, MetaWindow *window)
|
|
{
|
|
return !is_ignored_window(window) && meta_window_is_on_foreign_workspace_context (window);
|
|
}
|
|
|
|
/**
|
|
* shell_realms_window_frames_set_frame_enabled:
|
|
* @frames: a #ShellRealmsWindowFrames instance
|
|
* @window: a #MetaWindow
|
|
* @enabled: Set to #FALSE to disable drawing frame for this window
|
|
*
|
|
*/
|
|
void
|
|
shell_realms_window_frames_set_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window, gboolean enabled)
|
|
{
|
|
guint32 id = meta_window_get_stable_sequence (window);
|
|
|
|
if (enabled) {
|
|
if (remove_from_disabled_list (frames, id)) {
|
|
g_signal_handlers_disconnect_by_func (window, G_CALLBACK (on_window_unmanaged), frames);
|
|
}
|
|
} else if (add_to_disabled_list (frames, id)) {
|
|
g_signal_connect_object (window, "unmanaged", G_CALLBACK(on_window_unmanaged), frames, 0);
|
|
}
|
|
}
|
|
|
|
static ClutterColor *
|
|
rgba_to_clutter_color(GdkRGBA *rgba)
|
|
{
|
|
guint8 r = (guint8) (0.5 + CLAMP(rgba->red, 0.0, 1.0) * 255.0);
|
|
guint8 g = (guint8) (0.5 + CLAMP(rgba->green, 0.0, 1.0) * 255.0);
|
|
guint8 b = (guint8) (0.5 + CLAMP(rgba->blue, 0.0, 1.0) * 255.0);
|
|
|
|
return clutter_color_new (r, g, b, REALM_FRAME_ALPHA);
|
|
}
|
|
|
|
/**
|
|
* shell_realms_window_frames_color_for_window:
|
|
* @frames: a #ShellRealmsWindowFrames instance
|
|
* @window: a #MetaWindow
|
|
*
|
|
* Returns a color to use for painting window frame.
|
|
*
|
|
* Return value: (transfer full) (nullable): The frame color or %NULL if no frame should be drawn.
|
|
*/
|
|
ClutterColor *
|
|
shell_realms_window_frames_color_for_window (ShellRealmsWindowFrames *frames, MetaWindow *window)
|
|
{
|
|
if (!shell_realms_window_frames_has_frame (frames, window)) {
|
|
return NULL;
|
|
}
|
|
|
|
ShellRealms *realms = shell_realms_get_default();
|
|
|
|
const gchar *name = shell_realms_window_frames_realm_name_for_window (frames, realms, window);
|
|
|
|
GdkRGBA *rgba = g_hash_table_lookup (frames->realm_frame_colors, name);
|
|
|
|
if (!rgba) {
|
|
rgba = allocate_color (frames);
|
|
g_hash_table_insert (frames->realm_frame_colors, g_strdup(name), rgba);
|
|
shell_realms_window_frames_store_colors (frames);
|
|
}
|
|
|
|
return rgba_to_clutter_color (rgba);
|
|
}
|
|
|
|
/**
|
|
* shell_realms_window_frames_label_for_window:
|
|
* @frames: a #ShellRealmsWindowFrames instance
|
|
* @window: a #MetaWindow
|
|
*
|
|
* Return the label text for window if the window requires a frame.
|
|
*
|
|
* Return value: (transfer none) (nullable): The label text or %NULL if no label should be displayed
|
|
*/
|
|
const gchar *
|
|
shell_realms_window_frames_label_for_window (ShellRealmsWindowFrames *frames, MetaWindow *window)
|
|
{
|
|
if (!shell_realms_window_frames_has_frame (frames, window)) {
|
|
return NULL;
|
|
}
|
|
if (meta_window_get_window_type (window) != META_WINDOW_NORMAL) {
|
|
return NULL;
|
|
}
|
|
|
|
ShellRealms *realms = shell_realms_get_default();
|
|
|
|
if (shell_realms_is_citadel_window (realms, window)) {
|
|
return "Citadel";
|
|
} else {
|
|
return shell_realms_window_frames_realm_name_for_window (frames, realms, window);
|
|
}
|
|
}
|