1 /* Theming/CSS Blend Modes
2 *
3 * You can blend multiple backgrounds using the CSS blend modes available.
4 */
5
6 #include <gtk/gtk.h>
7
8 #define WID(x) ((GtkWidget*) gtk_builder_get_object (builder, x))
9
10 /*
11 * These are the available blend modes.
12 */
13 struct {
14 gchar *name;
15 gchar *id;
16 } blend_modes[] =
17 {
18 { "Color", "color" },
19 { "Color (burn)", "color-burn" },
20 { "Color (dodge)", "color-dodge" },
21 { "Darken", "darken" },
22 { "Difference", "difference" },
23 { "Exclusion", "exclusion" },
24 { "Hard Light", "hard-light" },
25 { "Hue", "hue" },
26 { "Lighten", "lighten" },
27 { "Luminosity", "luminosity" },
28 { "Multiply", "multiply" },
29 { "Normal", "normal" },
30 { "Overlay", "overlay" },
31 { "Saturate", "saturate" },
32 { "Screen", "screen" },
33 { "Soft Light", "soft-light" },
34 { NULL }
35 };
36
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
39 static void
update_css_for_blend_mode(GtkCssProvider * provider,const gchar * blend_mode)40 update_css_for_blend_mode (GtkCssProvider *provider,
41 const gchar *blend_mode)
42 {
43 GBytes *bytes;
44 gchar *css;
45
46 bytes = g_resources_lookup_data ("/css_blendmodes/css_blendmodes.css", 0, NULL);
47
48 css = g_strdup_printf ((gchar*) g_bytes_get_data (bytes, NULL),
49 blend_mode,
50 blend_mode,
51 blend_mode);
52
53 gtk_css_provider_load_from_data (provider, css, -1, NULL);
54
55 g_bytes_unref (bytes);
56 g_free (css);
57 }
58 #pragma GCC diagnostic pop
59
60 static void
row_activated(GtkListBox * listbox,GtkListBoxRow * row,GtkCssProvider * provider)61 row_activated (GtkListBox *listbox,
62 GtkListBoxRow *row,
63 GtkCssProvider *provider)
64 {
65 const gchar *blend_mode;
66
67 blend_mode = blend_modes[gtk_list_box_row_get_index (row)].id;
68
69 update_css_for_blend_mode (provider, blend_mode);
70 }
71
72 static void
setup_listbox(GtkBuilder * builder,GtkStyleProvider * provider)73 setup_listbox (GtkBuilder *builder,
74 GtkStyleProvider *provider)
75 {
76 GtkWidget *normal_row;
77 GtkWidget *listbox;
78 gint i;
79
80 normal_row = NULL;
81 listbox = gtk_list_box_new ();
82 gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
83
84 g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
85
86 /* Add a row for each blend mode available */
87 for (i = 0; blend_modes[i].name != NULL; i++)
88 {
89 GtkWidget *label;
90 GtkWidget *row;
91
92 row = gtk_list_box_row_new ();
93 label = g_object_new (GTK_TYPE_LABEL,
94 "label", blend_modes[i].name,
95 "xalign", 0.0,
96 NULL);
97
98 gtk_container_add (GTK_CONTAINER (row), label);
99
100 gtk_container_add (GTK_CONTAINER (listbox), row);
101
102 /* The first selected row is "normal" */
103 if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
104 normal_row = row;
105 }
106
107 /* Select the "normal" row */
108 gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (normal_row));
109 g_signal_emit_by_name (G_OBJECT (normal_row), "activate");
110
111 gtk_widget_grab_focus (normal_row);
112 }
113
114 GtkWidget *
do_css_blendmodes(GtkWidget * do_widget)115 do_css_blendmodes (GtkWidget *do_widget)
116 {
117 static GtkWidget *window = NULL;
118
119 if (!window)
120 {
121 GtkStyleProvider *provider;
122 GtkBuilder *builder;
123
124 builder = gtk_builder_new_from_resource ("/css_blendmodes/blendmodes.ui");
125
126 window = WID ("window");
127 gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
128 g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
129
130 /* Setup the CSS provider for window */
131 provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
132
133 gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
134 provider,
135 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
136
137 setup_listbox (builder, provider);
138 }
139
140 if (!gtk_widget_get_visible (window))
141 gtk_widget_show_all (window);
142 else
143 gtk_widget_destroy (window);
144
145 return window;
146 }
147