Replace window realm frame decorations with nicer label decorations

This commit is contained in:
2024-05-06 18:25:56 -04:00
parent ee57f6de95
commit 661e293434
16 changed files with 517 additions and 792 deletions

View File

@ -177,8 +177,6 @@ libshell_sources = [
'shell-polkit-authentication-agent.h',
'shell-realm-item.c',
'shell-realm-item.h',
'shell-realms-window-frames.c',
'shell-realms-window-frames.h',
'shell-realms.c',
'shell-realms.h',
'shell-realm-tracker.c',

View File

@ -83,6 +83,8 @@ struct _ShellApp
ShellAppRunningState *running_state;
char *realm_name;
char *window_id_string;
char *name_collation_key;
};
@ -176,6 +178,43 @@ shell_app_get_id (ShellApp *app)
return app->window_id_string;
}
static char *
shell_app_realm_name_from_app (ShellApp *app)
{
if (!app->info) {
return g_strdup("??");
}
const char *app_id = g_app_info_get_id (G_APP_INFO (app->info));
if (!app_id) {
return g_strdup("??");
}
char *realm_name = NULL;
char **split = g_strsplit(app_id, ".", 2);
if (g_str_has_prefix(split[0], "realm-")) {
realm_name = g_strdup(split[0] + 6);
} else {
realm_name = g_strdup("Citadel");
}
g_strfreev(split);
return realm_name;
}
const char *
shell_app_get_realm_name (ShellApp *app)
{
if(!app->realm_name) {
app->realm_name = shell_app_realm_name_from_app(app);
}
return app->realm_name;
}
static MetaWindow *
window_backed_app_get_window (ShellApp *app)
{
@ -908,6 +947,7 @@ _shell_app_set_app_info (ShellApp *app,
g_set_object (&app->info, info);
g_clear_pointer (&app->name_collation_key, g_free);
g_clear_pointer (&app->realm_name, g_free);
if (app->info)
app->name_collation_key = g_utf8_collate_key (shell_app_get_name (app), -1);
}
@ -1754,6 +1794,8 @@ shell_app_finalize (GObject *object)
{
ShellApp *app = SHELL_APP (object);
g_free(app->realm_name);
g_free (app->window_id_string);
g_free (app->name_collation_key);

View File

@ -25,6 +25,8 @@ typedef enum {
const char *shell_app_get_id (ShellApp *app);
const char *shell_app_get_realm_name (ShellApp *app);
GDesktopAppInfo *shell_app_get_app_info (ShellApp *app);
ClutterActor *shell_app_create_icon_texture (ShellApp *app, int size);

View File

@ -2,7 +2,6 @@
#define __SHELL_REALMS_PRIVATE_H__
#include <glib-object.h>
#include "shell-realms.h"
#include "shell-realms-window-frames.h"
#define CITADEL_REALM_TAG "[CITADEL]"

View File

@ -1,390 +0,0 @@
#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;
ShellRealms *realms;
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 };
ShellRealmsWindowFrames *
shell_realms_window_frames_new (ShellRealms *realms)
{
ShellRealmsWindowFrames *frames;
frames = g_object_new (SHELL_TYPE_REALMS_WINDOW_FRAMES, NULL);
frames->realms = realms;
return frames;
}
static void
shell_realms_window_frames_process_color (ShellRealmsWindowFrames *frames, const char *entry)
{
ClutterColor *rgba = clutter_color_alloc();
gchar **split = g_strsplit (entry, ":", -1);
if (g_strv_length (split) != 2) {
g_warning ("ShellRealmsWindowFrames: Unable to parse realm-frame-colors entry: %s", entry);
clutter_color_free(rgba);
g_strfreev (split);
return;
}
if (!clutter_color_from_string(rgba, split[1])) {
g_warning ("ShellRealmsWindowFrames: Failed to parse RGBA component of realm frame color entry: %s", entry);
clutter_color_free(rgba);
} else {
g_hash_table_insert (frames->realm_frame_colors, g_strdup (split[0]), 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;
ClutterColor *rgba = clutter_color_alloc();
entries = g_settings_get_strv (frames->settings, FRAME_COLOR_LIST_KEY);
n_entries = g_strv_length (entries);
g_clear_list (&frames->default_colors, (GDestroyNotify) clutter_color_free);
for (i = 0; i < n_entries; i++) {
if (clutter_color_from_string(rgba, entries[i])) {
frames->default_colors = g_list_append (frames->default_colors, clutter_color_copy(rgba));
}
}
clutter_color_free(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) clutter_color_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) clutter_color_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 clutter_color_equal(c1, c2) ? 0 : 1;
}
static ClutterColor *
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) {
return clutter_color_new(153, 193, 241, REALM_FRAME_ALPHA);
}
// 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) {
ClutterColor *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;
ClutterColor *rgba = value;
char *rgba_str = clutter_color_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, MetaWindow *window)
{
ShellRealmItem *realm = shell_realms_realm_by_window (frames->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) && shell_realms_is_foreign_window (frames->realms, 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);
}
}
/**
* 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;
}
const gchar *name = shell_realms_window_frames_realm_name_for_window (frames, window);
if (name == NULL) {
return NULL;
}
ClutterColor *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);
}
ClutterColor *copy = clutter_color_copy(rgba);
copy->alpha = REALM_FRAME_ALPHA;
return copy;
}
/**
* 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;
}
if (shell_realms_is_citadel_window (frames->realms, window)) {
return "Citadel";
} else {
return shell_realms_window_frames_realm_name_for_window (frames, window);
}
}

View File

@ -1,21 +0,0 @@
#ifndef __SHELL_REALMS_WINDOW_FRAMES_H__
#define __SHELL_REALMS_WINDOW_FRAMES_H__
#include <glib-object.h>
#include <clutter/clutter.h>
#include <gdk/gdk.h>
#include <meta/window.h>
#define SHELL_TYPE_REALMS_WINDOW_FRAMES (shell_realms_window_frames_get_type())
G_DECLARE_FINAL_TYPE (ShellRealmsWindowFrames, shell_realms_window_frames, SHELL, REALMS_WINDOW_FRAMES, GObject)
typedef struct _ShellRealms ShellRealms;
ShellRealmsWindowFrames *shell_realms_window_frames_new (ShellRealms *realms);
gboolean shell_realms_window_frames_has_frame (ShellRealmsWindowFrames *frames, MetaWindow *window);
gboolean shell_realms_window_frames_is_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window);
void shell_realms_window_frames_set_frame_enabled (ShellRealmsWindowFrames *frames, MetaWindow *window, gboolean enabled);
ClutterColor *shell_realms_window_frames_color_for_window (ShellRealmsWindowFrames *frames, MetaWindow *window);
const gchar *shell_realms_window_frames_label_for_window (ShellRealmsWindowFrames *frames, MetaWindow *window);
#endif // __SHELL_REALMS_WINDOW_FRAMES_H__

View File

@ -11,7 +11,6 @@ struct _ShellRealms {
GHashTable *realms;
GList *running_realms;
ShellRealmItem *current_realm;
ShellRealmsWindowFrames *frames;
MetaWorkspaceContext *detached_context;
};
@ -185,20 +184,6 @@ shell_realms_get_all_realms (ShellRealms *realms)
return g_hash_table_get_values (realms->realms);
}
/**
* shell_realms_window_frames:
* @realms: the #ShellRealms instance
*
* Returns the window frames manager.
*
* Returns: (transfer none): a #ShellRealmsWindowFrames instance
*/
ShellRealmsWindowFrames *
shell_realms_window_frames (ShellRealms *realms)
{
return realms->frames;
}
static gboolean
shell_realms_is_on_running_list (ShellRealms *realms, ShellRealmItem *item)
{
@ -597,8 +582,6 @@ shell_realms_finalize (GObject *obj)
realms->current_realm = NULL;
g_list_free_full (realms->running_realms, g_object_unref);
g_hash_table_destroy (realms->realms);
g_object_unref (realms->frames);
realms->frames = NULL;
G_OBJECT_CLASS (shell_realms_parent_class)->finalize (obj);
}

View File

@ -4,7 +4,6 @@
#include <glib-object.h>
#include <meta/window.h>
#include "shell-realm-item.h"
#include "shell-realms-window-frames.h"
#define SHELL_TYPE_REALMS (shell_realms_get_type())
G_DECLARE_FINAL_TYPE(ShellRealms, shell_realms, SHELL, REALMS, GObject)
@ -19,8 +18,6 @@ ShellRealmItem *shell_realms_realm_by_window (ShellRealms *realms, MetaWindow *w
gboolean shell_realms_is_citadel_window (ShellRealms *realms, MetaWindow *window);
gboolean shell_realms_is_foreign_window (ShellRealms *realms, MetaWindow *window);
ShellRealmsWindowFrames *shell_realms_window_frames (ShellRealms *realms);
GList *shell_realms_get_running_realms (ShellRealms *realms);
GList *shell_realms_get_all_realms (ShellRealms *realms);