Compare commits

...

12 Commits

Author SHA1 Message Date
Matthias Clasen
4c5fc2db89 Add a test for CSS variables 2024-04-21 14:35:26 -04:00
Alice Mikhaylenko
9faeea801e tmp tests 2024-03-20 23:11:36 +04:00
Alice Mikhaylenko
26aecbb006 tmp: Add libadwaita styles 2024-03-20 23:11:36 +04:00
Alice Mikhaylenko
17ccb849b3 csskeyframes: Support variables 2024-03-20 23:11:36 +04:00
Alice Mikhaylenko
4a3894e820 cssanimation: Recompute values while playing
This will be necessary for supporting variables in animations.
2024-03-20 23:11:36 +04:00
Alice Mikhaylenko
156a7450be cssvalue: Pass an extra GtkCssVariableSet to compute()
This will be useful for supporting variables in @keyframes.
2024-03-20 23:11:35 +04:00
Alice Mikhaylenko
b7988d133d Implement basic support for CSS variables 2024-03-20 22:46:32 +04:00
Alice Mikhaylenko
1baaeeb048 cssvalue: Add contains_variables()
We'll need this to know which values to recompute for animations.
2024-03-20 22:46:32 +04:00
Alice Mikhaylenko
63f489dc64 csstokenizer: Add save() and restore()
We'll need that to check if property values contain variables.
2024-03-20 22:46:32 +04:00
Alice Mikhaylenko
3323f08c75 cssselector: Support :root
This is useful for defining global variables.
2024-03-20 22:46:32 +04:00
Alice Mikhaylenko
35060aae8d cssprovider: Copy bytes when loading
We'll need to keep accessing them later to compute values with variables,
so we can't avoid this anymore.
2024-03-20 22:46:32 +04:00
Alice Mikhaylenko
c6c13ded6a csstokenizer: Fix an out of bounds when reading an ident followed by EOG
TODO: Split this into a separate MR, it's a preexisting bug.
2024-03-20 22:46:32 +04:00
147 changed files with 9841 additions and 328 deletions

View File

@@ -27,12 +27,13 @@
#include "gtkcsslocationprivate.h"
typedef struct _GtkCssParserBlock GtkCssParserBlock;
typedef struct _GtkCssParserTokenStreamData GtkCssParserTokenStreamData;
struct _GtkCssParser
{
volatile int ref_count;
GtkCssTokenizer *tokenizer;
GPtrArray *tokenizers;
GFile *file;
GFile *directory;
GtkCssParserErrorFunc error_func;
@@ -42,6 +43,11 @@ struct _GtkCssParser
GArray *blocks;
GtkCssLocation location;
GtkCssToken token;
GtkCssVariableValue **refs;
gsize n_refs;
gsize next_ref;
gboolean var_fallback;
};
struct _GtkCssParserBlock
@@ -52,6 +58,12 @@ struct _GtkCssParserBlock
GtkCssTokenType alternative_token;
};
static inline GtkCssTokenizer *
get_tokenizer (GtkCssParser *self)
{
return g_ptr_array_index (self->tokenizers, self->tokenizers->len - 1);
}
static GtkCssParser *
gtk_css_parser_new (GtkCssTokenizer *tokenizer,
GFile *file,
@@ -64,7 +76,11 @@ gtk_css_parser_new (GtkCssTokenizer *tokenizer,
self = g_new0 (GtkCssParser, 1);
self->ref_count = 1;
self->tokenizer = gtk_css_tokenizer_ref (tokenizer);
self->tokenizers = g_ptr_array_new ();
g_ptr_array_add (self->tokenizers, gtk_css_tokenizer_ref (tokenizer));
g_ptr_array_set_free_func (self->tokenizers, (GDestroyNotify) gtk_css_tokenizer_unref);
if (file)
{
self->file = g_object_ref (file);
@@ -117,19 +133,46 @@ gtk_css_parser_new_for_bytes (GBytes *bytes,
return result;
}
GtkCssParser *
gtk_css_parser_new_for_token_stream (GtkCssVariableValue *value,
GFile *file,
GtkCssVariableValue **refs,
gsize n_refs,
GtkCssParserErrorFunc error_func,
gpointer user_data,
GDestroyNotify user_destroy)
{
GtkCssTokenizer *tokenizer;
GtkCssParser *result;
tokenizer = gtk_css_tokenizer_new_for_range (value->bytes, value->offset,
value->end_offset - value->offset);
result = gtk_css_parser_new (tokenizer, file, error_func, user_data, user_destroy);
gtk_css_tokenizer_unref (tokenizer);
result->refs = refs;
result->n_refs = n_refs;
result->next_ref = 0;
return result;
}
static void
gtk_css_parser_finalize (GtkCssParser *self)
{
if (self->user_destroy)
self->user_destroy (self->user_data);
g_clear_pointer (&self->tokenizer, gtk_css_tokenizer_unref);
g_clear_pointer (&self->tokenizers, g_ptr_array_unref);
g_clear_object (&self->file);
g_clear_object (&self->directory);
if (self->blocks->len)
g_critical ("Finalizing CSS parser with %u remaining blocks", self->blocks->len);
g_array_free (self->blocks, TRUE);
if (self->refs)
g_free (self->refs);
g_free (self);
}
@@ -239,7 +282,7 @@ gtk_css_parser_get_start_location (GtkCssParser *self)
const GtkCssLocation *
gtk_css_parser_get_end_location (GtkCssParser *self)
{
return gtk_css_tokenizer_get_location (self->tokenizer);
return gtk_css_tokenizer_get_location (get_tokenizer (self));
}
/**
@@ -273,12 +316,14 @@ static void
gtk_css_parser_ensure_token (GtkCssParser *self)
{
GError *error = NULL;
GtkCssTokenizer *tokenizer;
if (!gtk_css_token_is (&self->token, GTK_CSS_TOKEN_EOF))
return;
self->location = *gtk_css_tokenizer_get_location (self->tokenizer);
if (!gtk_css_tokenizer_read_token (self->tokenizer, &self->token, &error))
tokenizer = get_tokenizer (self);
self->location = *gtk_css_tokenizer_get_location (tokenizer);
if (!gtk_css_tokenizer_read_token (tokenizer, &self->token, &error))
{
/* We ignore the error here, because the resulting token will
* likely already trigger an error in the parsing code and
@@ -286,6 +331,64 @@ gtk_css_parser_ensure_token (GtkCssParser *self)
*/
g_clear_error (&error);
}
if (self->tokenizers->len > 1 && gtk_css_token_is (&self->token, GTK_CSS_TOKEN_EOF))
{
g_ptr_array_remove_index_fast (self->tokenizers, self->tokenizers->len - 1);
gtk_css_parser_ensure_token (self);
return;
}
/* Resolve var(--name): skip it and insert the resolved reference instead */
if (self->n_refs > 0 && gtk_css_token_is_function (&self->token, "var") && self->var_fallback == 0)
{
GtkCssVariableValue *ref;
GtkCssTokenizer *ref_tokenizer;
gtk_css_parser_start_block (self);
if (gtk_css_parser_has_token (self, GTK_CSS_TOKEN_IDENT))
{
char *var_name = gtk_css_parser_consume_ident (self);
if (var_name[0] != '-' || var_name[1] != '-')
{
g_free (var_name);
self->var_fallback++;
gtk_css_parser_skip (self);
gtk_css_parser_end_block (self);
self->var_fallback--;
return;
}
g_free (var_name);
}
else
{
self->var_fallback++;
gtk_css_parser_skip (self);
gtk_css_parser_end_block (self);
self->var_fallback--;
return;
}
/* If we encounter var() in a fallback when we can already resolve the
* actual variable, skip it */
self->var_fallback++;
gtk_css_parser_skip (self);
gtk_css_parser_end_block (self);
self->var_fallback--;
g_assert (self->next_ref < self->n_refs);
ref = self->refs[self->next_ref++];
ref_tokenizer = gtk_css_tokenizer_new_for_range (ref->bytes, ref->offset,
ref->end_offset - ref->offset);
g_ptr_array_add (self->tokenizers, ref_tokenizer);
gtk_css_parser_ensure_token (self);
}
}
const GtkCssToken *
@@ -1112,3 +1215,274 @@ gtk_css_parser_consume_any (GtkCssParser *parser,
return result;
}
gboolean
gtk_css_parser_has_references (GtkCssParser *self)
{
GtkCssTokenizer *tokenizer = get_tokenizer (self);
gboolean ret = FALSE;
int inner_blocks = 0, i;
gtk_css_tokenizer_save (tokenizer);
do {
const GtkCssToken *token;
token = gtk_css_parser_get_token (self);
if (inner_blocks == 0)
{
if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
break;
if (gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_SQUARE))
{
goto error;
}
}
if (gtk_css_token_is_preserved (token, NULL))
{
if (inner_blocks > 0 && gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
gtk_css_parser_end_block (self);
inner_blocks--;
}
else
{
gtk_css_parser_consume_token (self);
}
}
else
{
gboolean is_var = gtk_css_token_is_function (token, "var");
inner_blocks++;
gtk_css_parser_start_block (self);
if (!ret && is_var)
{
token = gtk_css_parser_get_token (self);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
const char *var_name = gtk_css_token_get_string (token);
if (var_name[0] != '-' || var_name[1] != '-')
goto error;
gtk_css_parser_consume_token (self);
if (!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_EOF) &&
!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_COMMA))
{
goto error;
}
ret = TRUE;
}
}
}
}
while (!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SEMICOLON) &&
!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_CLOSE_CURLY));
if (inner_blocks > 0)
goto error;
gtk_css_tokenizer_restore (tokenizer);
self->location = *gtk_css_tokenizer_get_location (tokenizer);
gtk_css_tokenizer_read_token (tokenizer, &self->token, NULL);
return ret;
error:
for (i = 0; i < inner_blocks; i++)
gtk_css_parser_end_block (self);
gtk_css_tokenizer_restore (tokenizer);
self->location = *gtk_css_tokenizer_get_location (tokenizer);
gtk_css_tokenizer_read_token (tokenizer, &self->token, NULL);
return FALSE;
}
static void
clear_ref (GtkCssVariableValueReference *ref)
{
g_free (ref->name);
if (ref->fallback)
gtk_css_variable_value_unref (ref->fallback);
}
GtkCssVariableValue *
gtk_css_parser_parse_value_into_token_stream (GtkCssParser *self)
{
GBytes *bytes = gtk_css_tokenizer_get_bytes (get_tokenizer (self));
const GtkCssToken *token;
gsize offset;
gsize length = 0;
GArray *refs;
GtkCssVariableValueReference *out_refs;
gsize n_refs;
int inner_blocks = 0, i;
gboolean is_initial = FALSE;
refs = g_array_new (FALSE, TRUE, sizeof (GtkCssVariableValueReference));
g_array_set_clear_func (refs, (GDestroyNotify) clear_ref);
for (token = gtk_css_parser_peek_token (self);
gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
token = gtk_css_parser_peek_token (self))
{
gtk_css_parser_consume_token (self);
}
offset = self->location.bytes;
do {
token = gtk_css_parser_get_token (self);
if (length == 0 && gtk_css_token_is_ident (token, "initial"))
is_initial = TRUE;
if (gtk_css_token_is (token, GTK_CSS_TOKEN_BAD_STRING) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_BAD_URL))
{
gtk_css_parser_error_syntax (self, "Invalid property value");
goto error;
}
if (inner_blocks == 0)
{
if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
break;
if (gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_PARENS) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_CLOSE_SQUARE))
{
gtk_css_parser_error_syntax (self, "Invalid property value");
goto error;
}
}
if (gtk_css_token_is_preserved (token, NULL))
{
if (inner_blocks > 0 && gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
length++;
gtk_css_parser_end_block (self);
inner_blocks--;
}
else
{
length++;
gtk_css_parser_consume_token (self);
}
}
else
{
gboolean is_var = gtk_css_token_is_function (token, "var");
length++;
inner_blocks++;
gtk_css_parser_start_block (self);
if (is_var)
{
token = gtk_css_parser_get_token (self);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
{
GtkCssVariableValueReference ref;
char *var_name = g_strdup (gtk_css_token_get_string (token));
if (var_name[0] != '-' || var_name[1] != '-')
{
gtk_css_parser_error_value (self, "Invalid variable name: %s", var_name);
g_free (var_name);
goto error;
}
length++;
gtk_css_parser_consume_token (self);
if (!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_EOF) &&
!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_COMMA))
{
gtk_css_parser_error_syntax (self, "Invalid property value");
g_free (var_name);
goto error;
}
ref.name = var_name;
if (gtk_css_parser_has_token (self, GTK_CSS_TOKEN_EOF))
{
ref.length = 3;
ref.fallback = NULL;
}
else
{
length++;
gtk_css_parser_consume_token (self);
ref.fallback = gtk_css_parser_parse_value_into_token_stream (self);
if (ref.fallback == NULL)
{
gtk_css_parser_error_value (self, "Invalid fallback for: %s", var_name);
g_free (var_name);
goto error;
}
ref.length = 4 + ref.fallback->length;
length += ref.fallback->length;
}
g_array_append_val (refs, ref);
}
}
}
}
while (!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_SEMICOLON) &&
!gtk_css_parser_has_token (self, GTK_CSS_TOKEN_CLOSE_CURLY));
if (inner_blocks > 0)
{
gtk_css_parser_error_syntax (self, "Invalid property value");
goto error;
}
if (is_initial && length == 1)
{
g_array_unref (refs);
return gtk_css_variable_value_new_initial (bytes,
offset,
self->location.bytes);
}
else
{
out_refs = g_array_steal (refs, &n_refs);
return gtk_css_variable_value_new (bytes,
offset,
self->location.bytes,
length,
out_refs,
n_refs);
}
error:
for (i = 0; i < inner_blocks; i++)
gtk_css_parser_end_block (self);
g_array_unref (refs);
return NULL;
}

View File

@@ -22,6 +22,7 @@
#include "gtkcssenums.h"
#include "gtkcsstokenizerprivate.h"
#include "gtkcssvariablevalueprivate.h"
#include <gio/gio.h>
@@ -58,6 +59,13 @@ GtkCssParser * gtk_css_parser_new_for_bytes (GBytes
GtkCssParserErrorFunc error_func,
gpointer user_data,
GDestroyNotify user_destroy);
GtkCssParser * gtk_css_parser_new_for_token_stream (GtkCssVariableValue *value,
GFile *file,
GtkCssVariableValue **refs,
gsize n_refs,
GtkCssParserErrorFunc error_func,
gpointer user_data,
GDestroyNotify user_destroy);
GtkCssParser * gtk_css_parser_ref (GtkCssParser *self);
void gtk_css_parser_unref (GtkCssParser *self);
@@ -150,5 +158,9 @@ gsize gtk_css_parser_consume_any (GtkCssParser
gsize n_options,
gpointer user_data);
gboolean gtk_css_parser_has_references (GtkCssParser *parser);
GtkCssVariableValue * gtk_css_parser_parse_value_into_token_stream (GtkCssParser *parser);
G_END_DECLS

View File

@@ -36,8 +36,15 @@ struct _GtkCssTokenizer
const char *end;
GtkCssLocation position;
GArray *saved_states;
};
typedef struct
{
GtkCssLocation position;
const char *data;
} GtkCssTokenizerSavedState;
void
gtk_css_token_clear (GtkCssToken *token)
{
@@ -568,6 +575,14 @@ gtk_css_token_init_dimension (GtkCssToken *token,
GtkCssTokenizer *
gtk_css_tokenizer_new (GBytes *bytes)
{
return gtk_css_tokenizer_new_for_range (bytes, 0, g_bytes_get_size (bytes));
}
GtkCssTokenizer *
gtk_css_tokenizer_new_for_range (GBytes *bytes,
gsize offset,
gsize length)
{
GtkCssTokenizer *tokenizer;
@@ -576,10 +591,11 @@ gtk_css_tokenizer_new (GBytes *bytes)
tokenizer->bytes = g_bytes_ref (bytes);
tokenizer->name_buffer = g_string_new (NULL);
tokenizer->data = g_bytes_get_data (bytes, NULL);
tokenizer->end = tokenizer->data + g_bytes_get_size (bytes);
tokenizer->data = g_bytes_get_region (bytes, 1, offset, length);
tokenizer->end = tokenizer->data + length;
gtk_css_location_init (&tokenizer->position);
tokenizer->saved_states = g_array_new (FALSE, FALSE, sizeof (GtkCssTokenizerSavedState));
return tokenizer;
}
@@ -601,9 +617,16 @@ gtk_css_tokenizer_unref (GtkCssTokenizer *tokenizer)
g_string_free (tokenizer->name_buffer, TRUE);
g_bytes_unref (tokenizer->bytes);
g_array_unref (tokenizer->saved_states);
g_free (tokenizer);
}
GBytes *
gtk_css_tokenizer_get_bytes (GtkCssTokenizer *tokenizer)
{
return tokenizer->bytes;
}
const GtkCssLocation *
gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer)
{
@@ -1020,7 +1043,7 @@ gtk_css_tokenizer_read_ident_like (GtkCssTokenizer *tokenizer,
{
gtk_css_tokenizer_read_name (tokenizer);
if (*tokenizer->data == '(')
if (gtk_css_tokenizer_remaining (tokenizer) > 0 && *tokenizer->data == '(')
{
gtk_css_tokenizer_consume_ascii (tokenizer);
if (g_ascii_strcasecmp (tokenizer->name_buffer->str, "url") == 0)
@@ -1484,3 +1507,29 @@ gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
}
}
void
gtk_css_tokenizer_save (GtkCssTokenizer *tokenizer)
{
GtkCssTokenizerSavedState state;
state.position = tokenizer->position;
state.data = tokenizer->data;
g_array_append_val (tokenizer->saved_states, state);
}
void
gtk_css_tokenizer_restore (GtkCssTokenizer *tokenizer)
{
GtkCssTokenizerSavedState state;
int index = tokenizer->saved_states->len - 1;
g_assert (index >= 0);
state = g_array_index (tokenizer->saved_states, GtkCssTokenizerSavedState, index);
g_array_remove_index_fast (tokenizer->saved_states, index);
tokenizer->position = state.position;
tokenizer->data = state.data;
}

View File

@@ -138,15 +138,22 @@ void gtk_css_token_print (const GtkCssTok
char * gtk_css_token_to_string (const GtkCssToken *token);
GtkCssTokenizer * gtk_css_tokenizer_new (GBytes *bytes);
GtkCssTokenizer * gtk_css_tokenizer_new_for_range (GBytes *bytes,
gsize offset,
gsize length);
GtkCssTokenizer * gtk_css_tokenizer_ref (GtkCssTokenizer *tokenizer);
void gtk_css_tokenizer_unref (GtkCssTokenizer *tokenizer);
GBytes * gtk_css_tokenizer_get_bytes (GtkCssTokenizer *tokenizer);
const GtkCssLocation * gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer) G_GNUC_CONST;
gboolean gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
GtkCssToken *token,
GError **error);
void gtk_css_tokenizer_save (GtkCssTokenizer *tokenizer);
void gtk_css_tokenizer_restore (GtkCssTokenizer *tokenizer);
G_END_DECLS

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#include "gtkcssvariablevalueprivate.h"
GtkCssVariableValue *
gtk_css_variable_value_new (GBytes *bytes,
gsize offset,
gsize end_offset,
gsize length,
GtkCssVariableValueReference *references,
gsize n_references)
{
GtkCssVariableValue *self = g_new0 (GtkCssVariableValue, 1);
self->ref_count = 1;
self->bytes = g_bytes_ref (bytes);
self->offset = offset;
self->end_offset = end_offset;
self->length = length;
self->references = references;
self->n_references = n_references;
return self;
}
GtkCssVariableValue *
gtk_css_variable_value_new_initial (GBytes *bytes,
gsize offset,
gsize end_offset)
{
GtkCssVariableValue *self = gtk_css_variable_value_new (bytes, offset, end_offset, 1, NULL, 0);
self->is_invalid = TRUE;
return self;
}
GtkCssVariableValue *
gtk_css_variable_value_ref (GtkCssVariableValue *self)
{
self->ref_count++;
return self;
}
void
gtk_css_variable_value_unref (GtkCssVariableValue *self)
{
gsize i;
self->ref_count--;
if (self->ref_count > 0)
return;
g_bytes_unref (self->bytes);
for (i = 0; i < self->n_references; i++)
{
GtkCssVariableValueReference *ref = &self->references[i];
g_free (ref->name);
if (ref->fallback)
gtk_css_variable_value_unref (ref->fallback);
}
g_free (self->references);
g_free (self);
}
void
gtk_css_variable_value_print (GtkCssVariableValue *self,
GString *string)
{
gsize len = self->end_offset - self->offset;
gconstpointer data = g_bytes_get_region (self->bytes, 1, self->offset, len);
g_assert (data != NULL);
g_string_append_len (string, (const char *) data, len);
}
gboolean
gtk_css_variable_value_equal (const GtkCssVariableValue *value1,
const GtkCssVariableValue *value2)
{
if (value1 == value2)
return TRUE;
if (value1 == NULL || value2 == NULL)
return FALSE;
if (value1->bytes != value2->bytes)
return FALSE;
if (value1->offset != value2->offset)
return FALSE;
if (value1->end_offset != value2->end_offset)
return FALSE;
return TRUE;
}
GtkCssVariableValue *
gtk_css_variable_value_transition (GtkCssVariableValue *start,
GtkCssVariableValue *end,
double progress)
{
GtkCssVariableValue *ret = progress < 0.5 ? start : end;
if (ret == NULL)
return NULL;
return gtk_css_variable_value_ref (ret);
}
void
gtk_css_variable_value_set_section (GtkCssVariableValue *self,
GtkCssSection *section)
{
self->section = gtk_css_section_ref (section);
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#pragma once
#include "gtkcss.h"
#include "gtkcsstokenizerprivate.h"
G_BEGIN_DECLS
typedef struct _GtkCssVariableValueReference GtkCssVariableValueReference;
typedef struct _GtkCssVariableValue GtkCssVariableValue;
struct _GtkCssVariableValueReference
{
char *name;
gsize length;
GtkCssVariableValue *fallback;
};
struct _GtkCssVariableValue
{
int ref_count;
GBytes *bytes;
gsize offset;
gsize end_offset;
gsize length;
GtkCssVariableValueReference *references;
gsize n_references;
GtkCssSection *section;
gboolean is_invalid;
};
GtkCssVariableValue *gtk_css_variable_value_new (GBytes *bytes,
gsize offset,
gsize end_offset,
gsize length,
GtkCssVariableValueReference *references,
gsize n_references);
GtkCssVariableValue *gtk_css_variable_value_new_initial (GBytes *bytes,
gsize offset,
gsize end_offset);
GtkCssVariableValue *gtk_css_variable_value_ref (GtkCssVariableValue *self);
void gtk_css_variable_value_unref (GtkCssVariableValue *self);
void gtk_css_variable_value_print (GtkCssVariableValue *self,
GString *string);
gboolean gtk_css_variable_value_equal (const GtkCssVariableValue *value1,
const GtkCssVariableValue *value2) G_GNUC_PURE;
GtkCssVariableValue *gtk_css_variable_value_transition (GtkCssVariableValue *start,
GtkCssVariableValue *end,
double progress);
void gtk_css_variable_value_set_section (GtkCssVariableValue *self,
GtkCssSection *section);
G_END_DECLS

View File

@@ -6,8 +6,9 @@ gtk_css_public_sources = files([
gtk_css_private_sources = files([
'gtkcssdataurl.c',
'gtkcssparser.c',
'gtkcsstokenizer.c',
'gtkcssserializer.c',
'gtkcsstokenizer.c',
'gtkcssvariablevalue.c',
])
gtk_css_public_headers = files([

View File

@@ -37,9 +37,178 @@
#include "gtkstyleanimationprivate.h"
#include "gtkstylepropertyprivate.h"
#include "gtkstyleproviderprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
G_DEFINE_TYPE (GtkCssAnimatedStyle, gtk_css_animated_style, GTK_TYPE_CSS_STYLE)
static const int core_props[] = {
GTK_CSS_PROPERTY_COLOR,
GTK_CSS_PROPERTY_DPI,
GTK_CSS_PROPERTY_FONT_SIZE,
GTK_CSS_PROPERTY_ICON_PALETTE
};
static const int background_props[] = {
GTK_CSS_PROPERTY_BACKGROUND_COLOR,
GTK_CSS_PROPERTY_BOX_SHADOW,
GTK_CSS_PROPERTY_BACKGROUND_CLIP,
GTK_CSS_PROPERTY_BACKGROUND_ORIGIN,
GTK_CSS_PROPERTY_BACKGROUND_SIZE,
GTK_CSS_PROPERTY_BACKGROUND_POSITION,
GTK_CSS_PROPERTY_BACKGROUND_REPEAT,
GTK_CSS_PROPERTY_BACKGROUND_IMAGE,
GTK_CSS_PROPERTY_BACKGROUND_BLEND_MODE
};
static const int border_props[] = {
GTK_CSS_PROPERTY_BORDER_TOP_STYLE,
GTK_CSS_PROPERTY_BORDER_TOP_WIDTH,
GTK_CSS_PROPERTY_BORDER_LEFT_STYLE,
GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH,
GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE,
GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH,
GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE,
GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH,
GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS,
GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS,
GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS,
GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS,
GTK_CSS_PROPERTY_BORDER_TOP_COLOR,
GTK_CSS_PROPERTY_BORDER_RIGHT_COLOR,
GTK_CSS_PROPERTY_BORDER_BOTTOM_COLOR,
GTK_CSS_PROPERTY_BORDER_LEFT_COLOR,
GTK_CSS_PROPERTY_BORDER_IMAGE_SOURCE,
GTK_CSS_PROPERTY_BORDER_IMAGE_REPEAT,
GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE,
GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH
};
static const int icon_props[] = {
GTK_CSS_PROPERTY_ICON_SIZE,
GTK_CSS_PROPERTY_ICON_SHADOW,
GTK_CSS_PROPERTY_ICON_STYLE,
};
static const int outline_props[] = {
GTK_CSS_PROPERTY_OUTLINE_STYLE,
GTK_CSS_PROPERTY_OUTLINE_WIDTH,
GTK_CSS_PROPERTY_OUTLINE_OFFSET,
GTK_CSS_PROPERTY_OUTLINE_COLOR,
};
static const int font_props[] = {
GTK_CSS_PROPERTY_FONT_FAMILY,
GTK_CSS_PROPERTY_FONT_STYLE,
GTK_CSS_PROPERTY_FONT_WEIGHT,
GTK_CSS_PROPERTY_FONT_STRETCH,
GTK_CSS_PROPERTY_LETTER_SPACING,
GTK_CSS_PROPERTY_TEXT_SHADOW,
GTK_CSS_PROPERTY_CARET_COLOR,
GTK_CSS_PROPERTY_SECONDARY_CARET_COLOR,
GTK_CSS_PROPERTY_FONT_FEATURE_SETTINGS,
GTK_CSS_PROPERTY_FONT_VARIATION_SETTINGS,
GTK_CSS_PROPERTY_LINE_HEIGHT,
};
static const int font_variant_props[] = {
GTK_CSS_PROPERTY_TEXT_DECORATION_LINE,
GTK_CSS_PROPERTY_TEXT_DECORATION_COLOR,
GTK_CSS_PROPERTY_TEXT_DECORATION_STYLE,
GTK_CSS_PROPERTY_TEXT_TRANSFORM,
GTK_CSS_PROPERTY_FONT_KERNING,
GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES,
GTK_CSS_PROPERTY_FONT_VARIANT_POSITION,
GTK_CSS_PROPERTY_FONT_VARIANT_CAPS,
GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC,
GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES,
GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN,
};
static const int animation_props[] = {
GTK_CSS_PROPERTY_ANIMATION_NAME,
GTK_CSS_PROPERTY_ANIMATION_DURATION,
GTK_CSS_PROPERTY_ANIMATION_TIMING_FUNCTION,
GTK_CSS_PROPERTY_ANIMATION_ITERATION_COUNT,
GTK_CSS_PROPERTY_ANIMATION_DIRECTION,
GTK_CSS_PROPERTY_ANIMATION_PLAY_STATE,
GTK_CSS_PROPERTY_ANIMATION_DELAY,
GTK_CSS_PROPERTY_ANIMATION_FILL_MODE,
};
static const int transition_props[] = {
GTK_CSS_PROPERTY_TRANSITION_PROPERTY,
GTK_CSS_PROPERTY_TRANSITION_DURATION,
GTK_CSS_PROPERTY_TRANSITION_TIMING_FUNCTION,
GTK_CSS_PROPERTY_TRANSITION_DELAY,
};
static const int size_props[] = {
GTK_CSS_PROPERTY_MARGIN_TOP,
GTK_CSS_PROPERTY_MARGIN_LEFT,
GTK_CSS_PROPERTY_MARGIN_BOTTOM,
GTK_CSS_PROPERTY_MARGIN_RIGHT,
GTK_CSS_PROPERTY_PADDING_TOP,
GTK_CSS_PROPERTY_PADDING_LEFT,
GTK_CSS_PROPERTY_PADDING_BOTTOM,
GTK_CSS_PROPERTY_PADDING_RIGHT,
GTK_CSS_PROPERTY_BORDER_SPACING,
GTK_CSS_PROPERTY_MIN_WIDTH,
GTK_CSS_PROPERTY_MIN_HEIGHT,
};
static const int other_props[] = {
GTK_CSS_PROPERTY_ICON_SOURCE,
GTK_CSS_PROPERTY_ICON_TRANSFORM,
GTK_CSS_PROPERTY_ICON_FILTER,
GTK_CSS_PROPERTY_TRANSFORM,
GTK_CSS_PROPERTY_TRANSFORM_ORIGIN,
GTK_CSS_PROPERTY_OPACITY,
GTK_CSS_PROPERTY_FILTER,
};
#define DEFINE_VALUES(ENUM, TYPE, NAME) \
static inline void \
gtk_css_ ## NAME ## _values_recompute (GtkCssAnimatedStyle *animated) \
{ \
GtkCssStyle *style = (GtkCssStyle *)animated; \
GtkCssValue **values = (GtkCssValue **)((guint8*)(animated->style->NAME) + sizeof (GtkCssValues)); \
int i; \
\
for (i = 0; i < G_N_ELEMENTS (NAME ## _props); i++) \
{ \
guint id = NAME ## _props[i]; \
GtkCssValue *original, *computed; \
\
if (values[i] == NULL) \
continue; \
\
original = gtk_css_style_get_original_value (style, id); \
if (original == NULL) \
continue; \
\
computed = _gtk_css_value_compute (original, \
id, \
animated->provider, \
style, \
animated->parent_style, \
NULL); \
if (computed == NULL) \
continue; \
\
gtk_css_animated_style_set_animated_value (animated, id, computed); \
} \
}
DEFINE_VALUES (CORE, Core, core)
DEFINE_VALUES (BACKGROUND, Background, background)
DEFINE_VALUES (BORDER, Border, border)
DEFINE_VALUES (ICON, Icon, icon)
DEFINE_VALUES (OUTLINE, Outline, outline)
DEFINE_VALUES (FONT, Font, font)
DEFINE_VALUES (FONT_VARIANT, FontVariant, font_variant)
DEFINE_VALUES (ANIMATION, Animation, animation)
DEFINE_VALUES (TRANSITION, Transition, transition)
DEFINE_VALUES (SIZE, Size, size)
DEFINE_VALUES (OTHER, Other, other)
static GtkCssSection *
gtk_css_animated_style_get_section (GtkCssStyle *style,
@@ -74,6 +243,15 @@ gtk_css_animated_style_get_static_style (GtkCssStyle *style)
return (GtkCssStaticStyle *)animated->style;
}
static GtkCssValue *
gtk_css_animated_style_get_original_value (GtkCssStyle *style,
guint id)
{
GtkCssAnimatedStyle *animated = GTK_CSS_ANIMATED_STYLE (style);
return gtk_css_style_get_original_value (animated->style, id);
}
static void
gtk_css_animated_style_dispose (GObject *object)
{
@@ -96,6 +274,9 @@ gtk_css_animated_style_finalize (GObject *object)
GtkCssAnimatedStyle *style = GTK_CSS_ANIMATED_STYLE (object);
g_object_unref (style->style);
if (style->parent_style)
g_object_unref (style->parent_style);
g_object_unref (style->provider);
G_OBJECT_CLASS (gtk_css_animated_style_parent_class)->finalize (object);
}
@@ -112,6 +293,7 @@ gtk_css_animated_style_class_init (GtkCssAnimatedStyleClass *klass)
style_class->get_section = gtk_css_animated_style_get_section;
style_class->is_static = gtk_css_animated_style_is_static;
style_class->get_static_style = gtk_css_animated_style_get_static_style;
style_class->get_original_value = gtk_css_animated_style_get_original_value;
}
static void
@@ -546,6 +728,51 @@ gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
return gtk_css_style_get_value (style->style, id);
}
void
gtk_css_animated_style_set_animated_custom_value (GtkCssAnimatedStyle *animated,
int id,
GtkCssVariableValue *value)
{
GtkCssStyle *style = (GtkCssStyle *)animated;
gtk_internal_return_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style));
gtk_internal_return_if_fail (value != NULL);
if (style->variables == NULL)
{
style->variables = gtk_css_variable_set_new ();
if (animated->parent_style)
gtk_css_variable_set_set_parent (style->variables,
animated->parent_style->variables);
}
else if (style->variables == animated->style->variables)
{
gtk_css_variable_set_unref (style->variables);
style->variables = gtk_css_variable_set_copy (animated->style->variables);
}
gtk_css_variable_set_add (style->variables, id, value);
gtk_css_core_values_recompute (animated);
gtk_css_background_values_recompute (animated);
gtk_css_border_values_recompute (animated);
gtk_css_icon_values_recompute (animated);
gtk_css_outline_values_recompute (animated);
gtk_css_font_values_recompute (animated);
gtk_css_font_variant_values_recompute (animated);
gtk_css_animation_values_recompute (animated);
gtk_css_transition_values_recompute (animated);
gtk_css_size_values_recompute (animated);
gtk_css_other_values_recompute (animated);
}
GtkCssVariableValue *
gtk_css_animated_style_get_intrinsic_custom_value (GtkCssAnimatedStyle *style,
int id)
{
return gtk_css_style_get_custom_property (style->style, id);
}
static GPtrArray *
gtk_css_animated_style_create_dynamic (GPtrArray *animations,
GtkCssStyle *style,
@@ -770,7 +997,6 @@ gtk_css_animated_style_find_animation (GtkStyleAnimation **animations,
static GPtrArray *
gtk_css_animated_style_create_css_animations (GPtrArray *animations,
GtkCssStyle *base_style,
GtkCssStyle *parent_style,
gint64 timestamp,
GtkStyleProvider *provider,
GtkCssStyle *source)
@@ -832,8 +1058,6 @@ gtk_css_animated_style_create_css_animations (GPtrArray *animations,
if (keyframes == NULL)
continue;
keyframes = _gtk_css_keyframes_compute (keyframes, provider, base_style, parent_style);
animation = _gtk_css_animation_new (name,
keyframes,
timestamp,
@@ -844,7 +1068,6 @@ gtk_css_animated_style_create_css_animations (GPtrArray *animations,
_gtk_css_play_state_value_get (_gtk_css_array_value_get_nth (play_states, i)),
_gtk_css_fill_mode_value_get (_gtk_css_array_value_get_nth (fill_modes, i)),
_gtk_css_number_value_get (_gtk_css_array_value_get_nth (iteration_counts, i), 100));
_gtk_css_keyframes_unref (keyframes);
}
if (!animations)
@@ -893,7 +1116,7 @@ gtk_css_animated_style_new (GtkCssStyle *base_style,
if (previous_style != NULL)
animations = gtk_css_animated_style_create_css_transitions (animations, base_style, timestamp, previous_style);
animations = gtk_css_animated_style_create_css_animations (animations, base_style, parent_style, timestamp, provider, previous_style);
animations = gtk_css_animated_style_create_css_animations (animations, base_style, timestamp, provider, previous_style);
animations = gtk_css_animated_style_create_dynamic (animations, base_style, timestamp);
if (animations == NULL)
@@ -902,6 +1125,9 @@ gtk_css_animated_style_new (GtkCssStyle *base_style,
result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL);
result->style = g_object_ref (base_style);
if (parent_style)
result->parent_style = g_object_ref (parent_style);
result->provider = g_object_ref (provider);
result->current_time = timestamp;
result->n_animations = animations->len;
result->animations = g_ptr_array_free (animations, FALSE);
@@ -918,6 +1144,8 @@ gtk_css_animated_style_new (GtkCssStyle *base_style,
style->transition = (GtkCssTransitionValues *)gtk_css_values_ref ((GtkCssValues *)base_style->transition);
style->size = (GtkCssSizeValues *)gtk_css_values_ref ((GtkCssValues *)base_style->size);
style->other = (GtkCssOtherValues *)gtk_css_values_ref ((GtkCssValues *)base_style->other);
if (base_style->variables)
style->variables = gtk_css_variable_set_ref (base_style->variables);
gtk_css_animated_style_apply_animations (result);
@@ -927,7 +1155,9 @@ gtk_css_animated_style_new (GtkCssStyle *base_style,
GtkCssStyle *
gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
GtkCssStyle *base_style,
gint64 timestamp)
GtkCssStyle *parent_style,
gint64 timestamp,
GtkStyleProvider *provider)
{
GtkCssAnimatedStyle *result;
GtkCssStyle *style;
@@ -936,6 +1166,8 @@ gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (source), NULL);
gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (base_style), NULL);
gtk_internal_return_val_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style), NULL);
gtk_internal_return_val_if_fail (GTK_IS_STYLE_PROVIDER (provider), NULL);
if (timestamp == 0)
return g_object_ref (source->style);
@@ -966,6 +1198,9 @@ gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
result = g_object_new (GTK_TYPE_CSS_ANIMATED_STYLE, NULL);
result->style = g_object_ref (base_style);
if (parent_style)
result->parent_style = g_object_ref (parent_style);
result->provider = g_object_ref (provider);
result->current_time = timestamp;
result->n_animations = animations->len;
result->animations = g_ptr_array_free (animations, FALSE);
@@ -982,8 +1217,34 @@ gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
style->transition = (GtkCssTransitionValues *)gtk_css_values_ref ((GtkCssValues *)base_style->transition);
style->size = (GtkCssSizeValues *)gtk_css_values_ref ((GtkCssValues *)base_style->size);
style->other = (GtkCssOtherValues *)gtk_css_values_ref ((GtkCssValues *)base_style->other);
if (base_style->variables)
style->variables = gtk_css_variable_set_ref (base_style->variables);
gtk_css_animated_style_apply_animations (result);
return GTK_CSS_STYLE (result);
}
GtkCssStyle *
gtk_css_animated_style_get_base_style (GtkCssAnimatedStyle *style)
{
gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), NULL);
return style->style;
}
GtkCssStyle *
gtk_css_animated_style_get_parent_style (GtkCssAnimatedStyle *style)
{
gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), NULL);
return style->parent_style;
}
GtkStyleProvider *
gtk_css_animated_style_get_provider (GtkCssAnimatedStyle *style)
{
gtk_internal_return_val_if_fail (GTK_IS_CSS_ANIMATED_STYLE (style), NULL);
return style->provider;
}

View File

@@ -38,6 +38,8 @@ struct _GtkCssAnimatedStyle
GtkCssStyle parent;
GtkCssStyle *style; /* the style if we weren't animating */
GtkCssStyle *parent_style;
GtkStyleProvider *provider;
gint64 current_time; /* the current time in our world */
gpointer *animations; /* GtkStyleAnimation**, least important one first */
@@ -57,15 +59,26 @@ GtkCssStyle * gtk_css_animated_style_new (GtkCssStyle
GtkStyleProvider *provider,
GtkCssStyle *previous_style);
GtkCssStyle * gtk_css_animated_style_new_advance (GtkCssAnimatedStyle *source,
GtkCssStyle *base,
gint64 timestamp);
GtkCssStyle *base_style,
GtkCssStyle *parent_style,
gint64 timestamp,
GtkStyleProvider *provider);
void gtk_css_animated_style_set_animated_value(GtkCssAnimatedStyle *style,
guint id,
GtkCssValue *value);
GtkCssValue * gtk_css_animated_style_get_intrinsic_value (GtkCssAnimatedStyle *style,
guint id);
void gtk_css_animated_style_set_animated_custom_value (GtkCssAnimatedStyle *animated,
int id,
GtkCssVariableValue *value);
GtkCssVariableValue * gtk_css_animated_style_get_intrinsic_custom_value (GtkCssAnimatedStyle *style,
int id);
GtkCssStyle * gtk_css_animated_style_get_base_style (GtkCssAnimatedStyle *style);
GtkCssStyle * gtk_css_animated_style_get_parent_style (GtkCssAnimatedStyle *style);
GtkStyleProvider * gtk_css_animated_style_get_provider (GtkCssAnimatedStyle *style);
G_END_DECLS

View File

@@ -90,6 +90,9 @@ gtk_css_animation_apply_values (GtkStyleAnimation *style_animation,
GtkCssAnimatedStyle *style)
{
GtkCssAnimation *animation = (GtkCssAnimation *)style_animation;
GtkCssStyle *base_style, *parent_style;
GtkStyleProvider *provider;
GtkCssKeyframes *resolved_keyframes;
double progress;
guint i;
@@ -99,19 +102,43 @@ gtk_css_animation_apply_values (GtkStyleAnimation *style_animation,
progress = gtk_css_animation_get_progress (animation);
progress = _gtk_css_ease_value_transform (animation->ease, progress);
for (i = 0; i < _gtk_css_keyframes_get_n_properties (animation->keyframes); i++)
base_style = gtk_css_animated_style_get_base_style (style);
parent_style = gtk_css_animated_style_get_parent_style (style);
provider = gtk_css_animated_style_get_provider (style);
resolved_keyframes = _gtk_css_keyframes_compute (animation->keyframes,
provider,
base_style,
parent_style);
for (i = 0; i < _gtk_css_keyframes_get_n_variables (resolved_keyframes); i++)
{
GtkCssVariableValue *value;
int variable_id;
variable_id = _gtk_css_keyframes_get_variable_id (resolved_keyframes, i);
value = _gtk_css_keyframes_get_variable (resolved_keyframes,
i,
progress,
gtk_css_animated_style_get_intrinsic_custom_value (style, variable_id));
gtk_css_animated_style_set_animated_custom_value (style, variable_id, value);
}
for (i = 0; i < _gtk_css_keyframes_get_n_properties (resolved_keyframes); i++)
{
GtkCssValue *value;
guint property_id;
property_id = _gtk_css_keyframes_get_property_id (animation->keyframes, i);
property_id = _gtk_css_keyframes_get_property_id (resolved_keyframes, i);
value = _gtk_css_keyframes_get_value (animation->keyframes,
value = _gtk_css_keyframes_get_value (resolved_keyframes,
i,
progress,
gtk_css_animated_style_get_intrinsic_value (style, property_id));
gtk_css_animated_style_set_animated_value (style, property_id, value);
}
_gtk_css_keyframes_unref (resolved_keyframes);
}
static gboolean

View File

@@ -41,11 +41,12 @@ gtk_css_value_array_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_array_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_array_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *result;
GtkCssValue *i_value;
@@ -54,7 +55,7 @@ gtk_css_value_array_compute (GtkCssValue *value,
result = NULL;
for (i = 0; i < value->n_values; i++)
{
i_value = _gtk_css_value_compute (value->values[i], property_id, provider, style, parent_style);
i_value = _gtk_css_value_compute (value->values[i], property_id, provider, style, parent_style, variables);
if (result == NULL &&
i_value != value->values[i])
@@ -342,6 +343,20 @@ gtk_css_value_array_get_dynamic_value (GtkCssValue *value,
return result;
}
static gboolean
gtk_css_value_array_contains_variables (const GtkCssValue *value)
{
guint i;
for (i = 0; i < value->n_values; i++)
{
if (gtk_css_value_contains_variables (value->values[i]))
return TRUE;
}
return FALSE;
}
static void
gtk_css_value_array_print (const GtkCssValue *value,
GString *string)
@@ -370,6 +385,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_ARRAY = {
gtk_css_value_array_transition,
gtk_css_value_array_is_dynamic,
gtk_css_value_array_get_dynamic_value,
gtk_css_value_array_contains_variables,
gtk_css_value_array_print
};

View File

@@ -41,11 +41,12 @@ gtk_css_value_bg_size_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_bg_size_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_bg_size_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *x, *y;
@@ -55,10 +56,10 @@ gtk_css_value_bg_size_compute (GtkCssValue *value,
x = y = NULL;
if (value->x)
x = _gtk_css_value_compute (value->x, property_id, provider, style, parent_style);
x = _gtk_css_value_compute (value->x, property_id, provider, style, parent_style, variables);
if (value->y)
y = _gtk_css_value_compute (value->y, property_id, provider, style, parent_style);
y = _gtk_css_value_compute (value->y, property_id, provider, style, parent_style, variables);
if (x == value->x && y == value->y)
{
@@ -160,6 +161,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BG_SIZE = {
gtk_css_value_bg_size_transition,
NULL,
NULL,
NULL,
gtk_css_value_bg_size_print
};

View File

@@ -42,11 +42,12 @@ gtk_css_value_border_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_border_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_border_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *values[4];
GtkCssValue *computed;
@@ -57,7 +58,7 @@ gtk_css_value_border_compute (GtkCssValue *value,
{
if (value->values[i])
{
values[i] = _gtk_css_value_compute (value->values[i], property_id, provider, style, parent_style);
values[i] = _gtk_css_value_compute (value->values[i], property_id, provider, style, parent_style, variables);
changed |= (values[i] != value->values[i]);
}
else
@@ -147,6 +148,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BORDER = {
gtk_css_value_border_transition,
NULL,
NULL,
NULL,
gtk_css_value_border_print
};

View File

@@ -94,10 +94,11 @@ gtk_css_value_color_free (GtkCssValue *color)
}
static GtkCssValue *
gtk_css_value_color_get_fallback (guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_color_get_fallback (guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
switch (property_id)
{
@@ -120,7 +121,8 @@ gtk_css_value_color_get_fallback (guint property_id,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
case GTK_CSS_PROPERTY_ICON_PALETTE:
return _gtk_css_value_ref (style->core->color);
default:
@@ -132,11 +134,12 @@ gtk_css_value_color_get_fallback (guint property_id,
}
static GtkCssValue *
gtk_css_value_color_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_color_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *resolved;
@@ -173,7 +176,7 @@ gtk_css_value_color_compute (GtkCssValue *value,
}
if (resolved == NULL)
return gtk_css_value_color_get_fallback (property_id, provider, style, parent_style);
return gtk_css_value_color_get_fallback (property_id, provider, style, parent_style, variables);
return resolved;
}
@@ -293,6 +296,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_COLOR = {
gtk_css_value_color_transition,
NULL,
NULL,
NULL,
gtk_css_value_color_print
};

View File

@@ -37,16 +37,17 @@ gtk_css_value_corner_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_corner_compute (GtkCssValue *corner,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_corner_compute (GtkCssValue *corner,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *x, *y;
x = _gtk_css_value_compute (corner->x, property_id, provider, style, parent_style);
y = _gtk_css_value_compute (corner->y, property_id, provider, style, parent_style);
x = _gtk_css_value_compute (corner->x, property_id, provider, style, parent_style, variables);
y = _gtk_css_value_compute (corner->y, property_id, provider, style, parent_style, variables);
if (x == corner->x && y == corner->y)
{
_gtk_css_value_unref (x);
@@ -106,6 +107,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_CORNER = {
gtk_css_value_corner_transition,
NULL,
NULL,
NULL,
gtk_css_value_corner_print
};

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#include "gtkcsscustompropertypoolprivate.h"
struct _GtkCssCustomPropertyPool
{
GObject parent_instance;
GArray *names;
GHashTable *name_mappings;
};
struct _GtkCssCustomPropertyName
{
int ref_count;
char *name;
};
typedef struct _GtkCssCustomPropertyName GtkCssCustomPropertyName;
static GtkCssCustomPropertyPool *instance = NULL;
G_DEFINE_FINAL_TYPE (GtkCssCustomPropertyPool, gtk_css_custom_property_pool, G_TYPE_OBJECT)
static void
clear_custom_property_name (GtkCssCustomPropertyName *name)
{
g_clear_pointer (&name->name, g_free);
}
static void
gtk_css_custom_property_pool_finalize (GObject *object)
{
GtkCssCustomPropertyPool *self = (GtkCssCustomPropertyPool *)object;
g_hash_table_unref (self->name_mappings);
g_array_unref (self->names);
G_OBJECT_CLASS (gtk_css_custom_property_pool_parent_class)->finalize (object);
}
static void
gtk_css_custom_property_pool_class_init (GtkCssCustomPropertyPoolClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_css_custom_property_pool_finalize;
}
static void
gtk_css_custom_property_pool_init (GtkCssCustomPropertyPool *self)
{
self->name_mappings = g_hash_table_new (g_str_hash, g_str_equal);
self->names = g_array_new (FALSE, FALSE, sizeof (GtkCssCustomPropertyName));
g_array_set_clear_func (self->names, (GDestroyNotify) clear_custom_property_name);
}
GtkCssCustomPropertyPool *
gtk_css_custom_property_pool_get (void)
{
if (instance == NULL)
instance = g_object_new (GTK_TYPE_CSS_CUSTOM_PROPERTY_POOL, NULL);
return instance;
}
int
gtk_css_custom_property_pool_add (GtkCssCustomPropertyPool *self,
const char *str)
{
GtkCssCustomPropertyName name;
int id;
id = gtk_css_custom_property_pool_lookup (self, str);
if (id > 0)
return gtk_css_custom_property_pool_ref (self, id);
name.ref_count = 1;
name.name = g_strdup (str);
// TODO reuse slots after they're gone
g_array_append_val (self->names, name);
id = self->names->len;
g_hash_table_insert (self->name_mappings, (char *) name.name, GINT_TO_POINTER (id));
return id;
}
int
gtk_css_custom_property_pool_lookup (GtkCssCustomPropertyPool *self,
const char *str)
{
gpointer id;
id = g_hash_table_lookup (self->name_mappings, str);
return GPOINTER_TO_INT (id);
}
int
gtk_css_custom_property_pool_ref (GtkCssCustomPropertyPool *self,
int id)
{
GtkCssCustomPropertyName *name;
name = &g_array_index (self->names, GtkCssCustomPropertyName, id - 1);
name->ref_count++;
return id;
}
void
gtk_css_custom_property_pool_unref (GtkCssCustomPropertyPool *self,
int id)
{
GtkCssCustomPropertyName *name;
name = &g_array_index (self->names, GtkCssCustomPropertyName, id - 1);
g_assert (name->ref_count > 0);
name->ref_count--;
if (name->ref_count == 0)
{
g_hash_table_remove (self->name_mappings, name->name);
clear_custom_property_name (name);
}
}
const char *
gtk_css_custom_property_pool_get_name (GtkCssCustomPropertyPool *self,
int id)
{
GtkCssCustomPropertyName *name;
name = &g_array_index (self->names, GtkCssCustomPropertyName, id - 1);
return name->name;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#pragma once
#include <glib-object.h>
G_BEGIN_DECLS
#define GTK_TYPE_CSS_CUSTOM_PROPERTY_POOL (gtk_css_custom_property_pool_get_type())
G_DECLARE_FINAL_TYPE (GtkCssCustomPropertyPool, gtk_css_custom_property_pool, GTK, CSS_CUSTOM_PROPERTY_POOL, GObject)
GtkCssCustomPropertyPool *gtk_css_custom_property_pool_get (void);
int gtk_css_custom_property_pool_add (GtkCssCustomPropertyPool *self,
const char *str);
int gtk_css_custom_property_pool_lookup (GtkCssCustomPropertyPool *self,
const char *str);
const char * gtk_css_custom_property_pool_get_name (GtkCssCustomPropertyPool *self,
int id);
int gtk_css_custom_property_pool_ref (GtkCssCustomPropertyPool *self,
int id);
void gtk_css_custom_property_pool_unref (GtkCssCustomPropertyPool *self,
int id);
G_END_DECLS

View File

@@ -50,11 +50,12 @@ gtk_css_value_ease_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_ease_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_ease_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (value);
}
@@ -142,6 +143,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_EASE = {
gtk_css_value_ease_transition,
NULL,
NULL,
NULL,
gtk_css_value_ease_print
};

View File

@@ -41,11 +41,12 @@ gtk_css_value_enum_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_enum_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_enum_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (value);
}
@@ -83,6 +84,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BORDER_STYLE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -141,6 +143,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BLEND_MODE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -229,11 +232,12 @@ gtk_css_font_size_get_default_px (GtkStyleProvider *provider,
}
static GtkCssValue *
gtk_css_value_font_size_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_font_size_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
double font_size;
@@ -292,6 +296,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_SIZE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -349,6 +354,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_STYLE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -396,11 +402,12 @@ _gtk_css_font_style_value_get (const GtkCssValue *value)
#define LIGHTER -2
static GtkCssValue *
gtk_css_value_font_weight_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_font_weight_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
PangoWeight new_weight;
int parent_value;
@@ -448,6 +455,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_WEIGHT = {
NULL,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -498,6 +506,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_STRETCH = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -555,6 +564,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_STYLE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -606,6 +616,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_AREA = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -663,6 +674,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_DIRECTION = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -724,6 +736,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_PLAY_STATE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -780,6 +793,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FILL_MODE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -838,6 +852,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_ICON_STYLE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -895,6 +910,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_KERNING = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -952,6 +968,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_POSITION = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -1009,6 +1026,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_CAPS = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -1070,6 +1088,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};
@@ -1178,6 +1197,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_TEXT_DECORATION_LINE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_text_decoration_line_value_print
};
@@ -1277,6 +1297,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_LIGATURE = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_font_variant_ligature_value_print
};
@@ -1385,6 +1406,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_NUMERIC = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_font_variant_numeric_value_print
};
@@ -1490,6 +1512,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_font_variant_east_asian_value_print
};
@@ -1579,6 +1602,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_TEXT_TRANSFORM = {
gtk_css_value_enum_transition,
NULL,
NULL,
NULL,
gtk_css_value_enum_print
};

View File

@@ -307,55 +307,56 @@ gtk_css_value_filter_free (GtkCssValue *value)
/* returns TRUE if dest == src */
static gboolean
gtk_css_filter_compute (GtkCssFilter *dest,
GtkCssFilter *src,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_filter_compute (GtkCssFilter *dest,
GtkCssFilter *src,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
dest->type = src->type;
switch (src->type)
{
case GTK_CSS_FILTER_BRIGHTNESS:
dest->brightness.value = _gtk_css_value_compute (src->brightness.value, property_id, provider, style, parent_style);
dest->brightness.value = _gtk_css_value_compute (src->brightness.value, property_id, provider, style, parent_style, variables);
return dest->brightness.value == src->brightness.value;
case GTK_CSS_FILTER_CONTRAST:
dest->contrast.value = _gtk_css_value_compute (src->contrast.value, property_id, provider, style, parent_style);
dest->contrast.value = _gtk_css_value_compute (src->contrast.value, property_id, provider, style, parent_style, variables);
return dest->contrast.value == src->contrast.value;
case GTK_CSS_FILTER_GRAYSCALE:
dest->grayscale.value = _gtk_css_value_compute (src->grayscale.value, property_id, provider, style, parent_style);
dest->grayscale.value = _gtk_css_value_compute (src->grayscale.value, property_id, provider, style, parent_style, variables);
return dest->grayscale.value == src->grayscale.value;
case GTK_CSS_FILTER_HUE_ROTATE:
dest->hue_rotate.value = _gtk_css_value_compute (src->hue_rotate.value, property_id, provider, style, parent_style);
dest->hue_rotate.value = _gtk_css_value_compute (src->hue_rotate.value, property_id, provider, style, parent_style, variables);
return dest->hue_rotate.value == src->hue_rotate.value;
case GTK_CSS_FILTER_INVERT:
dest->invert.value = _gtk_css_value_compute (src->invert.value, property_id, provider, style, parent_style);
dest->invert.value = _gtk_css_value_compute (src->invert.value, property_id, provider, style, parent_style, variables);
return dest->invert.value == src->invert.value;
case GTK_CSS_FILTER_OPACITY:
dest->opacity.value = _gtk_css_value_compute (src->opacity.value, property_id, provider, style, parent_style);
dest->opacity.value = _gtk_css_value_compute (src->opacity.value, property_id, provider, style, parent_style, variables);
return dest->opacity.value == src->opacity.value;
case GTK_CSS_FILTER_SATURATE:
dest->saturate.value = _gtk_css_value_compute (src->saturate.value, property_id, provider, style, parent_style);
dest->saturate.value = _gtk_css_value_compute (src->saturate.value, property_id, provider, style, parent_style, variables);
return dest->saturate.value == src->saturate.value;
case GTK_CSS_FILTER_SEPIA:
dest->sepia.value = _gtk_css_value_compute (src->sepia.value, property_id, provider, style, parent_style);
dest->sepia.value = _gtk_css_value_compute (src->sepia.value, property_id, provider, style, parent_style, variables);
return dest->sepia.value == src->sepia.value;
case GTK_CSS_FILTER_BLUR:
dest->blur.value = _gtk_css_value_compute (src->blur.value, property_id, provider, style, parent_style);
dest->blur.value = _gtk_css_value_compute (src->blur.value, property_id, provider, style, parent_style, variables);
return dest->blur.value == src->blur.value;
case GTK_CSS_FILTER_DROP_SHADOW:
dest->drop_shadow.value = _gtk_css_value_compute (src->drop_shadow.value, property_id, provider, style, parent_style);
dest->drop_shadow.value = _gtk_css_value_compute (src->drop_shadow.value, property_id, provider, style, parent_style, variables);
return dest->drop_shadow.value == src->drop_shadow.value;
case GTK_CSS_FILTER_NONE:
@@ -366,11 +367,12 @@ gtk_css_filter_compute (GtkCssFilter *dest,
}
static GtkCssValue *
gtk_css_value_filter_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_filter_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *result;
gboolean changes;
@@ -390,7 +392,8 @@ gtk_css_value_filter_compute (GtkCssValue *value,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
}
if (!changes)
@@ -720,6 +723,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FILTER = {
gtk_css_value_filter_transition,
NULL,
NULL,
NULL,
gtk_css_value_filter_print
};

View File

@@ -53,11 +53,12 @@ gtk_css_value_font_features_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_font_features_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_font_features_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (specified);
}
@@ -162,6 +163,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_FEATURES = {
gtk_css_value_font_features_transition,
NULL,
NULL,
NULL,
gtk_css_value_font_features_print
};

View File

@@ -52,11 +52,12 @@ gtk_css_value_font_variations_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_font_variations_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_font_variations_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (specified);
}
@@ -163,6 +164,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIATIONS = {
gtk_css_value_font_variations_transition,
NULL,
NULL,
NULL,
gtk_css_value_font_variations_print
};

View File

@@ -65,11 +65,12 @@ gtk_css_image_real_get_aspect_ratio (GtkCssImage *image)
}
static GtkCssImage *
gtk_css_image_real_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_real_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return g_object_ref (image);
}
@@ -173,11 +174,12 @@ _gtk_css_image_get_aspect_ratio (GtkCssImage *image)
}
GtkCssImage *
_gtk_css_image_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
_gtk_css_image_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageClass *klass;
@@ -187,7 +189,7 @@ _gtk_css_image_compute (GtkCssImage *image,
klass = GTK_CSS_IMAGE_GET_CLASS (image);
return klass->compute (image, property_id, provider, style, parent_style);
return klass->compute (image, property_id, provider, style, parent_style, variables);
}
GtkCssImage *

View File

@@ -313,11 +313,12 @@ gtk_css_image_conic_print (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_conic_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_conic_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
GtkCssImageConic *copy;
@@ -325,8 +326,8 @@ gtk_css_image_conic_compute (GtkCssImage *image,
copy = g_object_new (GTK_TYPE_CSS_IMAGE_CONIC, NULL);
copy->center = _gtk_css_value_compute (self->center, property_id, provider, style, parent_style);
copy->rotation = _gtk_css_value_compute (self->rotation, property_id, provider, style, parent_style);
copy->center = _gtk_css_value_compute (self->center, property_id, provider, style, parent_style, variables);
copy->rotation = _gtk_css_value_compute (self->rotation, property_id, provider, style, parent_style, variables);
copy->n_stops = self->n_stops;
copy->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * copy->n_stops);
@@ -335,11 +336,11 @@ gtk_css_image_conic_compute (GtkCssImage *image,
const GtkCssImageConicColorStop *stop = &self->color_stops[i];
GtkCssImageConicColorStop *scopy = &copy->color_stops[i];
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style);
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style, variables);
if (stop->offset)
{
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style);
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style, variables);
}
else
{

View File

@@ -399,11 +399,12 @@ gtk_css_image_cross_fade_print (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_cross_fade_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_cross_fade_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageCrossFade *self = GTK_CSS_IMAGE_CROSS_FADE (image);
GtkCssImageCrossFade *result;
@@ -418,7 +419,7 @@ gtk_css_image_cross_fade_compute (GtkCssImage *image,
gtk_css_image_cross_fade_add (result,
entry->has_progress,
entry->progress,
_gtk_css_image_compute (entry->image, property_id, provider, style, parent_style));
_gtk_css_image_compute (entry->image, property_id, provider, style, parent_style, variables));
}
return GTK_CSS_IMAGE (result);

View File

@@ -133,11 +133,12 @@ gtk_css_image_fallback_dispose (GObject *object)
static GtkCssImage *
gtk_css_image_fallback_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_fallback_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageFallback *fallback = GTK_CSS_IMAGE_FALLBACK (image);
GtkCssImageFallback *copy;
@@ -152,7 +153,8 @@ gtk_css_image_fallback_compute (GtkCssImage *image,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
/* image($color) that didn't change */
if (computed_color && !fallback->images &&
@@ -168,7 +170,8 @@ gtk_css_image_fallback_compute (GtkCssImage *image,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
if (gtk_css_image_is_invalid (copy->images[i]))
continue;

View File

@@ -138,11 +138,12 @@ gtk_css_image_icon_theme_print (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_icon_theme_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_icon_theme_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageIconTheme *icon_theme = GTK_CSS_IMAGE_ICON_THEME (image);
GtkCssImageIconTheme *copy;

View File

@@ -488,11 +488,12 @@ gtk_css_image_linear_print (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_linear_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_linear_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
GtkCssImageLinear *copy;
@@ -503,7 +504,7 @@ gtk_css_image_linear_compute (GtkCssImage *image,
copy->side = linear->side;
if (linear->angle)
copy->angle = _gtk_css_value_compute (linear->angle, property_id, provider, style, parent_style);
copy->angle = _gtk_css_value_compute (linear->angle, property_id, provider, style, parent_style, variables);
copy->n_stops = linear->n_stops;
copy->color_stops = g_malloc (sizeof (GtkCssImageLinearColorStop) * copy->n_stops);
@@ -512,11 +513,11 @@ gtk_css_image_linear_compute (GtkCssImage *image,
const GtkCssImageLinearColorStop *stop = &linear->color_stops[i];
GtkCssImageLinearColorStop *scopy = &copy->color_stops[i];
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style);
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style, variables);
if (stop->offset)
{
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style);
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style, variables);
}
else
{

View File

@@ -96,11 +96,12 @@ gtk_css_image_paintable_get_static_image (GtkCssImage *image)
}
static GtkCssImage *
gtk_css_image_paintable_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_paintable_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return gtk_css_image_paintable_get_static_image (image);
}

View File

@@ -26,6 +26,7 @@
#include "gtk/css/gtkcsstokenizerprivate.h"
#include "gtk/css/gtkcssparserprivate.h"
#include "gtk/gtkcsstypesprivate.h"
#include "gtk/gtkcssvariablesetprivate.h"
#include "gtk/gtksnapshot.h"
#include "gtk/gtkstyleprovider.h"
@@ -62,7 +63,8 @@ struct _GtkCssImageClass
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style);
GtkCssStyle *parent_style,
GtkCssVariableSet *variables);
/* compare two images for equality */
gboolean (* equal) (GtkCssImage *image1,
GtkCssImage *image2);
@@ -106,7 +108,8 @@ GtkCssImage * _gtk_css_image_compute (GtkCssImage *
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style);
GtkCssStyle *parent_style,
GtkCssVariableSet *variables);
gboolean _gtk_css_image_equal (GtkCssImage *image1,
GtkCssImage *image2) G_GNUC_PURE;
GtkCssImage * _gtk_css_image_transition (GtkCssImage *start,

View File

@@ -489,11 +489,12 @@ gtk_css_image_radial_print (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_radial_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_radial_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageRadial *radial = GTK_CSS_IMAGE_RADIAL (image);
GtkCssImageRadial *copy;
@@ -504,13 +505,13 @@ gtk_css_image_radial_compute (GtkCssImage *image,
copy->circle = radial->circle;
copy->size = radial->size;
copy->position = _gtk_css_value_compute (radial->position, property_id, provider, style, parent_style);
copy->position = _gtk_css_value_compute (radial->position, property_id, provider, style, parent_style, variables);
if (radial->sizes[0])
copy->sizes[0] = _gtk_css_value_compute (radial->sizes[0], property_id, provider, style, parent_style);
copy->sizes[0] = _gtk_css_value_compute (radial->sizes[0], property_id, provider, style, parent_style, variables);
if (radial->sizes[1])
copy->sizes[1] = _gtk_css_value_compute (radial->sizes[1], property_id, provider, style, parent_style);
copy->sizes[1] = _gtk_css_value_compute (radial->sizes[1], property_id, provider, style, parent_style, variables);
copy->n_stops = radial->n_stops;
copy->color_stops = g_malloc (sizeof (GtkCssImageRadialColorStop) * copy->n_stops);
@@ -519,11 +520,11 @@ gtk_css_image_radial_compute (GtkCssImage *image,
const GtkCssImageRadialColorStop *stop = &radial->color_stops[i];
GtkCssImageRadialColorStop *scopy = &copy->color_stops[i];
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style);
scopy->color = _gtk_css_value_compute (stop->color, property_id, provider, style, parent_style, variables);
if (stop->offset)
{
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style);
scopy->offset = _gtk_css_value_compute (stop->offset, property_id, provider, style, parent_style, variables);
}
else
{

View File

@@ -200,11 +200,12 @@ gtk_css_image_recolor_snapshot (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_recolor_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_recolor_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageRecolor *recolor = GTK_CSS_IMAGE_RECOLOR (image);
GtkCssValue *palette;
@@ -215,7 +216,7 @@ gtk_css_image_recolor_compute (GtkCssImage *image,
scale = gtk_style_provider_get_scale (provider);
if (recolor->palette)
palette = _gtk_css_value_compute (recolor->palette, property_id, provider, style, parent_style);
palette = _gtk_css_value_compute (recolor->palette, property_id, provider, style, parent_style, variables);
else
palette = _gtk_css_value_ref (style->core->icon_palette);

View File

@@ -97,11 +97,12 @@ gtk_css_image_scaled_dispose (GObject *object)
static GtkCssImage *
gtk_css_image_scaled_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_scaled_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageScaled *scaled = GTK_CSS_IMAGE_SCALED (image);
int scale;
@@ -137,7 +138,8 @@ gtk_css_image_scaled_compute (GtkCssImage *image,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
res->scales[0] = scaled->scales[best];
return GTK_CSS_IMAGE (res);

View File

@@ -112,11 +112,12 @@ gtk_css_image_url_snapshot (GtkCssImage *image,
}
static GtkCssImage *
gtk_css_image_url_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_image_url_compute (GtkCssImage *image,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImageUrl *url = GTK_CSS_IMAGE_URL (image);
GtkCssImage *copy;

View File

@@ -34,11 +34,12 @@ gtk_css_value_image_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_image_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_image_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssImage *image, *computed;
@@ -47,7 +48,7 @@ gtk_css_value_image_compute (GtkCssValue *value,
if (image == NULL)
return _gtk_css_value_ref (value);
computed = _gtk_css_image_compute (image, property_id, provider, style, parent_style);
computed = _gtk_css_image_compute (image, property_id, provider, style, parent_style, variables);
if (computed == image)
{
@@ -130,6 +131,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_IMAGE = {
gtk_css_value_image_transition,
gtk_css_value_image_is_dynamic,
gtk_css_value_image_get_dynamic_value,
NULL,
gtk_css_value_image_print
};

View File

@@ -34,11 +34,12 @@ gtk_css_value_inherit_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_inherit_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_inherit_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
if (parent_style)
{
@@ -50,7 +51,8 @@ gtk_css_value_inherit_compute (GtkCssValue *value,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
}
}
@@ -85,6 +87,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_INHERIT = {
gtk_css_value_inherit_transition,
NULL,
NULL,
NULL,
gtk_css_value_inherit_print
};

View File

@@ -38,11 +38,12 @@ gtk_css_value_initial_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_initial_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_initial_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkSettings *settings;
@@ -75,7 +76,8 @@ gtk_css_value_initial_compute (GtkCssValue *value,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
}
static gboolean
@@ -109,6 +111,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_INITIAL = {
gtk_css_value_initial_transition,
NULL,
NULL,
NULL,
gtk_css_value_initial_print
};
@@ -135,5 +138,6 @@ _gtk_css_initial_value_new_compute (guint property_id,
property_id,
provider,
style,
parent_style);
parent_style,
NULL);
}

View File

@@ -21,6 +21,8 @@
#include "gtkcssstyleprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
#include "gtkcssreferencevalueprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkstylepropertyprivate.h"
@@ -31,12 +33,15 @@
#include <string.h>
struct _GtkCssKeyframes {
int ref_count; /* ref count */
int n_keyframes; /* number of keyframes (at least 2 for 0% and 100% */
double *keyframe_progress; /* ordered array of n_keyframes of [0..1] */
int n_properties; /* number of properties used by keyframes */
guint *property_ids; /* ordered array of n_properties property ids */
GtkCssValue **values; /* 2D array: n_keyframes * n_properties of (value or NULL) for all the keyframes */
int ref_count; /* ref count */
int n_keyframes; /* number of keyframes (at least 2 for 0% and 100% */
double *keyframe_progress; /* ordered array of n_keyframes of [0..1] */
int n_properties; /* number of properties used by keyframes */
guint *property_ids; /* ordered array of n_properties property ids */
GtkCssValue **values; /* 2D array: n_keyframes * n_properties of (value or NULL) for all the keyframes */
GtkCssVariableSet **variables; /* array of variable sets for each keyframe */
int *variable_ids; /* ordered array of variable ids */
int n_variables; /* number of variable used by keyframes */
};
#define KEYFRAMES_VALUE(keyframes, k, p) ((keyframes)->values[(k) * (keyframes)->n_properties + (p)])
@@ -72,8 +77,13 @@ _gtk_css_keyframes_unref (GtkCssKeyframes *keyframes)
_gtk_css_value_unref (KEYFRAMES_VALUE (keyframes, k, p));
KEYFRAMES_VALUE (keyframes, k, p) = NULL;
}
if (keyframes->variables && keyframes->variables[k])
gtk_css_variable_set_unref (keyframes->variables[k]);
}
g_free (keyframes->values);
g_free (keyframes->variables);
g_free (keyframes->variable_ids);
g_free (keyframes);
}
@@ -120,6 +130,9 @@ gtk_css_keyframes_add_keyframe (GtkCssKeyframes *keyframes,
memset (&KEYFRAMES_VALUE (keyframes, k, 0), 0, size);
}
if (keyframes->variables)
keyframes->variables = g_realloc (keyframes->variables, sizeof (GtkCssVariableSet *) * keyframes->n_keyframes);
return k;
}
@@ -173,6 +186,26 @@ gtk_css_keyframes_lookup_property (GtkCssKeyframes *keyframes,
return p;
}
static void
gtk_css_keyframes_register_variable (GtkCssKeyframes *keyframes,
int variable_id)
{
guint p;
for (p = 0; p < keyframes->n_variables; p++)
{
if (keyframes->variable_ids[p] == variable_id)
return;
else if (keyframes->variable_ids[p] > variable_id)
break;
}
keyframes->n_variables++;
keyframes->variable_ids = g_realloc (keyframes->variable_ids, sizeof (int) * keyframes->n_variables);
memmove (keyframes->variable_ids + p + 1, keyframes->variable_ids + p, sizeof (int) * (keyframes->n_variables - p - 1));
keyframes->variable_ids[p] = variable_id;
}
static GtkCssKeyframes *
gtk_css_keyframes_alloc (void)
{
@@ -235,6 +268,44 @@ gtk_css_keyframes_parse_declaration (GtkCssKeyframes *keyframes,
return FALSE;
}
/* This is a custom property */
if (name[0] == '-' && name[1] == '-')
{
GtkCssVariableValue *var_value;
GtkCssCustomPropertyPool *pool;
int id;
if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COLON))
{
gtk_css_parser_error_syntax (parser, "Expected a ':'");
g_free (name);
return FALSE;
}
var_value = gtk_css_parser_parse_value_into_token_stream (parser);
if (var_value == NULL)
{
g_free (name);
return FALSE;
}
if (!keyframes->variables)
keyframes->variables = g_new0 (GtkCssVariableSet *, keyframes->n_keyframes);
if (!keyframes->variables[k])
keyframes->variables[k] = gtk_css_variable_set_new ();
pool = gtk_css_custom_property_pool_get ();
id = gtk_css_custom_property_pool_add (pool, name);
gtk_css_keyframes_register_variable (keyframes, id);
gtk_css_variable_set_add (keyframes->variables[k], id, var_value);
gtk_css_custom_property_pool_unref (pool, id);
return TRUE;
}
property = _gtk_style_property_lookup (name);
if (property == NULL)
{
@@ -251,9 +322,53 @@ gtk_css_keyframes_parse_declaration (GtkCssKeyframes *keyframes,
return FALSE;
}
value = _gtk_style_property_parse_value (property, parser);
if (value == NULL)
return FALSE;
if (gtk_css_parser_has_references (parser))
{
GtkCssVariableValue *var_value;
var_value = gtk_css_parser_parse_value_into_token_stream (parser);
if (var_value == NULL)
return FALSE;
if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
guint i, n;
GtkCssValue **values;
n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
values = g_new (GtkCssValue *, n);
for (i = 0; i < n; i++)
{
GtkCssValue *child =
_gtk_css_reference_value_new (property,
var_value,
gtk_css_parser_get_file (parser));
_gtk_css_reference_value_set_subproperty (child, i);
values[i] = _gtk_css_array_value_get_nth (child, i);
}
value = _gtk_css_array_value_new_from_array (values, n);
g_free (values);
}
else
{
value = _gtk_css_reference_value_new (property,
var_value,
gtk_css_parser_get_file (parser));
}
gtk_css_variable_value_unref (var_value);
}
else
{
value = _gtk_style_property_parse_value (property, parser);
if (value == NULL)
return FALSE;
}
if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
{
@@ -314,6 +429,9 @@ gtk_css_keyframes_parse_block (GtkCssKeyframes *keyframes,
gtk_css_parser_end_block (parser);
}
if (keyframes->variables && keyframes->variables[k])
gtk_css_variable_set_resolve_cycles (keyframes->variables[k]);
gtk_css_parser_end_block (parser);
return TRUE;
@@ -461,10 +579,27 @@ _gtk_css_keyframes_compute (GtkCssKeyframes *keyframes,
resolved->property_ids[p],
provider,
style,
parent_style);
parent_style,
keyframes->variables ? keyframes->variables[k] : NULL);
}
}
if (keyframes->variables)
{
resolved->variables = g_new0 (GtkCssVariableSet *, resolved->n_keyframes);
for (k = 0; k < resolved->n_keyframes; k++)
{
if (keyframes->variables[k])
resolved->variables[k] = gtk_css_variable_set_ref (keyframes->variables[k]);
}
}
else
resolved->variables = NULL;
resolved->variable_ids = g_memdup2 (keyframes->variable_ids, keyframes->n_variables * sizeof (int));
resolved->n_variables = keyframes->n_variables;
return resolved;
}
@@ -540,3 +675,78 @@ _gtk_css_keyframes_get_value (GtkCssKeyframes *keyframes,
return result;
}
guint
_gtk_css_keyframes_get_n_variables (GtkCssKeyframes *keyframes)
{
g_return_val_if_fail (keyframes != NULL, 0);
return keyframes->n_variables;
}
int
_gtk_css_keyframes_get_variable_id (GtkCssKeyframes *keyframes,
guint id)
{
g_return_val_if_fail (keyframes != NULL, 0);
g_return_val_if_fail (id < keyframes->n_variables, 0);
return keyframes->variable_ids[id];
}
GtkCssVariableValue *
_gtk_css_keyframes_get_variable (GtkCssKeyframes *keyframes,
guint id,
double progress,
GtkCssVariableValue *default_value)
{
GtkCssVariableValue *start_value, *end_value, *result;
double start_progress, end_progress;
int variable_id;
guint k;
g_return_val_if_fail (keyframes != NULL, 0);
g_return_val_if_fail (id < keyframes->n_variables, 0);
start_value = default_value;
start_progress = 0.0;
end_value = default_value;
end_progress = 1.0;
variable_id = keyframes->variable_ids[id];
for (k = 0; k < keyframes->n_keyframes; k++)
{
GtkCssVariableValue *value = gtk_css_variable_set_lookup (keyframes->variables[k], variable_id, NULL);
if (value == NULL)
continue;
if (keyframes->keyframe_progress[k] == progress)
{
return gtk_css_variable_value_ref (value);
}
else if (keyframes->keyframe_progress[k] < progress)
{
start_value = value;
start_progress = keyframes->keyframe_progress[k];
}
else
{
end_value = value;
end_progress = keyframes->keyframe_progress[k];
break;
}
}
progress = (progress - start_progress) / (end_progress - start_progress);
result = gtk_css_variable_value_transition (start_value,
end_value,
progress);
/* XXX: Dear spec, what's the correct thing to do here? */
if (result == NULL)
return start_value ? gtk_css_variable_value_ref (start_value) : NULL;
return result;
}

View File

@@ -50,5 +50,13 @@ GtkCssValue * _gtk_css_keyframes_get_value (GtkCssKeyframes
double progress,
GtkCssValue *default_value);
guint _gtk_css_keyframes_get_n_variables (GtkCssKeyframes *keyframes);
int _gtk_css_keyframes_get_variable_id (GtkCssKeyframes *keyframes,
guint id);
GtkCssVariableValue *_gtk_css_keyframes_get_variable (GtkCssKeyframes *keyframes,
guint id,
double progress,
GtkCssVariableValue *default_value);
G_END_DECLS

View File

@@ -39,15 +39,16 @@ gtk_css_value_line_height_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_line_height_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_line_height_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *height;
height = _gtk_css_value_compute (value->height, property_id, provider, style, parent_style);
height = _gtk_css_value_compute (value->height, property_id, provider, style, parent_style, variables);
if (gtk_css_number_value_get_dimension (height) == GTK_CSS_DIMENSION_PERCENTAGE)
{
@@ -113,6 +114,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_LINE_HEIGHT = {
gtk_css_value_line_height_transition,
NULL,
NULL,
NULL,
gtk_css_value_line_height_print
};

View File

@@ -19,6 +19,7 @@
#include "gtkcsslookupprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h"
@@ -36,6 +37,9 @@ void
_gtk_css_lookup_destroy (GtkCssLookup *lookup)
{
_gtk_bitmask_free (lookup->set_values);
if (lookup->custom_values)
g_hash_table_unref (lookup->custom_values);
}
gboolean
@@ -74,3 +78,17 @@ _gtk_css_lookup_set (GtkCssLookup *lookup,
lookup->values[id].section = section;
lookup->set_values = _gtk_bitmask_set (lookup->set_values, id, TRUE);
}
void
_gtk_css_lookup_set_custom (GtkCssLookup *lookup,
int id,
GtkCssVariableValue *value)
{
gtk_internal_return_if_fail (lookup != NULL);
if (!lookup->custom_values)
lookup->custom_values = g_hash_table_new (g_direct_hash, g_direct_equal);
if (!g_hash_table_contains (lookup->custom_values, GINT_TO_POINTER (id)))
g_hash_table_replace (lookup->custom_values, GINT_TO_POINTER (id), value);
}

View File

@@ -23,6 +23,8 @@
#include "gtk/gtkcssstaticstyleprivate.h"
#include "gtk/css/gtkcsssection.h"
#include "gtk/css/gtkcsstokenizerprivate.h"
#include "gtk/css/gtkcssvariablevalueprivate.h"
G_BEGIN_DECLS
@@ -37,6 +39,7 @@ typedef struct {
struct _GtkCssLookup {
GtkBitmask *set_values;
GtkCssLookupValue values[GTK_CSS_PROPERTY_N_PROPERTIES];
GHashTable *custom_values;
};
void _gtk_css_lookup_init (GtkCssLookup *lookup);
@@ -47,6 +50,9 @@ void _gtk_css_lookup_set (GtkCssLookup
guint id,
GtkCssSection *section,
GtkCssValue *value);
void _gtk_css_lookup_set_custom (GtkCssLookup *lookup,
int id,
GtkCssVariableValue *value);
static inline const GtkBitmask *
_gtk_css_lookup_get_set_values (const GtkCssLookup *lookup)

View File

@@ -445,9 +445,12 @@ gtk_css_node_real_update_style (GtkCssNode *cssnode,
}
else if (static_style != style && (change & GTK_CSS_CHANGE_TIMESTAMP))
{
GtkCssNode *parent = gtk_css_node_get_parent (cssnode);
new_style = gtk_css_animated_style_new_advance (GTK_CSS_ANIMATED_STYLE (style),
static_style,
timestamp);
parent ? gtk_css_node_get_style (parent) : NULL,
timestamp,
gtk_css_node_get_style_provider (cssnode));
}
else
{

View File

@@ -108,11 +108,12 @@ get_base_font_size_px (guint property_id,
}
static GtkCssValue *
gtk_css_value_number_compute (GtkCssValue *number,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_number_compute (GtkCssValue *number,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
double value;
@@ -130,7 +131,8 @@ gtk_css_value_number_compute (GtkCssValue *number,
{
GtkCssValue *computed = _gtk_css_value_compute (number->calc.terms[i],
property_id, provider, style,
parent_style);
parent_style,
variables);
changed |= computed != number->calc.terms[i];
new_values[i] = computed;
}
@@ -337,6 +339,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_NUMBER = {
gtk_css_value_number_transition,
NULL,
NULL,
NULL,
gtk_css_value_number_print
};

View File

@@ -103,11 +103,12 @@ gtk_css_value_palette_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_palette_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_palette_compute (GtkCssValue *specified,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *computed_color;
GtkCssValue *result;
@@ -120,7 +121,7 @@ gtk_css_value_palette_compute (GtkCssValue *specified,
{
GtkCssValue *value = specified->color_values[i];
computed_color = _gtk_css_value_compute (value, property_id, provider, style, parent_style);
computed_color = _gtk_css_value_compute (value, property_id, provider, style, parent_style, variables);
result->color_names[i] = g_strdup (specified->color_names[i]);
result->color_values[i] = computed_color;
@@ -249,6 +250,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_PALETTE = {
gtk_css_value_palette_transition,
NULL,
NULL,
NULL,
gtk_css_value_palette_print
};

View File

@@ -36,16 +36,17 @@ gtk_css_value_position_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_position_compute (GtkCssValue *position,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_position_compute (GtkCssValue *position,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *x, *y;
x = _gtk_css_value_compute (position->x, property_id, provider, style, parent_style);
y = _gtk_css_value_compute (position->y, property_id, provider, style, parent_style);
x = _gtk_css_value_compute (position->x, property_id, provider, style, parent_style, variables);
y = _gtk_css_value_compute (position->y, property_id, provider, style, parent_style, variables);
if (x == position->x && y == position->y)
{
_gtk_css_value_unref (x);
@@ -156,6 +157,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_POSITION = {
gtk_css_value_position_transition,
NULL,
NULL,
NULL,
gtk_css_value_position_print
};

View File

@@ -22,10 +22,13 @@
#include <gtk/css/gtkcss.h>
#include "gtk/css/gtkcsstokenizerprivate.h"
#include "gtk/css/gtkcssparserprivate.h"
#include "gtk/css/gtkcssvariablevalueprivate.h"
#include "gtkbitmaskprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
#include "gtkcsskeyframesprivate.h"
#include "gtkcssreferencevalueprivate.h"
#include "gtkcssselectorprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
#include "gtksettingsprivate.h"
@@ -113,6 +116,7 @@ struct GtkCssRuleset
PropertyValue *styles;
guint n_styles;
guint owns_styles : 1;
GHashTable *custom_properties;
};
struct _GtkCssScanner
@@ -270,6 +274,8 @@ gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
gtk_css_section_unref (ruleset->styles[i].section);
}
g_free (ruleset->styles);
if (ruleset->custom_properties)
g_hash_table_unref (ruleset->custom_properties);
}
if (ruleset->selector)
_gtk_css_selector_free (ruleset->selector);
@@ -285,7 +291,7 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
{
guint i;
g_return_if_fail (ruleset->owns_styles || ruleset->n_styles == 0);
g_return_if_fail (ruleset->owns_styles || (ruleset->n_styles == 0 && ruleset->custom_properties == NULL));
ruleset->owns_styles = TRUE;
@@ -315,6 +321,39 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
ruleset->styles[i].section = NULL;
}
static void
unref_custom_property_name (gpointer pointer)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
gtk_css_custom_property_pool_unref (pool, GPOINTER_TO_INT (pointer));
}
static void
gtk_css_ruleset_add_custom (GtkCssRuleset *ruleset,
const char *name,
GtkCssVariableValue *value)
{
GtkCssCustomPropertyPool *pool;
int id;
g_return_if_fail (ruleset->owns_styles || (ruleset->n_styles == 0 && ruleset->custom_properties == NULL));
ruleset->owns_styles = TRUE;
if (ruleset->custom_properties == NULL)
{
ruleset->custom_properties = g_hash_table_new_full (g_direct_hash, g_direct_equal,
unref_custom_property_name,
(GDestroyNotify) gtk_css_variable_value_unref);
}
pool = gtk_css_custom_property_pool_get ();
id = gtk_css_custom_property_pool_add (pool, name);
g_hash_table_replace (ruleset->custom_properties, GINT_TO_POINTER (id), value);
}
static void
gtk_css_scanner_destroy (GtkCssScanner *scanner)
{
@@ -490,7 +529,7 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
{
ruleset = gtk_css_selector_matches_get (&tree_rules, i);
if (ruleset->styles == NULL)
if (ruleset->styles == NULL && ruleset->custom_properties == NULL)
continue;
for (j = 0; j < ruleset->n_styles; j++)
@@ -506,6 +545,18 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
ruleset->styles[j].section,
ruleset->styles[j].value);
}
if (ruleset->custom_properties)
{
GHashTableIter iter;
gpointer id;
GtkCssVariableValue *value;
g_hash_table_iter_init (&iter, ruleset->custom_properties);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value))
_gtk_css_lookup_set_custom (lookup, GPOINTER_TO_INT (id), value);
}
}
}
gtk_css_selector_matches_clear (&tree_rules);
@@ -572,7 +623,7 @@ css_provider_commit (GtkCssProvider *css_provider,
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (css_provider);
guint i;
if (ruleset->styles == NULL)
if (ruleset->styles == NULL && ruleset->custom_properties == NULL)
{
for (i = 0; i < gtk_css_selectors_get_size (selectors); i++)
_gtk_css_selector_free (gtk_css_selectors_get (selectors, i));
@@ -814,6 +865,42 @@ parse_declaration (GtkCssScanner *scanner,
if (name == NULL)
goto out;
/* This is a custom property */
if (name[0] == '-' && name[1] == '-')
{
GtkCssVariableValue *value;
GtkCssSection *section;
if (!gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COLON))
{
gtk_css_parser_error_syntax (scanner->parser, "Expected ':'");
goto out;
}
value = gtk_css_parser_parse_value_into_token_stream (scanner->parser);
if (value == NULL)
goto out;
if (gtk_keep_css_sections)
{
section = gtk_css_section_new (gtk_css_parser_get_file (scanner->parser),
gtk_css_parser_get_block_location (scanner->parser),
gtk_css_parser_get_end_location (scanner->parser));
}
else
section = NULL;
if (section != NULL)
{
gtk_css_variable_value_set_section (value, section);
gtk_css_section_unref (section);
}
gtk_css_ruleset_add_custom (ruleset, name, value);
goto out;
}
property = _gtk_style_property_lookup (name);
if (property)
@@ -827,15 +914,60 @@ parse_declaration (GtkCssScanner *scanner,
goto out;
}
value = _gtk_style_property_parse_value (property, scanner->parser);
if (value == NULL)
goto out;
if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
if (gtk_css_parser_has_references (scanner->parser))
{
gtk_css_parser_error_syntax (scanner->parser, "Junk at end of value for %s", property->name);
goto out;
GtkCssVariableValue *var_value;
var_value = gtk_css_parser_parse_value_into_token_stream (scanner->parser);
if (var_value == NULL)
goto out;
if (GTK_IS_CSS_SHORTHAND_PROPERTY (property))
{
GtkCssShorthandProperty *shorthand = GTK_CSS_SHORTHAND_PROPERTY (property);
guint i, n;
GtkCssValue **values;
n = _gtk_css_shorthand_property_get_n_subproperties (shorthand);
values = g_new (GtkCssValue *, n);
for (i = 0; i < n; i++)
{
GtkCssValue *child =
_gtk_css_reference_value_new (property,
var_value,
gtk_css_parser_get_file (scanner->parser));
_gtk_css_reference_value_set_subproperty (child, i);
values[i] = _gtk_css_array_value_get_nth (child, i);
}
value = _gtk_css_array_value_new_from_array (values, n);
g_free (values);
}
else
{
value = _gtk_css_reference_value_new (property,
var_value,
gtk_css_parser_get_file (scanner->parser));
}
gtk_css_variable_value_unref (var_value);
}
else
{
value = _gtk_style_property_parse_value (property, scanner->parser);
if (value == NULL)
goto out;
if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
gtk_css_parser_error_syntax (scanner->parser, "Junk at end of value for %s", property->name);
gtk_css_value_unref (value);
goto out;
}
}
if (gtk_keep_css_sections)
@@ -1112,7 +1244,7 @@ gtk_css_provider_load_from_data (GtkCssProvider *css_provider,
if (length < 0)
length = strlen (data);
bytes = g_bytes_new_static (data, length);
bytes = g_bytes_new (data, length);
gtk_css_provider_load_from_bytes (css_provider, bytes);
@@ -1139,7 +1271,7 @@ gtk_css_provider_load_from_string (GtkCssProvider *css_provider,
g_return_if_fail (GTK_IS_CSS_PROVIDER (css_provider));
g_return_if_fail (string != NULL);
bytes = g_bytes_new_static (string, strlen (string));
bytes = g_bytes_new (string, strlen (string));
gtk_css_provider_load_from_bytes (css_provider, bytes);
@@ -1473,6 +1605,20 @@ compare_properties (gconstpointer a, gconstpointer b, gpointer style)
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (styles[*ub].property)));
}
static int
compare_custom_properties (gconstpointer a, gconstpointer b, gpointer user_data)
{
GtkCssCustomPropertyPool *pool = user_data;
int id1 = GPOINTER_TO_INT (*((gconstpointer *) a));
int id2 = GPOINTER_TO_INT (*((gconstpointer *) b));
const char *name1, *name2;
name1 = gtk_css_custom_property_pool_get_name (pool, id1);
name2 = gtk_css_custom_property_pool_get_name (pool, id2);
return strcmp (name1, name2);
}
static void
gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
GString *str)
@@ -1503,6 +1649,31 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
g_string_append (str, ";\n");
}
if (ruleset->custom_properties)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
GPtrArray *keys;
keys = g_hash_table_get_keys_as_ptr_array (ruleset->custom_properties);
g_ptr_array_sort_with_data (keys, compare_custom_properties, pool);
for (i = 0; i < keys->len; i++)
{
int id = GPOINTER_TO_INT (g_ptr_array_index (keys, i));
const char *name = gtk_css_custom_property_pool_get_name (pool, id);
GtkCssVariableValue *value = g_hash_table_lookup (ruleset->custom_properties,
GINT_TO_POINTER (id));
g_string_append (str, " ");
g_string_append (str, name);
g_string_append (str, ": ");
gtk_css_variable_value_print (value, str);
g_string_append (str, ";\n");
}
g_ptr_array_unref (keys);
}
g_free (sorted);
}

275
gtk/gtkcssreferencevalue.c Normal file
View File

@@ -0,0 +1,275 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#include "config.h"
#include "gtkcssreferencevalueprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
#include "gtkcssshorthandpropertyprivate.h"
#include "gtkcssstyleprivate.h"
#include "gtkcssunsetvalueprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkstyleproviderprivate.h"
#define MAX_TOKEN_LENGTH 65536
struct _GtkCssValue {
GTK_CSS_VALUE_BASE
GtkStyleProperty *property;
GtkCssVariableValue *value;
GFile *file;
guint subproperty;
};
static void
gtk_css_value_reference_free (GtkCssValue *value)
{
gtk_css_variable_value_unref (value->value);
if (value->file)
g_object_unref (value->file);
}
static gboolean
resolve_references_do (GtkCssVariableValue *value,
GtkCssVariableSet *style_variables,
GtkCssVariableSet *keyframes_variables,
gboolean root,
GPtrArray *refs,
gsize *out_length,
gsize *out_n_refs)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
gsize i;
gsize length = value->length;
gsize n_refs = 0;
if (value->is_invalid)
goto error;
if (!root)
{
n_refs += 1;
g_ptr_array_add (refs, value);
}
for (i = 0; i < value->n_references; i++)
{
GtkCssVariableValueReference *ref = &value->references[i];
int id = gtk_css_custom_property_pool_lookup (pool, ref->name);
GtkCssVariableValue *var_value = NULL;
gsize var_length, var_refs;
GtkCssVariableSet *source = style_variables;
if (keyframes_variables)
var_value = gtk_css_variable_set_lookup (keyframes_variables, id, NULL);
if (!var_value && style_variables)
var_value = gtk_css_variable_set_lookup (style_variables, id, &source);
if (!var_value || !resolve_references_do (var_value, source, keyframes_variables,
FALSE, refs, &var_length, &var_refs))
{
var_value = ref->fallback;
if (!var_value || !resolve_references_do (var_value, style_variables, keyframes_variables,
FALSE, refs, &var_length, &var_refs))
goto error;
}
length += var_length - ref->length;
n_refs += var_refs;
if (length > MAX_TOKEN_LENGTH)
goto error;
}
if (out_length)
*out_length = length;
if (out_n_refs)
*out_n_refs = n_refs;
return TRUE;
error:
/* Remove the references we added as if nothing happened */
g_ptr_array_remove_range (refs, refs->len - n_refs, n_refs);
if (out_length)
*out_length = 0;
if (out_n_refs)
*out_n_refs = 0;
return FALSE;
}
static GtkCssVariableValue **
resolve_references (GtkCssVariableValue *input,
GtkCssStyle *style,
GtkCssVariableSet *keyframes_variables,
gsize *n_refs)
{
GPtrArray *refs = g_ptr_array_new ();
if (!resolve_references_do (input, style->variables, keyframes_variables, TRUE, refs, NULL, NULL))
return NULL;
return (GtkCssVariableValue **) g_ptr_array_steal (refs, n_refs);
}
static void
parser_error (GtkCssParser *parser,
const GtkCssLocation *start,
const GtkCssLocation *end,
const GError *error,
gpointer user_data)
{
GtkStyleProvider *provider = user_data;
GtkCssSection *section;
section = gtk_css_section_new (gtk_css_parser_get_file (parser),
start,
end);
gtk_style_provider_emit_error (provider, section, (GError *) error);
gtk_css_section_unref (section);
}
static GtkCssValue *
gtk_css_value_reference_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *result = NULL, *computed;
GtkCssVariableValue **refs;
gsize n_refs = 0;
refs = resolve_references (value->value, style, variables, &n_refs);
if (refs != NULL)
{
GtkCssParser *value_parser =
gtk_css_parser_new_for_token_stream (value->value,
value->file,
refs,
n_refs,
parser_error, provider, NULL);
result = _gtk_style_property_parse_value (value->property, value_parser);
gtk_css_parser_unref (value_parser);
}
if (result == NULL)
result = _gtk_css_unset_value_new ();
if (GTK_IS_CSS_SHORTHAND_PROPERTY (value->property))
{
GtkCssValue *sub = gtk_css_value_ref (_gtk_css_array_value_get_nth (result, value->subproperty));
gtk_css_value_unref (result);
result = sub;
}
computed = _gtk_css_value_compute (result,
property_id,
provider,
style,
parent_style,
variables);
gtk_css_value_unref (result);
return computed;
}
static gboolean
gtk_css_value_reference_equal (const GtkCssValue *value1,
const GtkCssValue *value2)
{
return FALSE;
}
static GtkCssValue *
gtk_css_value_reference_transition (GtkCssValue *start,
GtkCssValue *end,
guint property_id,
double progress)
{
return NULL;
}
static gboolean
gtk_css_value_reference_contains_variables (const GtkCssValue *value)
{
return TRUE;
}
static void
gtk_css_value_reference_print (const GtkCssValue *value,
GString *string)
{
gtk_css_variable_value_print (value->value, string);
}
static const GtkCssValueClass GTK_CSS_VALUE_REFERENCE = {
"GtkCssReferenceValue",
gtk_css_value_reference_free,
gtk_css_value_reference_compute,
gtk_css_value_reference_equal,
gtk_css_value_reference_transition,
NULL,
NULL,
gtk_css_value_reference_contains_variables,
gtk_css_value_reference_print
};
GtkCssValue *
_gtk_css_reference_value_new (GtkStyleProperty *property,
GtkCssVariableValue *value,
GFile *file)
{
GtkCssValue *result;
result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_REFERENCE);
result->property = property;
result->value = gtk_css_variable_value_ref (value);
if (file)
result->file = g_object_ref (file);
else
result->file = NULL;
return result;
}
void
_gtk_css_reference_value_set_subproperty (GtkCssValue *value,
guint property)
{
g_assert (GTK_IS_CSS_SHORTHAND_PROPERTY (value->property));
value->subproperty = property;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#pragma once
#include <gtk/css/gtkcss.h>
#include "gtkcssvalueprivate.h"
#include "gtkstylepropertyprivate.h"
#include "css/gtkcssvariablevalueprivate.h"
G_BEGIN_DECLS
GtkCssValue *_gtk_css_reference_value_new (GtkStyleProperty *property,
GtkCssVariableValue *value,
GFile *file);
void _gtk_css_reference_value_set_subproperty (GtkCssValue *value,
guint property);
G_END_DECLS

View File

@@ -34,11 +34,12 @@ gtk_css_value_repeat_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_repeat_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_repeat_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (value);
}
@@ -120,6 +121,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BACKGROUND_REPEAT = {
gtk_css_value_repeat_transition,
NULL,
NULL,
NULL,
gtk_css_value_background_repeat_print
};
@@ -131,6 +133,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_BORDER_REPEAT = {
gtk_css_value_repeat_transition,
NULL,
NULL,
NULL,
gtk_css_value_border_repeat_print
};
/* BACKGROUND REPEAT */

View File

@@ -892,6 +892,48 @@ DEFINE_SIMPLE_SELECTOR(pseudoclass_position, PSEUDOCLASS_POSITION, print_pseudoc
match_pseudoclass_position, hash_pseudoclass_position, comp_pseudoclass_position,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_POSITION
/* PSEUDOCLASS FOR ROOT */
static void
print_pseudoclass_root (const GtkCssSelector *selector,
GString *string)
{
g_string_append (string, ":root");
}
static gboolean
match_pseudoclass_root (const GtkCssSelector *selector,
GtkCssNode *node)
{
return gtk_css_node_get_parent (node) == NULL;
}
static guint
hash_pseudoclass_root (const GtkCssSelector *selector)
{
return GPOINTER_TO_UINT (selector->class);
}
static int
comp_pseudoclass_root (const GtkCssSelector *a,
const GtkCssSelector *b)
{
return 0;
}
static GtkCssChange
change_pseudoclass_root (const GtkCssSelector *selector)
{
return 0;
}
#define GTK_CSS_CHANGE_PSEUDOCLASS_ROOT change_pseudoclass_root(selector)
DEFINE_SIMPLE_SELECTOR(pseudoclass_root, PSEUDOCLASS_ROOT, print_pseudoclass_root,
match_pseudoclass_root, hash_pseudoclass_root, comp_pseudoclass_root,
FALSE, TRUE, FALSE, TRUE)
#undef GTK_CSS_CHANGE_PSEUDOCLASS_ROOT
/* API */
static guint
@@ -1267,6 +1309,7 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser,
PositionType position_type;
int position_a;
int position_b;
gboolean is_root;
} pseudo_classes[] = {
{ "first-child", 0, POSITION_FORWARD, 0, 1 },
{ "last-child", 0, POSITION_BACKWARD, 0, 1 },
@@ -1283,6 +1326,7 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser,
{ "checked", GTK_STATE_FLAG_CHECKED, },
{ "focus-visible", GTK_STATE_FLAG_FOCUS_VISIBLE, },
{ "focus-within", GTK_STATE_FLAG_FOCUS_WITHIN, },
{ "root", 0, 0, 0, 0, TRUE },
};
guint i;
@@ -1297,6 +1341,12 @@ gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser,
selector);
selector->state.state = pseudo_classes[i].state_flag;
}
else if (pseudo_classes[i].is_root)
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_ROOT
: &GTK_CSS_SELECTOR_PSEUDOCLASS_ROOT,
selector);
}
else
{
selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION

View File

@@ -112,11 +112,12 @@ gtk_css_value_shadow_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_shadow_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_shadow_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
guint i;
ShadowValue *shadows;
@@ -127,11 +128,11 @@ gtk_css_value_shadow_compute (GtkCssValue *value,
{
const ShadowValue *shadow = &value->shadows[i];
shadows[i].hoffset = _gtk_css_value_compute (shadow->hoffset, property_id, provider, style, parent_style);
shadows[i].voffset = _gtk_css_value_compute (shadow->voffset, property_id, provider, style, parent_style);
shadows[i].radius = _gtk_css_value_compute (shadow->radius, property_id, provider, style, parent_style);
shadows[i].spread = _gtk_css_value_compute (shadow->spread, property_id, provider, style, parent_style),
shadows[i].color = _gtk_css_value_compute (shadow->color, property_id, provider, style, parent_style);
shadows[i].hoffset = _gtk_css_value_compute (shadow->hoffset, property_id, provider, style, parent_style, variables);
shadows[i].voffset = _gtk_css_value_compute (shadow->voffset, property_id, provider, style, parent_style, variables);
shadows[i].radius = _gtk_css_value_compute (shadow->radius, property_id, provider, style, parent_style, variables);
shadows[i].spread = _gtk_css_value_compute (shadow->spread, property_id, provider, style, parent_style, variables),
shadows[i].color = _gtk_css_value_compute (shadow->color, property_id, provider, style, parent_style, variables);
shadows[i].inset = shadow->inset;
}
@@ -283,6 +284,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
gtk_css_value_shadow_transition,
NULL,
NULL,
NULL,
gtk_css_value_shadow_print
};

View File

@@ -322,6 +322,12 @@ gtk_css_static_style_dispose (GObject *object)
style->sections = NULL;
}
if (style->original_values)
{
g_ptr_array_unref (style->original_values);
style->original_values = NULL;
}
G_OBJECT_CLASS (gtk_css_static_style_parent_class)->dispose (object);
}
@@ -331,6 +337,19 @@ gtk_css_static_style_get_static_style (GtkCssStyle *style)
return (GtkCssStaticStyle *)style;
}
static GtkCssValue *
gtk_css_static_style_get_original_value (GtkCssStyle *style,
guint id)
{
GtkCssStaticStyle *sstyle = GTK_CSS_STATIC_STYLE (style);
if (sstyle->original_values == NULL ||
id >= sstyle->original_values->len)
return NULL;
return g_ptr_array_index (sstyle->original_values, id);
}
static void
gtk_css_static_style_class_init (GtkCssStaticStyleClass *klass)
{
@@ -341,6 +360,7 @@ gtk_css_static_style_class_init (GtkCssStaticStyleClass *klass)
style_class->get_section = gtk_css_static_style_get_section;
style_class->get_static_style = gtk_css_static_style_get_static_style;
style_class->get_original_value = gtk_css_static_style_get_original_value;
gtk_css_core_values_init ();
gtk_css_background_values_init ();
@@ -369,6 +389,13 @@ maybe_unref_section (gpointer section)
gtk_css_section_unref (section);
}
static void
maybe_unref_value (gpointer value)
{
if (value)
_gtk_css_value_unref (value);
}
static inline void
gtk_css_take_value (GtkCssValue **variable,
GtkCssValue *value)
@@ -382,6 +409,7 @@ static void
gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
guint id,
GtkCssValue *value,
GtkCssValue *original_value,
GtkCssSection *section)
{
GtkCssStyle *style = (GtkCssStyle *)sstyle;
@@ -684,6 +712,22 @@ gtk_css_static_style_set_value (GtkCssStaticStyle *sstyle,
g_ptr_array_set_size (sstyle->sections, id + 1);
g_ptr_array_index (sstyle->sections, id) = gtk_css_section_ref (section);
}
if (sstyle->original_values && sstyle->original_values->len > id &&
g_ptr_array_index (sstyle->original_values, id))
{
_gtk_css_value_unref (g_ptr_array_index (sstyle->original_values, id));
g_ptr_array_index (sstyle->original_values, id) = NULL;
}
if (original_value)
{
if (sstyle->original_values == NULL)
sstyle->original_values = g_ptr_array_new_with_free_func (maybe_unref_value);
if (sstyle->original_values->len <= id)
g_ptr_array_set_size (sstyle->original_values, id + 1);
g_ptr_array_index (sstyle->original_values, id) = _gtk_css_value_ref (original_value);
}
}
static GtkCssStyle *default_style;
@@ -912,6 +956,35 @@ gtk_css_lookup_resolve (GtkCssLookup *lookup,
gtk_internal_return_if_fail (GTK_IS_CSS_STATIC_STYLE (style));
gtk_internal_return_if_fail (parent_style == NULL || GTK_IS_CSS_STYLE (parent_style));
if (lookup->custom_values)
{
GHashTableIter iter;
gpointer id;
GtkCssVariableValue *value;
style->variables = gtk_css_variable_set_new ();
g_hash_table_iter_init (&iter, lookup->custom_values);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value))
gtk_css_variable_set_add (style->variables, GPOINTER_TO_INT (id), value);
gtk_css_variable_set_resolve_cycles (style->variables);
if (parent_style)
{
GtkCssStyle *parent_sstyle = GTK_CSS_STYLE (parent_style);
gtk_css_variable_set_set_parent (style->variables,
parent_sstyle->variables);
}
}
else if (parent_style)
{
GtkCssStyle *parent_sstyle = GTK_CSS_STYLE (parent_style);
if (parent_sstyle->variables)
style->variables = gtk_css_variable_set_ref (parent_sstyle->variables);
}
if (_gtk_bitmask_is_empty (_gtk_css_lookup_get_set_values (lookup)))
{
style->background = (GtkCssBackgroundValues *)gtk_css_values_ref (gtk_css_background_initial_values);
@@ -1047,7 +1120,7 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
GtkCssValue *specified,
GtkCssSection *section)
{
GtkCssValue *value;
GtkCssValue *value, *original_value;
GtkBorderStyle border_style;
gtk_internal_return_if_fail (id < GTK_CSS_PROPERTY_N_PROPERTIES);
@@ -1068,7 +1141,7 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
border_style = _gtk_css_border_style_value_get (gtk_css_style_get_value ((GtkCssStyle *)style, id - 1));
if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
{
gtk_css_static_style_set_value (style, id, gtk_css_dimension_value_new (0, GTK_CSS_NUMBER), section);
gtk_css_static_style_set_value (style, id, gtk_css_dimension_value_new (0, GTK_CSS_NUMBER), NULL, section);
return;
}
break;
@@ -1085,19 +1158,34 @@ gtk_css_static_style_compute_value (GtkCssStaticStyle *style,
*/
if (specified)
{
value = _gtk_css_value_compute (specified, id, provider, (GtkCssStyle *)style, parent_style);
value = _gtk_css_value_compute (specified, id, provider, (GtkCssStyle *)style, parent_style, NULL);
if (gtk_css_value_contains_variables (specified))
original_value = specified;
else
original_value = NULL;
}
else if (parent_style && _gtk_css_style_property_is_inherit (_gtk_css_style_property_lookup_by_id (id)))
{
GtkCssValue *parent_original_value;
/* Just take the style from the parent */
value = _gtk_css_value_ref (gtk_css_style_get_value (parent_style, id));
parent_original_value = gtk_css_style_get_original_value (parent_style, id);
if (parent_original_value)
original_value = parent_original_value;
else
original_value = NULL;
}
else
{
value = _gtk_css_initial_value_new_compute (id, provider, (GtkCssStyle *)style, parent_style);
original_value = NULL;
}
gtk_css_static_style_set_value (style, id, value, section);
gtk_css_static_style_set_value (style, id, value, original_value, section);
}
GtkCssChange
@@ -1107,3 +1195,15 @@ gtk_css_static_style_get_change (GtkCssStaticStyle *style)
return style->change;
}
void
gtk_css_custom_values_compute_changes_and_affects (GtkCssStyle *style1,
GtkCssStyle *style2,
GtkBitmask **changes,
GtkCssAffects *affects)
{
if (gtk_css_variable_set_equal (style1->variables, style2->variables))
return;
*changes = _gtk_bitmask_set (*changes, GTK_CSS_PROPERTY_CUSTOM, TRUE);
}

View File

@@ -40,6 +40,7 @@ struct _GtkCssStaticStyle
GtkCssStyle parent;
GPtrArray *sections; /* sections the values are defined in */
GPtrArray *original_values;
GtkCssChange change; /* change as returned by value lookup */
};

View File

@@ -35,11 +35,12 @@ gtk_css_value_string_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_string_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_string_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
return _gtk_css_value_ref (value);
}
@@ -125,6 +126,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_STRING = {
gtk_css_value_string_transition,
NULL,
NULL,
NULL,
gtk_css_value_string_print
};
@@ -136,6 +138,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_IDENT = {
gtk_css_value_string_transition,
NULL,
NULL,
NULL,
gtk_css_value_ident_print
};

View File

@@ -24,6 +24,7 @@
#include "gtkcssanimationprivate.h"
#include "gtkcssarrayvalueprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
#include "gtkcssenumvalueprivate.h"
#include "gtkcssinheritvalueprivate.h"
#include "gtkcssinitialvalueprivate.h"
@@ -73,6 +74,9 @@ gtk_css_style_finalize (GObject *object)
gtk_css_values_unref ((GtkCssValues *)style->size);
gtk_css_values_unref ((GtkCssValues *)style->other);
if (style->variables)
gtk_css_variable_set_unref (style->variables);
G_OBJECT_CLASS (gtk_css_style_parent_class)->finalize (object);
}
@@ -311,6 +315,15 @@ gtk_css_style_get_static_style (GtkCssStyle *style)
return GTK_CSS_STYLE_GET_CLASS (style)->get_static_style (style);
}
GtkCssValue *
gtk_css_style_get_original_value (GtkCssStyle *style,
guint id)
{
gtk_internal_return_val_if_fail (GTK_IS_CSS_STYLE (style), NULL);
return GTK_CSS_STYLE_GET_CLASS (style)->get_original_value (style, id);
}
/*
* gtk_css_style_print:
* @style: a `GtkCssStyle`
@@ -368,6 +381,34 @@ gtk_css_style_print (GtkCssStyle *style,
retval = TRUE;
}
if (style->variables)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
GArray *ids = gtk_css_variable_set_list_ids (style->variables);
for (i = 0; i < ids->len; i++)
{
int id = g_array_index (ids, int, i);
const char *name = gtk_css_custom_property_pool_get_name (pool, id);
GtkCssVariableValue *value = gtk_css_variable_set_lookup (style->variables, id, NULL);
g_string_append_printf (string, "%*s%s: ", indent, "", name);
gtk_css_variable_value_print (value, string);
g_string_append_c (string, ';');
if (value->section)
{
g_string_append (string, " /* ");
gtk_css_section_print (value->section, string);
g_string_append (string, " */");
}
g_string_append_c (string, '\n');
}
retval = TRUE;
}
return retval;
}
@@ -837,3 +878,13 @@ gtk_css_values_new (GtkCssValuesType type)
return values;
}
GtkCssVariableValue *
gtk_css_style_get_custom_property (GtkCssStyle *style,
int id)
{
if (style->variables)
return gtk_css_variable_set_lookup (style->variables, id, NULL);
return NULL;
}

View File

@@ -102,6 +102,12 @@ compute_change (GtkCssStyleChange *change)
change->new_style,
&change->changes,
&change->affects);
if (change->old_style->variables != change->new_style->variables)
gtk_css_custom_values_compute_changes_and_affects (change->old_style,
change->new_style,
&change->changes,
&change->affects);
}
void

View File

@@ -24,6 +24,8 @@
#include "gtk/gtkbitmaskprivate.h"
#include "gtk/gtkcssvalueprivate.h"
#include "gtk/gtkcssvariablesetprivate.h"
#include "gtk/css/gtkcssvariablevalueprivate.h"
G_BEGIN_DECLS
@@ -232,6 +234,10 @@ struct _GtkCssStyle
GtkCssTransitionValues *transition;
GtkCssSizeValues *size;
GtkCssOtherValues *other;
GtkCssVariableSet *variables;
GtkCssValue *variable_values;
int n_variable_values;
};
struct _GtkCssStyleClass
@@ -246,6 +252,9 @@ struct _GtkCssStyleClass
gboolean (* is_static) (GtkCssStyle *style);
GtkCssStaticStyle * (* get_static_style) (GtkCssStyle *style);
GtkCssValue * (* get_original_value) (GtkCssStyle *style,
guint id);
};
GType gtk_css_style_get_type (void) G_GNUC_CONST;
@@ -257,6 +266,9 @@ GtkCssSection * gtk_css_style_get_section (GtkCssStyle
gboolean gtk_css_style_is_static (GtkCssStyle *style) G_GNUC_PURE;
GtkCssStaticStyle * gtk_css_style_get_static_style (GtkCssStyle *style);
GtkCssValue * gtk_css_style_get_original_value (GtkCssStyle *style,
guint id) G_GNUC_PURE;
char * gtk_css_style_to_string (GtkCssStyle *style);
gboolean gtk_css_style_print (GtkCssStyle *style,
GString *string,
@@ -268,6 +280,9 @@ char * gtk_css_style_compute_font_features (GtkCssStyle
PangoAttrList * gtk_css_style_get_pango_attributes (GtkCssStyle *style);
PangoFontDescription * gtk_css_style_get_pango_font (GtkCssStyle *style);
GtkCssVariableValue * gtk_css_style_get_custom_property (GtkCssStyle *style,
int id);
GtkCssValues *gtk_css_values_new (GtkCssValuesType type);
GtkCssValues *gtk_css_values_ref (GtkCssValues *values);
void gtk_css_values_unref (GtkCssValues *values);
@@ -317,6 +332,10 @@ void gtk_css_other_values_compute_changes_and_affects (GtkCssStyle *style1,
GtkCssStyle *style2,
GtkBitmask **changes,
GtkCssAffects *affects);
void gtk_css_custom_values_compute_changes_and_affects (GtkCssStyle *style1,
GtkCssStyle *style2,
GtkBitmask **changes,
GtkCssAffects *affects);
G_END_DECLS

View File

@@ -273,12 +273,13 @@ gtk_css_value_transform_free (GtkCssValue *value)
/* returns TRUE if dest == src */
static gboolean
gtk_css_transform_compute (GtkCssTransform *dest,
GtkCssTransform *src,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_transform_compute (GtkCssTransform *dest,
GtkCssTransform *src,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
dest->type = src->type;
@@ -288,41 +289,41 @@ gtk_css_transform_compute (GtkCssTransform *dest,
memcpy (dest, src, sizeof (GtkCssTransform));
return TRUE;
case GTK_CSS_TRANSFORM_TRANSLATE:
dest->translate.x = _gtk_css_value_compute (src->translate.x, property_id, provider, style, parent_style);
dest->translate.y = _gtk_css_value_compute (src->translate.y, property_id, provider, style, parent_style);
dest->translate.z = _gtk_css_value_compute (src->translate.z, property_id, provider, style, parent_style);
dest->translate.x = _gtk_css_value_compute (src->translate.x, property_id, provider, style, parent_style, variables);
dest->translate.y = _gtk_css_value_compute (src->translate.y, property_id, provider, style, parent_style, variables);
dest->translate.z = _gtk_css_value_compute (src->translate.z, property_id, provider, style, parent_style, variables);
return dest->translate.x == src->translate.x
&& dest->translate.y == src->translate.y
&& dest->translate.z == src->translate.z;
case GTK_CSS_TRANSFORM_ROTATE:
dest->rotate.x = _gtk_css_value_compute (src->rotate.x, property_id, provider, style, parent_style);
dest->rotate.y = _gtk_css_value_compute (src->rotate.y, property_id, provider, style, parent_style);
dest->rotate.z = _gtk_css_value_compute (src->rotate.z, property_id, provider, style, parent_style);
dest->rotate.angle = _gtk_css_value_compute (src->rotate.angle, property_id, provider, style, parent_style);
dest->rotate.x = _gtk_css_value_compute (src->rotate.x, property_id, provider, style, parent_style, variables);
dest->rotate.y = _gtk_css_value_compute (src->rotate.y, property_id, provider, style, parent_style, variables);
dest->rotate.z = _gtk_css_value_compute (src->rotate.z, property_id, provider, style, parent_style, variables);
dest->rotate.angle = _gtk_css_value_compute (src->rotate.angle, property_id, provider, style, parent_style, variables);
return dest->rotate.x == src->rotate.x
&& dest->rotate.y == src->rotate.y
&& dest->rotate.z == src->rotate.z
&& dest->rotate.angle == src->rotate.angle;
case GTK_CSS_TRANSFORM_SCALE:
dest->scale.x = _gtk_css_value_compute (src->scale.x, property_id, provider, style, parent_style);
dest->scale.y = _gtk_css_value_compute (src->scale.y, property_id, provider, style, parent_style);
dest->scale.z = _gtk_css_value_compute (src->scale.z, property_id, provider, style, parent_style);
dest->scale.x = _gtk_css_value_compute (src->scale.x, property_id, provider, style, parent_style, variables);
dest->scale.y = _gtk_css_value_compute (src->scale.y, property_id, provider, style, parent_style, variables);
dest->scale.z = _gtk_css_value_compute (src->scale.z, property_id, provider, style, parent_style, variables);
return dest->scale.x == src->scale.x
&& dest->scale.y == src->scale.y
&& dest->scale.z == src->scale.z;
case GTK_CSS_TRANSFORM_SKEW:
dest->skew.x = _gtk_css_value_compute (src->skew.x, property_id, provider, style, parent_style);
dest->skew.y = _gtk_css_value_compute (src->skew.y, property_id, provider, style, parent_style);
dest->skew.x = _gtk_css_value_compute (src->skew.x, property_id, provider, style, parent_style, variables);
dest->skew.y = _gtk_css_value_compute (src->skew.y, property_id, provider, style, parent_style, variables);
return dest->skew.x == src->skew.x
&& dest->skew.y == src->skew.y;
case GTK_CSS_TRANSFORM_SKEW_X:
dest->skew_x.skew = _gtk_css_value_compute (src->skew_x.skew, property_id, provider, style, parent_style);
dest->skew_x.skew = _gtk_css_value_compute (src->skew_x.skew, property_id, provider, style, parent_style, variables);
return dest->skew_x.skew == src->skew_x.skew;
case GTK_CSS_TRANSFORM_SKEW_Y:
dest->skew_y.skew = _gtk_css_value_compute (src->skew_y.skew, property_id, provider, style, parent_style);
dest->skew_y.skew = _gtk_css_value_compute (src->skew_y.skew, property_id, provider, style, parent_style, variables);
return dest->skew_y.skew == src->skew_y.skew;
case GTK_CSS_TRANSFORM_PERSPECTIVE:
dest->perspective.depth = _gtk_css_value_compute (src->perspective.depth, property_id, provider, style, parent_style);
dest->perspective.depth = _gtk_css_value_compute (src->perspective.depth, property_id, provider, style, parent_style, variables);
return dest->perspective.depth == src->perspective.depth;
case GTK_CSS_TRANSFORM_NONE:
default:
@@ -332,11 +333,12 @@ gtk_css_transform_compute (GtkCssTransform *dest,
}
static GtkCssValue *
gtk_css_value_transform_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_transform_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssValue *result;
gboolean changes;
@@ -356,7 +358,8 @@ gtk_css_value_transform_compute (GtkCssValue *value,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
}
if (!changes)
@@ -798,6 +801,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_TRANSFORM = {
gtk_css_value_transform_transition,
NULL,
NULL,
NULL,
gtk_css_value_transform_print
};

View File

@@ -277,7 +277,8 @@ enum { /*< skip >*/
GTK_CSS_PROPERTY_FONT_VARIATION_SETTINGS,
GTK_CSS_PROPERTY_LINE_HEIGHT,
/* add more */
GTK_CSS_PROPERTY_N_PROPERTIES
GTK_CSS_PROPERTY_N_PROPERTIES,
GTK_CSS_PROPERTY_CUSTOM,
};
typedef enum /*< skip >*/ {

View File

@@ -35,11 +35,12 @@ gtk_css_value_unset_free (GtkCssValue *value)
}
static GtkCssValue *
gtk_css_value_unset_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
gtk_css_value_unset_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
GtkCssStyleProperty *property;
GtkCssValue *unset_value;
@@ -55,7 +56,8 @@ gtk_css_value_unset_compute (GtkCssValue *value,
property_id,
provider,
style,
parent_style);
parent_style,
variables);
}
static gboolean
@@ -89,6 +91,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_UNSET = {
gtk_css_value_unset_transition,
NULL,
NULL,
NULL,
gtk_css_value_unset_print
};

View File

@@ -199,6 +199,7 @@ gtk_css_value_unref (GtkCssValue *value)
* @provider: Style provider for looking up extra information
* @style: Style to compute for
* @parent_style: parent style to use for inherited values
* @variables: an additional set of variables to use along with @style
*
* Converts the specified @value into the computed value for the CSS
* property given by @property_id using the information in @context.
@@ -208,11 +209,12 @@ gtk_css_value_unref (GtkCssValue *value)
* Returns: the computed value
**/
GtkCssValue *
_gtk_css_value_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style)
_gtk_css_value_compute (GtkCssValue *value,
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style,
GtkCssVariableSet *variables)
{
if (gtk_css_value_is_computed (value))
return _gtk_css_value_ref (value);
@@ -221,7 +223,7 @@ _gtk_css_value_compute (GtkCssValue *value,
get_accounting_data (value->class->type_name)->computed++;
#endif
return value->class->compute (value, property_id, provider, style, parent_style);
return value->class->compute (value, property_id, provider, style, parent_style, variables);
}
gboolean
@@ -367,3 +369,14 @@ gtk_css_value_is_computed (const GtkCssValue *value)
{
return value->is_computed;
}
gboolean
gtk_css_value_contains_variables (const GtkCssValue *value)
{
gtk_internal_return_val_if_fail (value != NULL, FALSE);
if (!value->class->contains_variables)
return FALSE;
return value->class->contains_variables (value);
}

View File

@@ -22,6 +22,7 @@
#include <glib-object.h>
#include "gtkcsstypesprivate.h"
#include "gtkcssvariablesetprivate.h"
#include "gtkstyleprovider.h"
G_BEGIN_DECLS
@@ -47,7 +48,8 @@ struct _GtkCssValueClass {
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style);
GtkCssStyle *parent_style,
GtkCssVariableSet *variables);
gboolean (* equal) (const GtkCssValue *value1,
const GtkCssValue *value2);
GtkCssValue * (* transition) (GtkCssValue *start,
@@ -57,6 +59,7 @@ struct _GtkCssValueClass {
gboolean (* is_dynamic) (const GtkCssValue *value);
GtkCssValue * (* get_dynamic_value) (GtkCssValue *value,
gint64 monotonic_time);
gboolean (* contains_variables) (const GtkCssValue *value);
void (* print) (const GtkCssValue *value,
GString *string);
};
@@ -76,7 +79,8 @@ GtkCssValue *_gtk_css_value_compute (GtkCssValue
guint property_id,
GtkStyleProvider *provider,
GtkCssStyle *style,
GtkCssStyle *parent_style) G_GNUC_PURE;
GtkCssStyle *parent_style,
GtkCssVariableSet *variables) G_GNUC_PURE;
gboolean _gtk_css_value_equal (const GtkCssValue *value1,
const GtkCssValue *value2) G_GNUC_PURE;
gboolean _gtk_css_value_equal0 (const GtkCssValue *value1,
@@ -93,6 +97,7 @@ char * _gtk_css_value_to_string (const GtkCssValue
void _gtk_css_value_print (const GtkCssValue *value,
GString *string);
gboolean gtk_css_value_is_computed (const GtkCssValue *value) G_GNUC_PURE;
gboolean gtk_css_value_contains_variables (const GtkCssValue *value) G_GNUC_PURE;
G_END_DECLS

337
gtk/gtkcssvariableset.c Normal file
View File

@@ -0,0 +1,337 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#include "gtkcssvariablesetprivate.h"
#include "gtkcsscustompropertypoolprivate.h"
static void
unref_custom_property_name (gpointer pointer)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
gtk_css_custom_property_pool_unref (pool, GPOINTER_TO_INT (pointer));
}
static void
maybe_unref_variable (gpointer pointer)
{
if (pointer != NULL)
gtk_css_variable_value_unref (pointer);
}
GtkCssVariableSet *
gtk_css_variable_set_new (void)
{
GtkCssVariableSet *self = g_new0 (GtkCssVariableSet, 1);
self->ref_count = 1;
self->variables = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
unref_custom_property_name,
maybe_unref_variable);
return self;
}
GtkCssVariableSet *
gtk_css_variable_set_ref (GtkCssVariableSet *self)
{
self->ref_count++;
return self;
}
void
gtk_css_variable_set_unref (GtkCssVariableSet *self)
{
self->ref_count--;
if (self->ref_count > 0)
return;
g_hash_table_unref (self->variables);
g_clear_pointer (&self->parent, gtk_css_variable_set_unref);
g_free (self);
}
GtkCssVariableSet *
gtk_css_variable_set_copy (GtkCssVariableSet *self)
{
GtkCssVariableSet *ret = gtk_css_variable_set_new ();
GHashTableIter iter;
gpointer id;
GtkCssVariableValue *value;
g_hash_table_iter_init (&iter, self->variables);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value))
gtk_css_variable_set_add (ret, GPOINTER_TO_INT (id), value);
gtk_css_variable_set_set_parent (ret, self->parent);
return ret;
}
void
gtk_css_variable_set_set_parent (GtkCssVariableSet *self,
GtkCssVariableSet *parent)
{
if (self->parent)
gtk_css_variable_set_unref (self->parent);
self->parent = parent;
if (self->parent)
gtk_css_variable_set_ref (self->parent);
}
void
gtk_css_variable_set_add (GtkCssVariableSet *self,
int id,
GtkCssVariableValue *value)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
g_hash_table_insert (self->variables,
GINT_TO_POINTER (gtk_css_custom_property_pool_ref (pool, id)),
value ? gtk_css_variable_value_ref (value) : NULL);
}
static gboolean check_variable (GtkCssVariableSet *self,
GHashTable *unvisited_variables,
GArray *stack,
int id,
GtkCssVariableValue *value);
static gboolean
check_references (GtkCssVariableSet *self,
GHashTable *unvisited_variables,
GArray *stack,
GtkCssVariableValue *value)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
int i;
for (i = 0; i < value->n_references; i++)
{
GtkCssVariableValueReference *ref = &value->references[i];
int ref_id = gtk_css_custom_property_pool_lookup (pool, ref->name);
if (g_hash_table_contains (unvisited_variables, GINT_TO_POINTER (ref_id)))
{
GtkCssVariableValue *ref_value;
ref_value = g_hash_table_lookup (self->variables, GINT_TO_POINTER (ref_id));
if (check_variable (self, unvisited_variables, stack, ref_id, ref_value))
return TRUE;
}
if (ref->fallback)
{
if (check_references (self, unvisited_variables, stack, ref->fallback))
return TRUE;
}
}
return FALSE;
}
static gboolean
check_variable (GtkCssVariableSet *self,
GHashTable *unvisited_variables,
GArray *stack,
int id,
GtkCssVariableValue *value)
{
int i;
g_array_append_val (stack, id);
for (i = stack->len - 2; i >= 0; i--)
{
/* Found a cycle, stop checking */
if (id == g_array_index (stack, int, i))
return TRUE;
}
if (check_references (self, unvisited_variables, stack, value))
return TRUE;
g_array_remove_index_fast (stack, stack->len - 1);
g_hash_table_remove (unvisited_variables, GINT_TO_POINTER (id));
return FALSE;
}
void
gtk_css_variable_set_resolve_cycles (GtkCssVariableSet *self)
{
GHashTable *variables = g_hash_table_new (g_direct_hash, g_direct_equal);
GHashTable *unvisited_variables = g_hash_table_new (g_direct_hash, g_direct_equal);
GArray *stack;
GHashTableIter iter;
gpointer id;
GtkCssVariableValue *value;
stack = g_array_new (FALSE, FALSE, sizeof (int));
g_hash_table_iter_init (&iter, self->variables);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value))
{
/* Have 2 copies of self->variables: "variables" can be iterated safely as
* we remove values, and "unvisited_variables" as a visited node marker
* for DFS */
g_hash_table_insert (variables, id, value);
g_hash_table_add (unvisited_variables, id);
}
g_hash_table_iter_init (&iter, variables);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value))
{
if (!g_hash_table_contains (unvisited_variables, id))
continue;
if (!g_hash_table_contains (self->variables, id))
continue;
if (check_variable (self, unvisited_variables, stack, GPOINTER_TO_INT (id), value))
{
int i;
/* Found a cycle, remove the offending variables */
for (i = stack->len - 2; i >= 0; i--)
{
int id_to_remove = g_array_index (stack, int, i);
g_hash_table_remove (self->variables, GINT_TO_POINTER (id_to_remove));
if (g_array_index (stack, int, i) == g_array_index (stack, int, stack->len - 1))
break;
}
g_array_remove_range (stack, 0, stack->len);
}
}
g_array_unref (stack);
g_hash_table_unref (variables);
g_hash_table_unref (unvisited_variables);
}
GtkCssVariableValue *
gtk_css_variable_set_lookup (GtkCssVariableSet *self,
int id,
GtkCssVariableSet **source)
{
GtkCssVariableValue *ret = g_hash_table_lookup (self->variables, GINT_TO_POINTER (id));
if (ret)
{
if (source)
*source = self;
return ret;
}
if (self->parent)
return gtk_css_variable_set_lookup (self->parent, id, source);
if (source)
*source = NULL;
return NULL;
}
static int
compare_ids (gconstpointer a, gconstpointer b, gpointer user_data)
{
GtkCssCustomPropertyPool *pool = user_data;
int id1 = GPOINTER_TO_INT (*((gconstpointer *) a));
int id2 = GPOINTER_TO_INT (*((gconstpointer *) b));
const char *name1, *name2;
name1 = gtk_css_custom_property_pool_get_name (pool, id1);
name2 = gtk_css_custom_property_pool_get_name (pool, id2);
return strcmp (name1, name2);
}
GArray *
gtk_css_variable_set_list_ids (GtkCssVariableSet *self)
{
GtkCssCustomPropertyPool *pool = gtk_css_custom_property_pool_get ();
GArray *ret = g_array_new (FALSE, FALSE, sizeof (int));
GHashTableIter iter;
gpointer id;
g_hash_table_iter_init (&iter, self->variables);
while (g_hash_table_iter_next (&iter, &id, NULL))
g_array_append_val (ret, id);
g_array_sort_with_data (ret, compare_ids, pool);
return ret;
}
gboolean
gtk_css_variable_set_equal (GtkCssVariableSet *set1,
GtkCssVariableSet *set2)
{
GHashTableIter iter;
gpointer id;
GtkCssVariableValue *value1;
if (set1 == set2)
return TRUE;
if (set1 == NULL || set2 == NULL)
return FALSE;
if (g_hash_table_size (set1->variables) != g_hash_table_size (set2->variables))
return FALSE;
if (set1->parent != set2->parent)
return FALSE;
g_hash_table_iter_init (&iter, set2->variables);
while (g_hash_table_iter_next (&iter, &id, NULL))
{
if (!g_hash_table_contains (set1->variables, id))
return FALSE;
}
g_hash_table_iter_init (&iter, set1->variables);
while (g_hash_table_iter_next (&iter, &id, (gpointer) &value1))
{
GtkCssVariableValue *value2 = g_hash_table_lookup (set2->variables, id);
if (value2 == NULL)
return FALSE;
if (!gtk_css_variable_value_equal (value1, value2))
return FALSE;
}
return TRUE;
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 GNOME Foundation Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Alice Mikhaylenko <alicem@gnome.org>
*/
#pragma once
#include "gtk/css/gtkcssvariablevalueprivate.h"
G_BEGIN_DECLS
typedef struct _GtkCssVariableSet GtkCssVariableSet;
struct _GtkCssVariableSet
{
int ref_count;
GHashTable *variables;
GtkCssVariableSet *parent;
};
GtkCssVariableSet * gtk_css_variable_set_new (void);
GtkCssVariableSet * gtk_css_variable_set_ref (GtkCssVariableSet *self);
void gtk_css_variable_set_unref (GtkCssVariableSet *self);
GtkCssVariableSet * gtk_css_variable_set_copy (GtkCssVariableSet *self);
void gtk_css_variable_set_set_parent (GtkCssVariableSet *self,
GtkCssVariableSet *parent);
void gtk_css_variable_set_add (GtkCssVariableSet *self,
int id,
GtkCssVariableValue *value);
void gtk_css_variable_set_resolve_cycles (GtkCssVariableSet *self);
GtkCssVariableValue *gtk_css_variable_set_lookup (GtkCssVariableSet *self,
int id,
GtkCssVariableSet **source);
GArray * gtk_css_variable_set_list_ids (GtkCssVariableSet *self);
gboolean gtk_css_variable_set_equal (GtkCssVariableSet *set1,
GtkCssVariableSet *set2);
G_END_DECLS

View File

@@ -53,6 +53,7 @@ gtk_private_sources = files([
'gtkcsscalcvalue.c',
'gtkcsscolorvalue.c',
'gtkcsscornervalue.c',
'gtkcsscustompropertypool.c',
'gtkcssdimensionvalue.c',
'gtkcssdynamic.c',
'gtkcsseasevalue.c',
@@ -84,6 +85,7 @@ gtk_private_sources = files([
'gtkcssnumbervalue.c',
'gtkcsspalettevalue.c',
'gtkcsspositionvalue.c',
'gtkcssreferencevalue.c',
'gtkcssrepeatvalue.c',
'gtkcssselector.c',
'gtkcssshadowvalue.c',
@@ -101,6 +103,7 @@ gtk_private_sources = files([
'gtkcsstypes.c',
'gtkcssunsetvalue.c',
'gtkcssvalue.c',
'gtkcssvariableset.c',
'gtkcsswidgetnode.c',
'gtkdrop.c',
'gtkfilechooserentry.c',
@@ -759,6 +762,7 @@ if not fs.exists('theme/Default/Default-light.css')
sassc_opts = [ '-a', '-M', '-t', 'compact' ]
subdir('theme/Default')
subdir('theme/libadwaita')
theme_deps += [
default_theme_deps,
@@ -1026,6 +1030,7 @@ gtk_sources += [
gtkprivatetypebuiltins,
gtktypebuiltins,
font_script_language_sources,
libadwaita_stylesheet_resources,
]
gtk_deps = [

View File

@@ -0,0 +1,42 @@
## Summary
* To be able to use the latest/adequate version of sass, install sassc
* meson will regenerate the CSS every time you modify the SCSS files.
* Note that meson always builds out-of-tree, so the modified css files will
appear in your builddir.
## Theme Variants
The Adwaita theme comes in 4 variants: light, dark, hc (highcontrast) and
hc-dark (highcontrast inverse). The generated CSS files for the variants
are called Adwaita-$variant.css. For technical reasons, GTK adds one level
of include wrappers around these, which are called gtk-$variant.css.
## How to Tweak the Theme
Adwaita is a complex theme, so to keep it maintainable it's written and
processed in SASS. The generated CSS is then transformed into a gresource file
during gtk build and used at runtime in a non-legible or editable form.
It is very likely your change will happen in the _common.scss file. That's where
all the widget selectors are defined. Here's a rundown of the "supporting"
stylesheets, that are unlikely to be the right place for a drive by stylesheet
fix:
_colors.scss - global color definitions. We keep the number of defined
colors to a necessary minimum, most colors are derived
from a handful of basics. It covers both the light variant
and the dark variant.
_colors-public.scss - SCSS colors exported through gtk to allow for 3rd party
apps color mixing.
_drawing.scss - drawing helper mixings/functions to allow easier
definition of widget drawing under specific context. This
is why Adwaita isn't 15000 LOC.
_common.scss - actual definitions of style for each widget. This is
where you are likely to add/remove your changes.
You can read about SASS at http://sass-lang.com/documentation/. Once you make
your changes to the _common.scss file, libadwaita will rebuild the CSS files.

View File

@@ -0,0 +1,129 @@
$border_opacity: if($contrast == 'high', .5, .15);
$thin_border_opacity: if($contrast == 'high', .25, .05);
$focus_border_opacity: if($contrast == 'high', 0.8, 0.5);
// Colors from _defaults.scss
$accent_bg_color: gtkcolor(accent_bg_color);
$accent_fg_color: gtkcolor(accent_fg_color);
$accent_color: gtkcolor(accent_color);
$destructive_bg_color: gtkcolor(destructive_bg_color);
$destructive_fg_color: gtkcolor(destructive_fg_color);
$destructive_color: gtkcolor(destructive_color);
$success_bg_color: gtkcolor(success_bg_color);
$success_fg_color: gtkcolor(success_fg_color);
$success_color: gtkcolor(success_color);
$warning_bg_color: gtkcolor(warning_bg_color);
$warning_fg_color: gtkcolor(warning_fg_color);
$warning_color: gtkcolor(warning_color);
$error_bg_color: gtkcolor(error_bg_color);
$error_fg_color: gtkcolor(error_fg_color);
$error_color: gtkcolor(error_color);
$window_bg_color: gtkcolor(window_bg_color);
$window_fg_color: gtkcolor(window_fg_color);
$view_bg_color: gtkcolor(view_bg_color);
$view_fg_color: gtkcolor(view_fg_color);
$headerbar_bg_color: gtkcolor(headerbar_bg_color);
$headerbar_fg_color: gtkcolor(headerbar_fg_color);
$headerbar_border_color: gtkalpha(gtkcolor(headerbar_border_color), $border_opacity);
$headerbar_backdrop_color: gtkcolor(headerbar_backdrop_color);
$headerbar_shade_color: gtkcolor(headerbar_shade_color);
$headerbar_darker_shade_color: gtkcolor(headerbar_darker_shade_color);
$sidebar_bg_color: gtkcolor(sidebar_bg_color);
$sidebar_fg_color: gtkcolor(sidebar_fg_color);
$sidebar_backdrop_color: gtkcolor(sidebar_backdrop_color);
$sidebar_shade_color: gtkcolor(sidebar_shade_color);
$secondary_sidebar_bg_color: gtkcolor(secondary_sidebar_bg_color);
$secondary_sidebar_fg_color: gtkcolor(secondary_sidebar_fg_color);
$secondary_sidebar_backdrop_color: gtkcolor(secondary_sidebar_backdrop_color);
$secondary_sidebar_shade_color: gtkcolor(secondary_sidebar_shade_color);
$card_bg_color: gtkcolor(card_bg_color);
$card_fg_color: gtkcolor(card_fg_color);
$card_shade_color: gtkcolor(card_shade_color);
$dialog_bg_color: gtkcolor(dialog_bg_color);
$dialog_fg_color: gtkcolor(dialog_fg_color);
$popover_bg_color: gtkcolor(popover_bg_color);
$popover_fg_color: gtkcolor(popover_fg_color);
$popover_shade_color: gtkcolor(popover_shade_color);
$thumbnail_bg_color: gtkcolor(thumbnail_bg_color);
$thumbnail_fg_color: gtkcolor(thumbnail_fg_color);
$shade_color: gtkcolor(shade_color);
$scrollbar_outline_color: gtkcolor(scrollbar_outline_color);
// Other colors
$border_color: gtkalpha(currentColor, $border_opacity);
$thin_border_color: gtkalpha(currentColor, $thin_border_opacity);
$link_color: $accent_color;
$link_visited_color: gtkmix($accent_color, $view_fg_color, 80%);
$hover_color: gtkalpha(currentColor, .07);
$active_color: gtkalpha(currentColor, .16);
$selected_color: gtkalpha(currentColor, .1);
$selected_hover_color: gtkalpha(currentColor, .13);
$selected_active_color: gtkalpha(currentColor, .19);
$view_hover_color: gtkalpha(currentColor, .04);
$view_active_color: gtkalpha(currentColor, .08);
$view_selected_color: gtkalpha($accent_bg_color, .25);
$view_selected_hover_color: gtkalpha($accent_bg_color, .32);
$view_selected_active_color: gtkalpha($accent_bg_color, .39);
$trough_color: gtkalpha(currentColor, .15);
$trough_hover_color: gtkalpha(currentColor, .2);
$trough_active_color: gtkalpha(currentColor, .25);
$fill_color: $accent_bg_color;
$fill_text_color: $accent_fg_color;
$slider_color: gtkmix(white, $view_bg_color, 80%);
$slider_hover_color: white;
$osd_fg_color: transparentize(white, .1);
$osd_text_color: white;
$osd_bg_color: transparentize(black, 0.3);
$osd_fill_bg_color: transparentize(white, .25);
$osd_fill_fg_color: transparentize(black, .25);
$osd_focus_color: transparentize(white, .5);
$osd_link_color: gtkmix($accent_bg_color, $osd_text_color, 50%);
$osd_link_visited_color: gtkmix($accent_bg_color, $osd_text_color, 75%);
$tooltip_border_color: transparentize(white, 0.9);
$shadow_color: transparentize(black, 0.9);
$drop_target_color: $accent_bg_color;
$window_outline_color: transparentize(white, .93);
//special cased widget colors
$focus_border_color: gtkalpha($accent_color, $focus_border_opacity);
$dim_label_opacity: 0.55;
$dimmer_opacity: 0.3;
$disabled_opacity: 0.5;
$strong_disabled_opacity: 0.3;
// High Contrast color overrides
@if $contrast == 'high' {
$dim_label_opacity: 0.9;
$dimmer_opacity: 0.8;
$disabled_opacity: 0.4;
$trough_color: gtkalpha(currentColor, .3);
$trough_hover_color: gtkalpha(currentColor, .4);
$trough_active_color: gtkalpha(currentColor, .5);
$window_outline_color: transparentize(white, .7);
}

View File

@@ -0,0 +1,199 @@
$border_opacity: if($contrast == 'high', .5, .15);
$thin_border_opacity: if($contrast == 'high', .25, .05);
$focus_border_opacity: if($contrast == 'high', 0.8, 0.5);
// Colors from _defaults.scss
:root {
--accent-color: @accent_color;
--accent-bg-color: @accent_bg_color;
--accent-fg-color: @accent_fg_color;
--destructive-color: @destructive_color;
--destructive-bg-color: @destructive_bg_color;
--destructive-fg-color: @destructive_fg_color;
--success-color: @success_color;
--success-bg-color: @success_bg_color;
--success-fg-color: @success_fg_color;
--warning-color: @warning_color;
--warning-bg-color: @warning_bg_color;
--warning-fg-color: @warning_fg_color;
--error-color: @error_color;
--error-bg-color: @error_bg_color;
--error-fg-color: @error_fg_color;
--window-bg-color: @window_bg_color;
--window-fg-color: @window_fg_color;
--view-bg-color: @view_bg_color;
--view-fg-color: @view_fg_color;
--headerbar-bg-color: @headerbar_bg_color;
--headerbar-fg-color: @headerbar_fg_color;
--headerbar-border-color: @headerbar_border_color;
--headerbar-backdrop-color: @headerbar_backdrop_color;
--headerbar-shade-color: @headerbar_shade_color;
--headerbar-darker-shade-color: @headerbar_darker_shade_color;
--sidebar-bg-color: @sidebar_bg_color;
--sidebar-fg-color: @sidebar_fg_color;
--sidebar-backdrop-color: @sidebar_backdrop_color;
--sidebar-shade-color: @sidebar_shade_color;
--secondary-sidebar-bg-color: @secondary_sidebar_bg_color;
--secondary-sidebar-fg-color: @secondary_sidebar_fg_color;
--secondary-sidebar-backdrop-color: @secondary_sidebar_backdrop_color;
--secondary-sidebar-shade-color: @secondary_sidebar_shade_color;
--card-bg-color: @card_bg_color;
--card-fg-color: @card_fg_color;
--card-shade-color: @card_shade_color;
--dialog-bg-color: @dialog_bg_color;
--dialog-fg-color: @dialog_fg_color;
--popover-bg-color: @popover_bg_color;
--popover-fg-color: @popover_fg_color;
--popover-shade-color: @popover_shade_color;
--thumbnail-bg-color: @thumbnail_bg_color;
--thumbnail-fg-color: @thumbnail_fg_color;
--shade-color: @shade_color;
--scrollbar-outline-color: @scrollbar_outline_color;
--backdrop-accent-color: #666666;
--backdrop-accent-bg-color: #7a7a7a;
&:backdrop {
--accent-color: var(--backdrop-accent-color);
--accent-bg-color: var(--backdrop-accent-bg-color);
}
}
$accent_bg_color: var(--accent-bg-color);
$accent_fg_color: var(--accent-fg-color);
$accent_color: var(--accent-color);
$destructive_bg_color: var(--destructive-bg-color);
$destructive_fg_color: var(--destructive-fg-color);
$destructive_color: var(--destructive-color);
$success_bg_color: var(--success-bg-color);
$success_fg_color: var(--success-fg-color);
$success_color: var(--success-color);
$warning_bg_color: var(--warning-bg-color);
$warning_fg_color: var(--warning-fg-color);
$warning_color: var(--warning-color);
$error_bg_color: var(--error-bg-color);
$error_fg_color: var(--error-fg-color);
$error_color: var(--error-color);
$window_bg_color: var(--window-bg-color);
$window_fg_color: var(--window-fg-color);
$view_bg_color: var(--view-bg-color);
$view_fg_color: var(--view-fg-color);
$headerbar_bg_color: var(--headerbar-bg-color);
$headerbar_fg_color: var(--headerbar-fg-color);
$headerbar_border_color: gtkalpha(var(--headerbar-border-color), $border_opacity);
$headerbar_backdrop_color: var(--headerbar-backdrop-color);
$headerbar_shade_color: var(--headerbar-shade-color);
$headerbar_darker_shade_color: var(--headerbar-darker-shade-color);
$sidebar_bg_color: var(--sidebar-bg-color);
$sidebar_fg_color: var(--sidebar-fg-color);
$sidebar_backdrop_color: var(--sidebar-backdrop-color);
$sidebar_shade_color: var(--sidebar-shade-color);
$secondary_sidebar_bg_color: var(--secondary-sidebar-bg-color);
$secondary_sidebar_fg_color: var(--secondary-sidebar-fg-color);
$secondary_sidebar_backdrop_color: var(--secondary-sidebar-backdrop-color);
$secondary_sidebar_shade_color: var(--secondary-sidebar-shade-color);
$card_bg_color: var(--card-bg-color);
$card_fg_color: var(--card-fg-color);
$card_shade_color: var(--card-shade-color);
$dialog_bg_color: var(--dialog-bg-color);
$dialog_fg_color: var(--dialog-fg-color);
$popover_bg_color: var(--popover-bg-color);
$popover_fg_color: var(--popover-fg-color);
$popover_shade_color: var(--popover-shade-color);
$thumbnail_bg_color: var(--thumbnail-bg-color);
$thumbnail_fg_color: var(--thumbnail-fg-color);
$shade_color: var(--shade-color);
$scrollbar_outline_color: var(--scrollbar-outline-color);
// Other colors
$border_color: gtkalpha(currentColor, $border_opacity);
$thin_border_color: gtkalpha(currentColor, $thin_border_opacity);
$link_color: $accent_color;
$link_visited_color: gtkmix($accent_color, $view_fg_color, 80%);
$hover_color: gtkalpha(currentColor, .07);
$active_color: gtkalpha(currentColor, .16);
$selected_color: gtkalpha(currentColor, .1);
$selected_hover_color: gtkalpha(currentColor, .13);
$selected_active_color: gtkalpha(currentColor, .19);
$view_hover_color: gtkalpha(currentColor, .04);
$view_active_color: gtkalpha(currentColor, .08);
$view_selected_color: gtkalpha($accent_bg_color, .25);
$view_selected_hover_color: gtkalpha($accent_bg_color, .32);
$view_selected_active_color: gtkalpha($accent_bg_color, .39);
$trough_color: gtkalpha(currentColor, .15);
$trough_hover_color: gtkalpha(currentColor, .2);
$trough_active_color: gtkalpha(currentColor, .25);
$fill_color: $accent_bg_color;
$fill_text_color: $accent_fg_color;
$slider_color: gtkmix(white, $view_bg_color, 80%);
$slider_hover_color: white;
$osd_fg_color: transparentize(white, .1);
$osd_text_color: white;
$osd_bg_color: transparentize(black, 0.3);
$osd_fill_bg_color: transparentize(white, .25);
$osd_fill_fg_color: transparentize(black, .25);
$osd_focus_color: transparentize(white, .5);
$osd_link_color: gtkmix($accent_bg_color, $osd_text_color, 50%);
$osd_link_visited_color: gtkmix($accent_bg_color, $osd_text_color, 75%);
$tooltip_border_color: transparentize(white, 0.9);
$shadow_color: transparentize(black, 0.9);
$drop_target_color: $accent_bg_color;
$window_outline_color: transparentize(white, .93);
//special cased widget colors
$focus_border_color: gtkalpha($accent_color, $focus_border_opacity);
$dim_label_opacity: 0.55;
$dimmer_opacity: 0.3;
$disabled_opacity: 0.5;
$strong_disabled_opacity: 0.3;
// High Contrast color overrides
@if $contrast == 'high' {
$dim_label_opacity: 0.9;
$dimmer_opacity: 0.8;
$disabled_opacity: 0.4;
$trough_color: gtkalpha(currentColor, .3);
$trough_hover_color: gtkalpha(currentColor, .4);
$trough_active_color: gtkalpha(currentColor, .5);
$window_outline_color: transparentize(white, .7);
}

View File

@@ -0,0 +1 @@
@import 'colors-var';

View File

@@ -0,0 +1,107 @@
$ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
$backdrop_transition: 200ms ease-out;
$focus_transition: outline-color 200ms $ease-out-quad,
outline-width 200ms $ease-out-quad,
outline-offset 200ms $ease-out-quad;
$button_transition: background 200ms $ease-out-quad,
box-shadow 200ms $ease-out-quad;
$button_radius: 6px;
$card_radius: $button_radius + 6;
$menu_radius: 6px;
$menu_margin: 6px; //margin around menuitems & sidebar items
$menu_padding: 12px; //inner menuitem padding
$window_radius: $button_radius + 6;
$popover_radius: $window_radius;
.background {
color: $window_fg_color;
background-color: $window_bg_color;
}
dnd {
color: $window_fg_color;
}
.normal-icons {
-gtk-icon-size: 16px;
}
.large-icons {
-gtk-icon-size: 32px;
}
%osd,
.osd {
color: $osd_fg_color;
border: none;
background-color: $osd_bg_color;
background-clip: padding-box;
}
/* Text selection */
selection {
background-color: gtkalpha($view_fg_color, 0.1);
color: transparent;
&:focus-within {
background-color: gtkalpha($accent_bg_color, 0.3);
}
}
:not(window):drop(active):focus,
:not(window):drop(active) { // FIXME needs to be done widget by widget, this wildcard should really die
border-color: $drop_target_color;
box-shadow: inset 0 0 0 1px $drop_target_color;
caret-color: $drop_target_color;
}
.navigation-sidebar,
placessidebar,
stackswitcher,
expander-widget {
:not(window):drop(active):focus,
:not(window):drop(active) {
box-shadow: none;
}
}
/* Outline for low res icons */
.lowres-icon {
-gtk-icon-shadow: 0 -1px rgba(0,0,0,0.05),
1px 0 rgba(0,0,0,0.1),
0 1px rgba(0,0,0,0.3),
-1px 0 rgba(0,0,0,0.1);
}
/* Drop shadow for large icons */
.icon-dropshadow {
-gtk-icon-shadow: 0 1px 12px rgba(0,0,0,0.05),
0 -1px rgba(0,0,0,0.05),
1px 0 rgba(0,0,0,0.1),
0 1px rgba(0,0,0,0.3),
-1px 0 rgba(0,0,0,0.1);
}
@keyframes needs_attention {
from { background-image: radial-gradient(farthest-side, transparent 0%, transparent 0%); } // TODO
to { background-image: radial-gradient(farthest-side, transparent 95%, transparent); } // TODO
}
%needs_attention {
// the dot is drawn by using two radial gradient, the first one is the actual dot, the other
// simulates the shadow labels and icons normally have in buttons.
animation: needs_attention 150ms ease-in;
background-image: radial-gradient(farthest-side, $accent_color 96%, transparent);
background-size: 6px 6px;
background-repeat: no-repeat;
background-position: right 3px;
&:dir(rtl) {
background-position: left 3px;
}
}
@import 'widgets';

View File

View File

@@ -0,0 +1,81 @@
/* GTK NAMED COLORS
----------------
use responsibly! */
// Sass thinks we're using the colors in the variables as strings and may shoot
// warning, it's innocuous and can be defeated by using #{$var}.
// These are the colors apps are can override. We define the defaults here and
// define variables for them in _colors.scss
// The main accent color and the matching text value
@define-color accent_bg_color @blue_3;
@define-color accent_fg_color white;
@define-color accent_color #{if($variant == 'dark', #78aeed, "@blue_4")};
// destructive-action buttons
@define-color destructive_bg_color #{if($variant == 'dark', "@red_4", "@red_3")};
@define-color destructive_fg_color white;
@define-color destructive_color #{if($variant == 'dark', #ff7b63, "@red_4")};
// Levelbars, entries, labels and infobars. These don't need text colors
@define-color success_bg_color #{if($variant == 'dark', "@green_5", "@green_4")};
@define-color success_fg_color white;
@define-color success_color #{if($variant == 'dark', "@green_1", "#1b8553")};
@define-color warning_bg_color #{if($variant == 'dark', #cd9309, "@yellow_5")};
@define-color warning_fg_color #{transparentize(black, .2)};
@define-color warning_color #{if($variant == 'dark', "@yellow_2", #9c6e03)};
@define-color error_bg_color #{if($variant == 'dark', "@red_4", "@red_3")};
@define-color error_fg_color white;
@define-color error_color #{if($variant == 'dark', #ff7b63, "@red_4")};
// Window
@define-color window_bg_color #{if($variant == 'light', #fafafa, #242424)};
@define-color window_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
// Views - e.g. text view or tree view
@define-color view_bg_color #{if($variant == 'light', #ffffff, #1e1e1e)};
@define-color view_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
// Header bar, search bar, tab bar
@define-color headerbar_bg_color #{if($variant == 'light', #ffffff, #303030)};
@define-color headerbar_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color headerbar_border_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color headerbar_backdrop_color @window_bg_color;
@define-color headerbar_shade_color #{if($variant == 'light', transparentize(black, .88), transparentize(black, .64))};
@define-color headerbar_darker_shade_color #{if($variant == 'light', transparentize(black, .88), transparentize(black, .1))};
// Split pane views
@define-color sidebar_bg_color #{if($variant == 'light', #ebebeb, #303030)};
@define-color sidebar_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color sidebar_backdrop_color #{if($variant == 'light', #f2f2f2, #2a2a2a)};
@define-color sidebar_shade_color #{if($variant == 'light', transparentize(black, .93), transparentize(black, .64))};
@define-color secondary_sidebar_bg_color #{if($variant == 'light', #f3f3f3, #2a2a2a)};
@define-color secondary_sidebar_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color secondary_sidebar_backdrop_color #{if($variant == 'light', #f6f6f6, #272727)};
@define-color secondary_sidebar_shade_color #{if($variant == 'light', transparentize(black, .93), transparentize(black, .64))};
// Cards, boxed lists
@define-color card_bg_color #{if($variant == 'light', #ffffff, transparentize(white, .92))};
@define-color card_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color card_shade_color #{if($variant == 'light', transparentize(black, .93), transparentize(black, .64))};
// Dialogs
@define-color dialog_bg_color #{if($variant == 'light', #fafafa, #383838)};
@define-color dialog_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
// Popovers
@define-color popover_bg_color #{if($variant == 'light', #ffffff, #383838)};
@define-color popover_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
@define-color popover_shade_color #{if($variant == 'light', transparentize(black, .93), transparentize(black, .64))};
// Thumbnails
@define-color thumbnail_bg_color #{if($variant == 'light', #ffffff, #383838)};
@define-color thumbnail_fg_color #{if($variant == 'light', transparentize(black, .2), white)};
// Miscellaneous
@define-color shade_color #{if($variant == 'light', transparentize(black, .93), transparentize(black, .64))};
@define-color scrollbar_outline_color #{if($variant == 'light', white, transparentize(black, .5))};

View File

@@ -0,0 +1,138 @@
// Drawing mixins
// generic drawing of more complex things
//
// Helper mixin for drawing visible focus rings
//
// If $target is specified, the focus ring is applied to the specified child element.
// If $outer is true, the focus ring extends outward. Otherwise, it extends inward.
// If $within is true, use focus-within instead of focus:focus-visible
//
@mixin focus-ring($target: null, $width: 2px, $offset: -$width, $outer: false, $focus-state: ':focus:focus-visible', $fc: $focus_border_color, $transition: null) {
& #{$target} {
outline: 0 solid transparent;
outline-offset: if($outer, $offset + 4px, $offset + $width + 4px);
transition: $focus_transition, $transition;
}
&#{$focus-state} #{$target} {
outline-color: $fc;
outline-width: $width;
outline-offset: $offset;
}
}
@mixin undershoot($p, $c: $shade_color, $neighbor: false) {
//
// undershoot
//
// $p: position
// $c: shade color
// $neighbor: use ~ instead of >
//
// possible $p values:
// top, bottom, right, left
//
$_border_pos: '';
$_direction: '';
$_selector: if($neighbor, '~', '>');
@if $p==top {
$_direction: bottom;
$_border_pos: 0 1px;
} @else if $p==bottom {
$_direction: top;
$_border_pos: 0 -1px;
} @else if $p==left {
$_direction: right;
$_border_pos: 1px 0;
} @else if $p==right {
$_direction: left;
$_border_pos: -1px 0;
} @else {
@error "Unknown position #{$p}"
}
#{$_selector} undershoot.#{$p} {
box-shadow: inset $_border_pos if($contrast == 'high', $border_color, gtkalpha($c, .75));
background: linear-gradient(to $_direction, gtkalpha($c, .75), transparent 4px);
}
}
@mixin overshoot($p) {
//
// overshoot
//
// $p: position
//
// possible $p values:
// top, bottom, right, left
//
$_small_gradient_length: 3%;
$_big_gradient_length: 50%;
$_small_gradient_size: 100% $_small_gradient_length;
$_big_gradient_size: 100% $_big_gradient_length;
@if $p==right or $p==left {
$_small_gradient_size: $_small_gradient_length 100%;
$_big_gradient_size: $_big_gradient_length 100%;
}
$_small_gradient: radial-gradient(farthest-side at $p,
gtkalpha(currentColor, 0.12) 85%,
gtkalpha(currentColor, 0));
$_big_gradient: radial-gradient(farthest-side at $p,
gtkalpha(currentColor, 0.05),
gtkalpha(currentColor, 0));
background-image: $_small_gradient, $_big_gradient;
background-size: $_small_gradient_size, $_big_gradient_size;
background-repeat: no-repeat;
background-position: $p;
background-color: transparent; // reset some properties to be sure to not inherit them somehow
border: none; //
box-shadow: none; //
}
@mixin background-shadow($direction, $color) {
background-image:
linear-gradient($direction,
gtkalpha($color, 0.7),
gtkalpha($color, 0.14) 40px,
gtkalpha($color, 0) 56px),
linear-gradient($direction,
gtkalpha($color, 0.4),
gtkalpha($color, 0.14) 7px,
gtkalpha($color, 0) 24px);
}
@mixin transition-shadows($color) {
> dimming {
background: $color;
}
@if $contrast == 'high' {
> border {
min-width: 1px;
min-height: 1px;
background: $border_color;
}
}
> shadow {
min-width: 56px;
min-height: 56px;
&.left { @include background-shadow(to right, $color); }
&.right { @include background-shadow(to left, $color); }
&.up { @include background-shadow(to bottom, $color); }
&.down { @include background-shadow(to top, $color); }
}
}

View File

@@ -0,0 +1,16 @@
@function gtkalpha($c,$a) {
@return unquote("alpha(#{$c},#{$a})");
}
@function gtkmix($c1,$c2,$r) {
$ratio: 1 - $r / 100%; // match SCSS mix()
@return unquote("mix(#{$c1},#{$c2},#{$ratio})");
}
@function gtkshade($c,$s) {
@return unquote("shade(#{$c},#{$s})");
}
@function gtkcolor($c) {
@return unquote("@#{$c}");
}

View File

@@ -0,0 +1,94 @@
$blue_1: #99c1f1;
$blue_2: #62a0ea;
$blue_3: #3584e4;
$blue_4: #1c71d8;
$blue_5: #1a5fb4;
$green_1: #8ff0a4;
$green_2: #57e389;
$green_3: #33d17a;
$green_4: #2ec27e;
$green_5: #26a269;
$yellow_1: #f9f06b;
$yellow_2: #f8e45c;
$yellow_3: #f6d32d;
$yellow_4: #f5c211;
$yellow_5: #e5a50a;
$orange_1: #ffbe6f;
$orange_2: #ffa348;
$orange_3: #ff7800;
$orange_4: #e66100;
$orange_5: #c64600;
$red_1: #f66151;
$red_2: #ed333b;
$red_3: #e01b24;
$red_4: #c01c28;
$red_5: #a51d2d;
$purple_1: #dc8add;
$purple_2: #c061cb;
$purple_3: #9141ac;
$purple_4: #813d9c;
$purple_5: #613583;
$brown_1: #cdab8f;
$brown_2: #b5835a;
$brown_3: #986a44;
$brown_4: #865e3c;
$brown_5: #63452c;
$light_1: #ffffff;
$light_2: #f6f5f4;
$light_3: #deddda;
$light_4: #c0bfbc;
$light_5: #9a9996;
$dark_1: #77767b;
$dark_2: #5e5c64;
$dark_3: #3d3846;
$dark_4: #241f31;
$dark_5: #000000;
// Sass thinks we're using the colors in the variables as strings and may shoot
// warning, it's innocuous and can be defeated by using #{$var}.
@define-color blue_1 #{$blue_1};
@define-color blue_2 #{$blue_2};
@define-color blue_3 #{$blue_3};
@define-color blue_4 #{$blue_4};
@define-color blue_5 #{$blue_5};
@define-color green_1 #{$green_1};
@define-color green_2 #{$green_2};
@define-color green_3 #{$green_3};
@define-color green_4 #{$green_4};
@define-color green_5 #{$green_5};
@define-color yellow_1 #{$yellow_1};
@define-color yellow_2 #{$yellow_2};
@define-color yellow_3 #{$yellow_3};
@define-color yellow_4 #{$yellow_4};
@define-color yellow_5 #{$yellow_5};
@define-color orange_1 #{$orange_1};
@define-color orange_2 #{$orange_2};
@define-color orange_3 #{$orange_3};
@define-color orange_4 #{$orange_4};
@define-color orange_5 #{$orange_5};
@define-color red_1 #{$red_1};
@define-color red_2 #{$red_2};
@define-color red_3 #{$red_3};
@define-color red_4 #{$red_4};
@define-color red_5 #{$red_5};
@define-color purple_1 #{$purple_1};
@define-color purple_2 #{$purple_2};
@define-color purple_3 #{$purple_3};
@define-color purple_4 #{$purple_4};
@define-color purple_5 #{$purple_5};
@define-color brown_1 #{$brown_1};
@define-color brown_2 #{$brown_2};
@define-color brown_3 #{$brown_3};
@define-color brown_4 #{$brown_4};
@define-color brown_5 #{$brown_5};
@define-color light_1 #{$light_1};
@define-color light_2 #{$light_2};
@define-color light_3 #{$light_3};
@define-color light_4 #{$light_4};
@define-color light_5 #{$light_5};
@define-color dark_1 #{$dark_1};
@define-color dark_2 #{$dark_2};
@define-color dark_3 #{$dark_3};
@define-color dark_4 #{$dark_4};
@define-color dark_5 #{$dark_5};

View File

@@ -0,0 +1,41 @@
@import 'widgets/avatar';
@import 'widgets/buttons';
@import 'widgets/calendar';
@import 'widgets/checks';
@import 'widgets/color-chooser';
@import 'widgets/column-view';
@import 'widgets/dialogs';
@import 'widgets/deprecated';
@import 'widgets/dropdowns';
@import 'widgets/emoji-chooser';
@import 'widgets/entries';
@import 'widgets/expanders';
@import 'widgets/file-chooser';
@import 'widgets/header-bar';
@import 'widgets/labels';
@import 'widgets/level-bar';
@import 'widgets/linked';
@import 'widgets/links';
@import 'widgets/lists';
@import 'widgets/menus';
@import 'widgets/message-dialog';
@import 'widgets/misc';
@import 'widgets/notebook';
@import 'widgets/paned';
@import 'widgets/popovers';
@import 'widgets/preferences';
@import 'widgets/progress-bar';
@import 'widgets/scale';
@import 'widgets/scrolling';
@import 'widgets/shortcuts-window';
@import 'widgets/sidebars';
@import 'widgets/spinner';
@import 'widgets/spin-button';
@import 'widgets/switch';
@import 'widgets/tab-view';
@import 'widgets/text-selection';
@import 'widgets/toolbars';
@import 'widgets/tooltip';
@import 'widgets/views';
@import 'widgets/view-switcher';
@import 'widgets/window';

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Adwaita/styles">
<file>base.css</file>
<file>base-hc.css</file>
<file>defaults-light.css</file>
<file>defaults-dark.css</file>
<file>assets/bullet-symbolic.symbolic.png</file>
<file>assets/bullet@2-symbolic.symbolic.png</file>
<file>assets/check-symbolic.symbolic.png</file>
<file>assets/check@2-symbolic.symbolic.png</file>
<file>assets/dash-symbolic.symbolic.png</file>
<file>assets/dash@2-symbolic.symbolic.png</file>
<file>assets/bullet-symbolic.svg</file>
<file>assets/check-symbolic.svg</file>
<file>assets/dash-symbolic.svg</file>
<file>assets/devel-symbolic.svg</file>
</gresource>
<gresource prefix="/org/gtk/libgtk/theme/Adwaita">
<file>gtk.css</file>
<file>gtk-dark.css</file>
</gresource>
<gresource prefix="/org/gtk/libgtk/theme/Adwaita-HC">
<file alias="gtk.css">gtk-hc.css</file>
<file alias="gtk-dark.css">gtk-hc-dark.css</file>
</gresource>
</gresources>

View File

@@ -0,0 +1 @@
<svg height="14" width="14" xmlns="http://www.w3.org/2000/svg"><g style="display:inline"><path d="M388 342c-2.207 0-4 1.793-4 4s1.793 4 4 4c2.208 0 4-1.793 4-4s-1.792-4-4-4z" style="color:#bebebe;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:'Andale Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.389;marker:none" transform="translate(-381 -339)"/></g></svg>

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

View File

@@ -0,0 +1 @@
<svg height="14" width="14" xmlns="http://www.w3.org/2000/svg"><g style="display:inline;opacity:1"><path style="color:#000;display:inline;fill:#bebebe;fill-opacity:1;stroke-linecap:round;-inkscape-stroke:none" d="M414.145 341.9a1.25 1.25 0 0 0-1.766.092l-5.68 6.305-2.881-2.909a1.25 1.25 0 0 0-1.766 1.77l4.743 4.768 7.442-8.262a1.25 1.25 0 0 0-.092-1.764z" transform="translate(-401 -339)"/></g></svg>

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

View File

@@ -0,0 +1 @@
<svg height="14" width="14" xmlns="http://www.w3.org/2000/svg"><g style="display:inline"><path style="color:#000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M407 367h8c1.108 0 2 .892 2 2s-.892 2-2 2h-8c-1.108 0-2-.892-2-2s.892-2 2-2z" transform="translate(-404 -362)"/></g></svg>

After

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

View File

@@ -0,0 +1 @@
<svg width="60" height="47" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><path id="a" style="fill:#000;fill-opacity:1;stroke-width:27.955;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:.482318;stop-color:#000" d="M0 0h29.88l49.875 47L32.637 3l46.185 44L31.703 3l46.185 44L30.769 3l46.185 44L29.836 3 76.02 47 28.902 3l46.185 44L27.968 3l46.185 44L27.034 3 73.22 47 26.101 3l46.184 44L25.167 3l46.185 44L24.233 3l46.185 44L23.299 3l46.185 44L22.366 3 68.55 47 21.432 3l46.185 44L20.498 3l46.185 44L19.564 3 65.75 47 18.63 3l46.185 44L17.697 3l46.185 44L16.763 3l46.185 44L15.829 3l46.185 44L14.895 3 61.08 47 13.962 3l46.185 44L13.028 3l46.185 44L12.094 3 58.28 47 11.16 3l46.185 44L10.227 3l46.185 44L9.292 3l46.186 44L8.359 3l46.185 44L7.425 3 53.61 47 6.492 3l46.185 44L5.557 3l46.186 44L4.624 3 50.81 47 3.69 3l46.185 44Z"/><use xlink:href="#a" transform="translate(-59.875)" width="100%" height="100%"/></svg>

After

Width:  |  Height:  |  Size: 957 B

View File

@@ -0,0 +1,8 @@
$contrast: 'high';
@import 'palette';
@import 'functions';
@import 'colors';
@import 'drawing';
@import 'common';
@import 'compat-colors';

View File

@@ -0,0 +1,8 @@
$contrast: 'normal';
@import 'palette';
@import 'functions';
@import 'colors';
@import 'drawing';
@import 'common';
@import 'compat-colors';

View File

@@ -0,0 +1,3 @@
$variant: 'dark';
@import 'defaults';

View File

@@ -0,0 +1,3 @@
$variant: 'light';
@import 'defaults';

View File

View File

@@ -0,0 +1,2 @@
@import url("resource:///org/gnome/Adwaita/styles/base.css");
@import url("resource:///org/gnome/Adwaita/styles/defaults-dark.css");

View File

@@ -0,0 +1,2 @@
@import url("resource:///org/gnome/Adwaita/styles/base-hc.css");
@import url("resource:///org/gnome/Adwaita/styles/defaults-dark.css");

View File

@@ -0,0 +1,2 @@
@import url("resource:///org/gnome/Adwaita/styles/base-hc.css");
@import url("resource:///org/gnome/Adwaita/styles/defaults-light.css");

View File

@@ -0,0 +1,2 @@
@import url("resource:///org/gnome/Adwaita/styles/base.css");
@import url("resource:///org/gnome/Adwaita/styles/defaults-light.css");

View File

@@ -0,0 +1,101 @@
fs = import('fs')
stylesheet_deps = []
# For git checkouts, but not for tarballs...
if not fs.exists('base.css')
sassc = find_program('sassc', required: false)
if not sassc.found()
subproject('sassc', default_options: ['warning_level=0', 'werror=false'])
sassc = find_program('sassc')
endif
if sassc.found()
sassc_opts = [ '-a', '-M', '-t', 'compact' ]
scss_deps = files([
'_colors.scss',
'_colors-var.scss',
'_colors-novar.scss',
'_common.scss',
'_compat-colors.scss',
'_defaults.scss',
'_drawing.scss',
'_functions.scss',
'_widgets.scss',
'widgets/_avatar.scss',
'widgets/_buttons.scss',
'widgets/_calendar.scss',
'widgets/_checks.scss',
'widgets/_color-chooser.scss',
'widgets/_column-view.scss',
'widgets/_deprecated.scss',
'widgets/_dialogs.scss',
'widgets/_dropdowns.scss',
'widgets/_emoji-chooser.scss',
'widgets/_entries.scss',
'widgets/_expanders.scss',
'widgets/_file-chooser.scss',
'widgets/_header-bar.scss',
'widgets/_labels.scss',
'widgets/_level-bar.scss',
'widgets/_linked.scss',
'widgets/_links.scss',
'widgets/_lists.scss',
'widgets/_menus.scss',
'widgets/_message-dialog.scss',
'widgets/_misc.scss',
'widgets/_notebook.scss',
'widgets/_paned.scss',
'widgets/_popovers.scss',
'widgets/_preferences.scss',
'widgets/_progress-bar.scss',
'widgets/_scale.scss',
'widgets/_scrolling.scss',
'widgets/_shortcuts-window.scss',
'widgets/_sidebars.scss',
'widgets/_spinner.scss',
'widgets/_spin-button.scss',
'widgets/_switch.scss',
'widgets/_tab-view.scss',
'widgets/_text-selection.scss',
'widgets/_toolbars.scss',
'widgets/_tooltip.scss',
'widgets/_views.scss',
'widgets/_view-switcher.scss',
'widgets/_window.scss',
])
scss_files = [
'base',
'base-hc',
'defaults-light',
'defaults-dark',
]
foreach scss: scss_files
stylesheet_deps += custom_target('@0@.scss'.format(scss),
input: '@0@.scss'.format(scss),
output: '@0@.css'.format(scss),
command: [
sassc, sassc_opts, '@INPUT@', '@OUTPUT@',
],
depend_files: scss_deps,
)
endforeach
endif
endif
libadwaita_stylesheet_resources = gnome.compile_resources(
'adwaita-stylesheet-resources',
'adwaita-stylesheet.gresources.xml',
source_dir: [
# List in order of preference
meson.current_build_dir(),
meson.current_source_dir(),
],
dependencies: stylesheet_deps,
c_name: 'adw_stylesheet',
)

View File

@@ -0,0 +1,38 @@
avatar {
border-radius: 9999px;
font-weight: bold;
// The list of colors to generate avatars.
// Each avatar color is represented by a font color, a gradient start color and a gradient stop color.
// There are 8 different colors for avtars in the list if you change the number of them you
// need to update the NUMBER_OF_COLORS in src/adw-avatar.c.
// The 2D list has this form: ((font-color, gradient-top-color, gradient-bottom-color)).
$avatarcolorlist: (
(#cfe1f5, #83b6ec, #337fdc), // blue
(#caeaf2, #7ad9f1, #0f9ac8), // cyan
(#cef8d8, #8de6b1, #29ae74), // green
(#e6f9d7, #b5e98a, #6ab85b), // lime
(#f9f4e1, #f8e359, #d29d09), // yellow
(#ffead1, #ffcb62, #d68400), // gold
(#ffe5c5, #ffa95a, #ed5b00), // orange
(#f8d2ce, #f78773, #e62d42), // raspberry
(#fac7de, #e973ab, #e33b6a), // magenta
(#e7c2e8, #cb78d4, #9945b5), // purple
(#d5d2f5, #9e91e8, #7a59ca), // violet
(#f2eade, #e3cf9c, #b08952), // beige
(#e5d6ca, #be916d, #785336), // brown
(#d8d7d3, #c0bfbc, #6e6d71), // gray
);
@for $i from 1 through length($avatarcolorlist) {
&.color#{$i} {
$avatarcolor: nth($avatarcolorlist, $i);
background-image: linear-gradient(nth($avatarcolor, 2), nth($avatarcolor, 3));
color: nth($avatarcolor, 1);
}
}
&.contrasted { color: white; }
&.image { background: none; }
}

View File

@@ -0,0 +1,627 @@
$button_color: gtkalpha(currentColor, .1);
$button_hover_color: gtkalpha(currentColor, .15);
$button_active_color: gtkalpha(currentColor, .3);
$button_checked_color: gtkalpha(currentColor, .3);
$button_checked_hover_color: gtkalpha(currentColor, .35);
$button_checked_active_color: gtkalpha(currentColor, .4);
$opaque_button_default_bg: gtkmix($window_bg_color, $window_fg_color, 85%);
%button,
button {
@at-root %button_basic, & {
min-height: 24px;
min-width: 16px;
padding: 5px 10px;
border-radius: $button_radius;
font-weight: bold;
@include focus-ring($transition: $button_transition);
.osd &:focus:focus-visible {
outline-color: $osd_focus_color;
}
@at-root %button_basic_raised, & {
background-color: $button_color;
@if $contrast == 'high' {
box-shadow: inset 0 0 0 1px $border_color;
}
&:hover {
background-color: $button_hover_color;
}
&.keyboard-activating,
&:active {
background-color: $button_active_color;
}
&:checked {
background-color: $button_checked_color;
&:hover {
background-color: $button_checked_hover_color;
}
&.keyboard-activating,
&:active {
background-color: $button_checked_active_color;
}
}
}
&:disabled {
filter: opacity($disabled_opacity);
label {
filter: none;
}
}
&.image-button {
min-width: 24px;
padding-left: 5px;
padding-right: 5px;
}
&.text-button {
padding-left: 17px;
padding-right: 17px;
}
&.text-button.image-button,
&.image-text-button {
padding-left: 9px;
padding-right: 9px;
> box,
> box > box {
border-spacing: 4px;
> label {
padding-left: 2px;
padding-right: 2px;
}
}
}
&.arrow-button {
padding-left: 9px;
padding-right: 9px;
> box { border-spacing: 4px; }
&.text-button {
> box { border-spacing: 4px; }
}
}
@at-root %button_basic_drop_active,
&:drop(active) {
color: $drop_target_color;
box-shadow: inset 0 0 0 2px $drop_target_color;
}
}
// big standalone buttons like in Documents pager
@at-root %osd_button,
&.osd {
min-width: 32px;
min-height: 32px;
@include focus-ring($outer: true, $offset: 1px, $transition: $button_transition);
color: $osd_fg_color;
background-color: transparentize(black, .35);
@if $contrast == 'high' {
box-shadow: 0 0 0 1px currentColor;
}
&:hover {
color: white;
background-color: gtkalpha(gtkmix(black, currentColor, 85%), .65);
}
&.keyboard-activating,
&:active {
color: white;
background-color: gtkalpha(gtkmix(black, currentColor, 75%), .65);
}
&:checked {
background-color: gtkalpha(gtkmix(black, currentColor, 80%), .65);
&:hover {
background-color: gtkalpha(gtkmix(black, currentColor, 75%), .65);
}
&.keyboard-activating,
&:active {
background-color: gtkalpha(gtkmix(black, currentColor, 65%), .65);
}
}
// Specificity bump
&:drop(active) {
@extend %button_basic_drop_active;
}
.osd &:focus:focus-visible {
outline-color: $osd_focus_color;
}
}
@at-root %opaque_button {
box-shadow: none;
@include focus-ring($outer: true, $offset: 1px, $transition: $button_transition);
.osd &:focus:focus-visible {
outline-color: $osd_focus_color;
}
&:hover {
background-image: image(gtkalpha(currentColor, .1));
}
&.keyboard-activating,
&:active {
background-image: image(transparentize(black, .8));
}
&:checked {
background-image: image(transparentize(black, .85));
&:hover {
background-image: image(transparentize(black, .95));
}
&.keyboard-activating,
&:active {
background-image: image(transparentize(black, .7));
}
}
}
&.opaque {
@extend %opaque_button;
background-color: $opaque_button_default_bg;
color: $window_fg_color;
}
&.destructive-action {
@extend %opaque_button;
color: $accent_fg_color;
&, &:checked {
background-color: $accent_bg_color;
}
--accent-color: var(--destructive-color);
--accent-bg-color: var(--destructive-bg-color);
--accent-fg-color: var(--destructive-fg-color);
}
&.suggested-action {
@extend %opaque_button;
color: $accent_fg_color;
&, &:checked {
background-color: $accent_bg_color;
}
}
@at-root %button_basic_flat,
&.flat {
background: transparent;
@include focus-ring($transition: $button_transition);
.osd &:focus:focus-visible {
outline-color: $osd_focus_color;
}
box-shadow: none;
@if $contrast == 'high' {
&:hover,
&.keyboard-activating,
&:active,
&:checked {
box-shadow: inset 0 0 0 1px $border_color;
}
}
&:hover {
background: $hover_color;
}
&.keyboard-activating,
&:active {
background: $active_color;
}
&:checked {
background: $selected_color;
&:hover {
background: $selected_hover_color;
}
&.keyboard-activating,
&:active {
background: $selected_active_color;
}
}
&:disabled:not(:checked) {
filter: opacity($strong_disabled_opacity);
}
// Specificity bump
&:drop(active) {
@extend %button_basic_drop_active;
}
}
stackswitcher > & {
// to position the needs attention dot, padding is added to the button
// child, a label needs just lateral padding while an icon needs vertical
// padding added too.
> label {
padding: 0 6px;
margin: 0 -6px;
}
> image {
padding: 3px 6px;
margin: -3px -6px;
}
&.text-button { min-width: 100px; }
&.needs-attention {
> label,
> image { @extend %needs_attention; }
}
}
// hide separators
&.font {
separator { background-color: transparent; }
> box { border-spacing: 6px; }
> box > box > label { font-weight: bold; }
}
@at-root %circular_button,
&.circular { // force circular button shape
min-width: 34px;
min-height: 34px;
padding: 0;
border-radius: 9999px;
label { padding: 0; }
}
@at-root %pill_button,
&.pill {
padding: 10px 32px;
border-radius: 9999px;
}
&.card {
background-color: $card_bg_color;
background-clip: padding-box;
font-weight: inherit;
padding: 0;
@include focus-ring($offset: -1px, $transition: $button_transition);
&:hover {
background-image: image($view_hover_color);
}
&.keyboard-activating,
&:active {
background-image: image($view_active_color);
}
&:checked {
background-color: $card_bg_color;
background-image: image($view_selected_color);
&:hover { background-image: image($view_selected_hover_color); }
&.keyboard-activating,
&:active { background-image: image($view_selected_active_color); }
&.has-open-popup { background-image: image($view_selected_hover_color); }
.osd & {
background-color: gtkalpha(currentColor, .1);
}
}
&:drop(active) {
color: $drop_target_color;
box-shadow: inset 0 0 0 1px $drop_target_color;
}
}
}
%undecorated_button {
background-color: transparent;
}
button.color {
padding: 5px;
> colorswatch:only-child {
border-radius: 2.5px;
> overlay {
border-radius: 2px;
}
&:disabled {
filter: none;
}
&.light > overlay {
border-color: gtkalpha($view_fg_color, 0.1);
}
}
}
menubutton {
&.osd {
background: none;
color: inherit;
> button { @extend %osd_button; }
}
&.circular > button { @extend %circular_button; }
&.flat > button { @extend %button_basic_flat; }
&.pill > button { @extend %pill_button; }
&.suggested-action {
background-color: $accent_bg_color;
color: $accent_fg_color;
}
&.opaque {
background-color: $opaque_button_default_bg;
color: $window_fg_color;
}
&.suggested-action,
&.destructive-action,
&.opaque {
border-radius: $button_radius;
&.circular, &.pill {
border-radius: 9999px;
}
> button {
@extend %opaque_button;
&, &:checked {
background-color: transparent;
color: inherit;
}
}
}
&.image-button > button {
min-width: 24px;
padding-left: 5px;
padding-right: 5px;
}
&.card > button {
border-radius: $card_radius;
}
arrow {
min-height: 16px;
min-width: 16px;
&.none {
-gtk-icon-source: -gtk-icontheme('open-menu-symbolic');
}
&.down {
-gtk-icon-source: -gtk-icontheme('pan-down-symbolic');
}
&.up {
-gtk-icon-source: -gtk-icontheme('pan-up-symbolic');
}
&.left {
-gtk-icon-source: -gtk-icontheme('pan-start-symbolic');
}
&.right {
-gtk-icon-source: -gtk-icontheme('pan-end-symbolic');
}
}
}
splitbutton {
border-radius: $button_radius;
&, & > separator {
transition: $button_transition;
transition-property: background;
}
> separator {
margin-top: 6px;
margin-bottom: 6px;
background: none;
}
> menubutton > button {
padding-left: 4px;
padding-right: 4px;
}
// Since the inner button doesn't have any style classes on it,
// we have to add them manually
&.image-button > button {
min-width: 24px;
padding-left: 5px;
padding-right: 5px;
}
&.text-button.image-button > button,
&.image-text-button > button {
padding-left: 9px;
padding-right: 9px;
> box {
border-spacing: 6px;
}
}
&:disabled {
filter: opacity($disabled_opacity);
> button, > menubutton > button {
filter: none;
}
}
// Reimplementing linked so we don't blow up css
> button:dir(ltr),
> menubutton > button:dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
margin-right: -1px;
}
> button:dir(rtl),
> menubutton > button:dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
margin-left: -1px;
}
@at-root %flat_split_button,
&.flat {
> separator {
background: gtkalpha(currentColor, $dimmer_opacity);
}
&:hover,
&:active,
&:checked {
background: $hover_color;
> separator {
background: none;
}
@if $contrast == 'high' {
box-shadow: inset 0 0 0 1px $thin_border_color;
}
}
&:disabled {
filter: opacity($strong_disabled_opacity);
> button:disabled, > menubutton > button:disabled {
filter: none;
}
}
&:focus-within:focus-visible > separator {
background: none;
}
> button,
> menubutton > button {
@extend %button_basic_flat;
border-radius: $button_radius;
}
}
&.suggested-action {
background-color: $accent_bg_color;
color: $accent_fg_color;
}
&.destructive-action {
background-color: $destructive_bg_color;
color: $destructive_fg_color;
}
&.opaque {
background-color: $opaque_button_default_bg;
color: $window_fg_color;
}
&.suggested-action,
&.destructive-action,
&.opaque {
> button, > menubutton > button {
@extend %opaque_button;
&, &:checked {
color: inherit;
background-color: transparent;
}
}
$_separator_color: gtkalpha(currentColor, $dimmer_opacity);
> menubutton > button {
&:dir(ltr) { box-shadow: inset 1px 0 $_separator_color; }
&:dir(rtl) { box-shadow: inset -1px 0 $_separator_color; }
}
}
> menubutton > button > arrow.none {
-gtk-icon-source: -gtk-icontheme('pan-down-symbolic');
}
}
buttoncontent {
> box {
border-spacing: 6px;
> label {
font-weight: bold;
&:dir(ltr) { padding-right: 2px; }
&:dir(rtl) { padding-left: 2px; }
}
}
.arrow-button > box > &,
splitbutton > button > & {
> box > label {
&:dir(ltr) { padding-right: 0; }
&:dir(rtl) { padding-left: 0; }
}
}
}
tabbutton {
label {
font-weight: 800;
font-size: 8pt;
&.small {
font-size: 6pt;
}
}
indicatorbin > indicator,
indicatorbin > mask {
transform: translate(-1px, 1px);
}
}

Some files were not shown because too many files have changed in this diff Show More