/* Theming/CSS Blend Modes * * You can blend multiple backgrounds using the CSS blend modes available. */ #include #define WID(x) ((GtkWidget*) gtk_builder_get_object (builder, x)) /* * These are the available blend modes. */ struct { const char *name; const char *id; } blend_modes[] = { { "Color", "color" }, { "Color (burn)", "color-burn" }, { "Color (dodge)", "color-dodge" }, { "Darken", "darken" }, { "Difference", "difference" }, { "Exclusion", "exclusion" }, { "Hard Light", "hard-light" }, { "Hue", "hue" }, { "Lighten", "lighten" }, { "Luminosity", "luminosity" }, { "Multiply", "multiply" }, { "Normal", "normal" }, { "Overlay", "overlay" }, { "Saturate", "saturation" }, { "Screen", "screen" }, { "Soft Light", "soft-light" }, { NULL } }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" static void update_css_for_blend_mode (GtkCssProvider *provider, const char *blend_mode) { GBytes *bytes; char *css; bytes = g_resources_lookup_data ("/css_blendmodes/css_blendmodes.css", 0, NULL); css = g_strdup_printf ((char *) g_bytes_get_data (bytes, NULL), blend_mode, blend_mode, blend_mode); gtk_css_provider_load_from_data (provider, css, -1); g_bytes_unref (bytes); g_free (css); } #pragma GCC diagnostic pop static void row_activated (GtkListBox *listbox, GtkListBoxRow *row, GtkCssProvider *provider) { const char *blend_mode; blend_mode = blend_modes[gtk_list_box_row_get_index (row)].id; update_css_for_blend_mode (provider, blend_mode); } static void setup_listbox (GtkBuilder *builder, GtkStyleProvider *provider) { GtkWidget *normal_row; GtkWidget *listbox; int i; normal_row = NULL; listbox = gtk_list_box_new (); gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (WID ("scrolledwindow")), listbox); g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider); /* Add a row for each blend mode available */ for (i = 0; blend_modes[i].name != NULL; i++) { GtkWidget *label; GtkWidget *row; row = gtk_list_box_row_new (); label = g_object_new (GTK_TYPE_LABEL, "label", blend_modes[i].name, "xalign", 0.0, NULL); gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), label); gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1); /* The first selected row is "normal" */ if (g_strcmp0 (blend_modes[i].id, "normal") == 0) normal_row = row; } /* Select the "normal" row */ gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (normal_row)); g_signal_emit_by_name (G_OBJECT (normal_row), "activate"); gtk_widget_grab_focus (normal_row); } GtkWidget * do_css_blendmodes (GtkWidget *do_widget) { static GtkWidget *window = NULL; if (!window) { GtkStyleProvider *provider; GtkBuilder *builder; builder = gtk_builder_new_from_resource ("/css_blendmodes/blendmodes.ui"); window = WID ("window"); gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget)); g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); /* Setup the CSS provider for window */ provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ()); gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); setup_listbox (builder, provider); g_object_unref (builder); } if (!gtk_widget_get_visible (window)) gtk_widget_show (window); else gtk_window_destroy (GTK_WINDOW (window)); return window; }