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