* 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk/gdk.h>
+#include <math.h>
#include <stdlib.h>
#include <gobject/gvaluecollector.h>
-#include "gtkstylecontext.h"
+#include "gtkstylecontextprivate.h"
+#include "gtkcontainerprivate.h"
+#include "gtkcsscolorvalueprivate.h"
+#include "gtkcsscornervalueprivate.h"
+#include "gtkcssenginevalueprivate.h"
+#include "gtkcssnumbervalueprivate.h"
+#include "gtkcssrgbavalueprivate.h"
+#include "gtkdebug.h"
+#include "gtkstylepropertiesprivate.h"
#include "gtktypebuiltins.h"
-#include "gtkthemingengine.h"
+#include "gtkthemingengineprivate.h"
#include "gtkintl.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
-#include "gtksymboliccolor.h"
-#include "gtkanimationdescription.h"
-#include "gtktimeline.h"
#include "gtkiconfactory.h"
+#include "gtkwidgetpath.h"
+#include "gtkwidgetprivate.h"
+#include "gtkstylecascadeprivate.h"
+#include "gtkstyleproviderprivate.h"
+#include "gtksettings.h"
+#include "gtksettingsprivate.h"
+
+#include "deprecated/gtkgradientprivate.h"
+#include "deprecated/gtksymboliccolorprivate.h"
/**
* SECTION:gtkstylecontext
* can be either attached explicitly to the context through
* gtk_style_context_add_provider(), or to the screen through
* gtk_style_context_add_provider_for_screen(). The resulting style is a
- * combination of all provider's information in priority order.
+ * combination of all providers' information in priority order.
*
* For GTK+ widgets, any #GtkStyleContext returned by
* gtk_widget_get_style_context() will already have a #GtkWidgetPath, a
- * #GdkScreen and RTL/LTR information set, the style context will be also
+ * #GdkScreen and RTL/LTR information set. The style context will be also
* updated automatically if any of these settings change on the widget.
*
- * If you are using are the theming layer standalone, you will need to set a
+ * If you are using the theming layer standalone, you will need to set a
* widget path and a screen yourself to the created style context through
* gtk_style_context_set_path() and gtk_style_context_set_screen(), as well
* as updating the context yourself using gtk_style_context_invalidate()
* Widgets can add style classes to their context, which can be used
* to associate different styles by class (see <xref linkend="gtkcssprovider-selectors"/>). Theme engines can also use style classes to vary their
* rendering. GTK+ has a number of predefined style classes:
- * <informaltable>
- * <tgroup cols="3">
- * <thead>
- * <row>
- * <entry>Style class</entry>
- * <entry>Macro</entry>
- * <entry>Used by</entry>
- * </row>
- * </thead>
- * <tbody>
- * <row>
- * <entry>button</entry>
- * <entry>GTK_STYLE_CLASS_BUTTON</entry>
- * <entry>#GtkButton, #GtkToggleButton, #GtkRadioButton, #GtkCheckButton</entry>
- * </row>
- * <row>
- * <entry>default</entry>
- * <entry>GTK_STYLE_CLASS_DEFAULT</entry>
- * <entry>#GtkButton</entry>
- * </row>
- * <row>
- * <entry>check</entry>
- * <entry>GTK_STYLE_CLASS_CHECK</entry>
- * <entry>#GtkCheckButton, #GtkCheckMenuItem, #GtkCellRendererToggle</entry>
- * </row>
- * <row>
- * <entry>radio</entry>
- * <entry>GTK_STYLE_CLASS_RADIO</entry>
- * <entry>#GtkRadioButton, #GtkRadioMenuItem, #GtkCellRendererToggle</entry>
- * </row>
- * <row>
- * <entry>arrow</entry>
- * <entry>GTK_STYLE_CLASS_ARROW</entry>
- * <entry>#GtkArrow</entry>
- * </row>
- * <row>
- * <entry>calendar</entry>
- * <entry>GTK_STYLE_CLASS_CALENDAR</entry>
- * <entry>#GtkCalendar</entry>
- * </row>
- * <row>
- * <entry>entry</entry>
- * <entry>GTK_STYLE_CLASS_ENTRY</entry>
- * <entry>#GtkEntry</entry>
- * </row>
- * <row>
- * <entry>cell</entry>
- * <entry>GTK_STYLE_CLASS_CELL</entry>
- * <entry>#GtkCellRendererToggle</entry>
- * </row>
- * <row>
- * <entry>menu</entry>
- * <entry>GTK_STYLE_CLASS_MENU</entry>
- * <entry>#GtkMenu, #GtkMenuItem, #GtkCheckMenuItem, #GtkRadioMenuItem</entry>
- * </row>
- * <row>
- * <entry>expander</entry>
- * <entry>GTK_STYLE_CLASS_EXPANDER</entry>
- * <entry>#GtkExpander</entry>
- * </row>
- * <row>
- * <entry>tooltip</entry>
- * <entry>GTK_STYLE_CLASS_TOOLTIP</entry>
- * <entry>#GtkTooltip</entry>
- * </row>
- * <row>
- * <entry>frame</entry>
- * <entry>GTK_STYLE_CLASS_FRAME</entry>
- * <entry>#GtkFrame</entry>
- * </row>
- * <row>
- * <entry>scrolled-window</entry>
- * <entry></entry>
- * <entry>#GtkScrolledWindow</entry>
- * </row>
- * <row>
- * <entry>viewport</entry>
- * <entry></entry>
- * <entry>#GtkViewport</entry>
- * </row>
- * <row>
- * <entry>trough</entry>
- * <entry>GTK_STYLE_CLASS_TROUGH</entry>
- * <entry>#GtkScrollbar, #GtkProgressBar, #GtkScale</entry>
- * </row>
- * <row>
- * <entry>progressbar</entry>
- * <entry>GTK_STYLE_CLASS_PROGRESSBAR</entry>
- * <entry>#GtkProgressBar, #GtkCellRendererProgress</entry>
- * </row>
- * <row>
- * <entry>slider</entry>
- * <entry>GTK_STYLE_CLASS_SLIDER</entry>
- * <entry>#GtkScrollbar, #GtkScale</entry>
- * </row>
- * <row>
- * <entry>menuitem</entry>
- * <entry>GTK_STYLE_CLASS_MENUITEM</entry>
- * <entry>#GtkMenuItem</entry>
- * </row>
- * <row>
- * <entry>popup</entry>
- * <entry></entry>
- * <entry>#GtkMenu</entry>
- * </row>
- * <row>
- * <entry>accelerator</entry>
- * <entry>GTK_STYLE_CLASS_ACCELERATOR</entry>
- * <entry>#GtkAccelLabel</entry>
- * </row>
- * <row>
- * <entry>menubar</entry>
- * <entry>GTK_STYLE_CLASS_MENUBAR</entry>
- * <entry>#GtkMenuBar</entry>
- * </row>
- * <row>
- * <entry>toolbar</entry>
- * <entry>GTK_STYLE_CLASS_TOOLBAR</entry>
- * <entry>#GtkToolbar</entry>
- * </row>
- * <row>
- * <entry>dock</entry>
- * <entry>GTK_STYLE_CLASS_DOCK</entry>
- * <entry>#GtkHandleBox</entry>
- * </row>
- * <row>
- * <entry>notebook</entry>
- * <entry></entry>
- * <entry>#GtkNotebook</entry>
- * </row>
- * <row>
- * <entry>background</entry>
- * <entry>GTK_STYLE_CLASS_BACKGROUND</entry>
- * <entry>#GtkWindow</entry>
- * </row>
- * <row>
- * <entry>rubberband</entry>
- * <entry>GTK_STYLE_CLASS_RUBBERBAND</entry>
- * <entry></entry>
- * </row>
- * <row>
- * <entry>header</entry>
- * <entry>GTK_STYLE_CLASS_HEADER</entry>
- * <entry></entry>
- * </row>
- * <row>
- * <entry>grip</entry>
- * <entry>GTK_STYLE_CLASS_GRIP</entry>
- * <entry>#GtkWindow</entry>
- * </row>
- * <row>
- * <entry>spinner</entry>
- * <entry>GTK_STYLE_CLASS_SPINNER</entry>
- * <entry>#GtkSpinner</entry>
- * </row>
- * </tbody>
- * </tgroup>
- * </informaltable>
+ * #GTK_STYLE_CLASS_CELL,
+ * #GTK_STYLE_CLASS_ENTRY,
+ * #GTK_STYLE_CLASS_BUTTON,
+ * #GTK_STYLE_CLASS_COMBOBOX_ENTRY,
+ * #GTK_STYLE_CLASS_CALENDAR,
+ * #GTK_STYLE_CLASS_SLIDER,
+ * #GTK_STYLE_CLASS_BACKGROUND,
+ * #GTK_STYLE_CLASS_RUBBERBAND,
+ * #GTK_STYLE_CLASS_TOOLTIP,
+ * #GTK_STYLE_CLASS_MENU,
+ * #GTK_STYLE_CLASS_MENUBAR,
+ * #GTK_STYLE_CLASS_MENUITEM,
+ * #GTK_STYLE_CLASS_TOOLBAR,
+ * #GTK_STYLE_CLASS_PRIMARY_TOOLBAR,
+ * #GTK_STYLE_CLASS_INLINE_TOOLBAR,
+ * #GTK_STYLE_CLASS_RADIO,
+ * #GTK_STYLE_CLASS_CHECK,
+ * #GTK_STYLE_CLASS_TROUGH,
+ * #GTK_STYLE_CLASS_SCROLLBAR,
+ * #GTK_STYLE_CLASS_SCALE,
+ * #GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE,
+ * #GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW,
+ * #GTK_STYLE_CLASS_HEADER,
+ * #GTK_STYLE_CLASS_ACCELERATOR,
+ * #GTK_STYLE_CLASS_GRIP,
+ * #GTK_STYLE_CLASS_DOCK,
+ * #GTK_STYLE_CLASS_PROGRESSBAR,
+ * #GTK_STYLE_CLASS_SPINNER,
+ * #GTK_STYLE_CLASS_EXPANDER,
+ * #GTK_STYLE_CLASS_SPINBUTTON,
+ * #GTK_STYLE_CLASS_NOTEBOOK,
+ * #GTK_STYLE_CLASS_VIEW,
+ * #GTK_STYLE_CLASS_SIDEBAR,
+ * #GTK_STYLE_CLASS_IMAGE,
+ * #GTK_STYLE_CLASS_HIGHLIGHT,
+ * #GTK_STYLE_CLASS_FRAME,
+ * #GTK_STYLE_CLASS_DND,
+ * #GTK_STYLE_CLASS_PANE_SEPARATOR,
+ * #GTK_STYLE_CLASS_SEPARATOR,
+ * #GTK_STYLE_CLASS_INFO,
+ * #GTK_STYLE_CLASS_WARNING,
+ * #GTK_STYLE_CLASS_QUESTION,
+ * #GTK_STYLE_CLASS_ERROR,
+ * #GTK_STYLE_CLASS_HORIZONTAL,
+ * #GTK_STYLE_CLASS_VERTICAL,
+ * #GTK_STYLE_CLASS_TOP,
+ * #GTK_STYLE_CLASS_BOTTOM,
+ * #GTK_STYLE_CLASS_LEFT,
+ * #GTK_STYLE_CLASS_RIGHT,
* </para>
* <para>
* Widgets can also add regions with flags to their context.
* </refsect2>
*/
-typedef struct GtkStyleContextPrivate GtkStyleContextPrivate;
-typedef struct GtkStyleProviderData GtkStyleProviderData;
+/* When these change we do a full restyling. Otherwise we try to figure out
+ * if we need to change things. */
+#define GTK_STYLE_CONTEXT_RADICAL_CHANGE (GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_SOURCE)
+/* When these change we don't clear the cache. This takes more memory but makes
+ * things go faster. */
+#define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE)
+
typedef struct GtkStyleInfo GtkStyleInfo;
typedef struct GtkRegion GtkRegion;
typedef struct PropertyValue PropertyValue;
-typedef struct AnimationInfo AnimationInfo;
typedef struct StyleData StyleData;
struct GtkRegion
GtkRegionFlags flags;
};
-struct GtkStyleProviderData
-{
- GtkStyleProvider *provider;
- guint priority;
-};
-
struct PropertyValue
{
GType widget_type;
struct GtkStyleInfo
{
+ GtkStyleInfo *next;
GArray *style_classes;
GArray *regions;
GtkJunctionSides junction_sides;
GtkStateFlags state_flags;
+ StyleData *data;
};
struct StyleData
{
- GtkStyleProperties *store;
- GSList *icon_factories;
+ GtkCssComputedValues *store;
GArray *property_cache;
+ guint ref_count;
};
-struct AnimationInfo
-{
- GtkTimeline *timeline;
-
- gpointer region_id;
- GdkWindow *window;
- GtkStateType state;
- gboolean target_value;
-
- cairo_region_t *invalidation_region;
- GArray *rectangles;
-};
-
-struct GtkStyleContextPrivate
+struct _GtkStyleContextPrivate
{
GdkScreen *screen;
- GList *providers;
- GList *providers_last;
+ GtkStyleCascade *cascade;
+ GtkStyleContext *parent;
+ GSList *children;
+ GtkWidget *widget;
GtkWidgetPath *widget_path;
GHashTable *style_data;
- GSList *info_stack;
- StyleData *current_data;
-
- GSList *animation_regions;
- GSList *animations;
+ GtkStyleInfo *info;
- guint animations_invalidated : 1;
- guint invalidating_context : 1;
+ GdkFrameClock *frame_clock;
+ guint frame_clock_update_id;
- GtkThemingEngine *theming_engine;
+ GtkCssChange relevant_changes;
+ GtkCssChange pending_changes;
- GtkTextDirection direction;
+ const GtkBitmask *invalidating_context;
+ guint animating : 1;
+ guint invalid : 1;
};
enum {
PROP_0,
PROP_SCREEN,
- PROP_DIRECTION
+ PROP_DIRECTION,
+ PROP_FRAME_CLOCK,
+ PROP_PARENT
};
enum {
static guint signals[LAST_SIGNAL] = { 0 };
-static GQuark provider_list_quark = 0;
-
static void gtk_style_context_finalize (GObject *object);
static void gtk_style_context_impl_set_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
+static StyleData *style_data_lookup (GtkStyleContext *context);
+static void gtk_style_context_disconnect_update (GtkStyleContext *context);
+static void gtk_style_context_connect_update (GtkStyleContext *context);
+
G_DEFINE_TYPE (GtkStyleContext, gtk_style_context, G_TYPE_OBJECT)
+static void
+gtk_style_context_real_changed (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+
+ if (priv->widget)
+ _gtk_widget_style_context_invalidated (priv->widget);
+}
+
static void
gtk_style_context_class_init (GtkStyleContextClass *klass)
{
object_class->set_property = gtk_style_context_impl_set_property;
object_class->get_property = gtk_style_context_impl_get_property;
+ klass->changed = gtk_style_context_real_changed;
+
signals[CHANGED] =
g_signal_new (I_("changed"),
G_TYPE_FROM_CLASS (object_class),
P_("The associated GdkScreen"),
GDK_TYPE_SCREEN,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_FRAME_CLOCK,
+ g_param_spec_object ("paint-clock",
+ P_("FrameClock"),
+ P_("The associated GdkFrameClock"),
+ GDK_TYPE_FRAME_CLOCK,
+ GTK_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DIRECTION,
g_param_spec_enum ("direction",
GTK_TYPE_TEXT_DIRECTION,
GTK_TEXT_DIR_LTR,
GTK_PARAM_READWRITE));
+ /**
+ * GtkStyleContext:parent:
+ *
+ * Sets or gets the style context's parent. See gtk_style_context_set_parent()
+ * for details.
+ *
+ * Since: 3.4
+ */
+ g_object_class_install_property (object_class,
+ PROP_PARENT,
+ g_param_spec_object ("parent",
+ P_("Parent"),
+ P_("The parent style context"),
+ GTK_TYPE_STYLE_CONTEXT,
+ GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkStyleContextPrivate));
}
+static StyleData *
+style_data_new (void)
+{
+ StyleData *data;
+
+ data = g_slice_new0 (StyleData);
+ data->ref_count = 1;
+
+ return data;
+}
+
+static void
+clear_property_cache (StyleData *data)
+{
+ guint i;
+
+ if (!data->property_cache)
+ return;
+
+ for (i = 0; i < data->property_cache->len; i++)
+ {
+ PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
+
+ g_param_spec_unref (node->pspec);
+ g_value_unset (&node->value);
+ }
+
+ g_array_free (data->property_cache, TRUE);
+ data->property_cache = NULL;
+}
+
+static StyleData *
+style_data_ref (StyleData *style_data)
+{
+ style_data->ref_count++;
+
+ return style_data;
+}
+
+static void
+style_data_unref (StyleData *data)
+{
+ data->ref_count--;
+
+ if (data->ref_count > 0)
+ return;
+
+ g_object_unref (data->store);
+ clear_property_cache (data);
+
+ g_slice_free (StyleData, data);
+}
+
+static gboolean
+style_data_is_animating (StyleData *style_data)
+{
+ return !_gtk_css_computed_values_is_static (style_data->store);
+}
+
static GtkStyleInfo *
style_info_new (void)
{
return info;
}
+static void
+style_info_set_data (GtkStyleInfo *info,
+ StyleData *data)
+{
+ if (info->data == data)
+ return;
+
+ if (data)
+ style_data_ref (data);
+
+ if (info->data)
+ style_data_unref (info->data);
+
+ info->data = data;
+}
+
static void
style_info_free (GtkStyleInfo *info)
{
+ style_info_set_data (info, NULL);
g_array_free (info->style_classes, TRUE);
g_array_free (info->regions, TRUE);
g_slice_free (GtkStyleInfo, info);
}
static GtkStyleInfo *
-style_info_copy (const GtkStyleInfo *info)
+style_info_pop (GtkStyleInfo *info)
+{
+ GtkStyleInfo *next = info->next;
+
+ style_info_free (info);
+
+ return next;
+}
+
+static GtkStyleInfo *
+style_info_copy (GtkStyleInfo *info)
{
GtkStyleInfo *copy;
info->regions->data,
info->regions->len);
+ copy->next = info;
copy->junction_sides = info->junction_sides;
copy->state_flags = info->state_flags;
+ style_info_set_data (copy, info->data);
return copy;
}
hash <<= 5;
}
- return hash;
+ return hash ^ info->state_flags;
}
static gboolean
info1 = elem1;
info2 = elem2;
+ if (info1->state_flags != info2->state_flags)
+ return FALSE;
+
if (info1->junction_sides != info2->junction_sides)
return FALSE;
return TRUE;
}
-static StyleData *
-style_data_new (void)
+static void
+gtk_style_context_cascade_changed (GtkStyleCascade *cascade,
+ GtkStyleContext *context)
{
- StyleData *data;
-
- data = g_slice_new0 (StyleData);
- data->store = gtk_style_properties_new ();
-
- return data;
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_SOURCE);
}
static void
-clear_property_cache (StyleData *data)
+gtk_style_context_set_cascade (GtkStyleContext *context,
+ GtkStyleCascade *cascade)
{
- guint i;
+ GtkStyleContextPrivate *priv;
- if (!data->property_cache)
+ priv = context->priv;
+
+ if (priv->cascade == cascade)
return;
- for (i = 0; i < data->property_cache->len; i++)
+ if (cascade)
{
- PropertyValue *node = &g_array_index (data->property_cache, PropertyValue, i);
-
- g_param_spec_unref (node->pspec);
- g_value_unset (&node->value);
+ g_object_ref (cascade);
+ g_signal_connect (cascade,
+ "-gtk-private-changed",
+ G_CALLBACK (gtk_style_context_cascade_changed),
+ context);
}
- g_array_free (data->property_cache, TRUE);
- data->property_cache = NULL;
-}
-
-static void
-style_data_free (StyleData *data)
-{
- g_object_unref (data->store);
- clear_property_cache (data);
+ if (priv->cascade)
+ {
+ g_signal_handlers_disconnect_by_func (priv->cascade,
+ gtk_style_context_cascade_changed,
+ context);
+ g_object_unref (priv->cascade);
+ }
- g_slist_foreach (data->icon_factories, (GFunc) g_object_unref, NULL);
- g_slist_free (data->icon_factories);
+ priv->cascade = cascade;
- g_slice_free (StyleData, data);
+ if (cascade)
+ gtk_style_context_cascade_changed (cascade, context);
}
static void
gtk_style_context_init (GtkStyleContext *style_context)
{
GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
priv = style_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (style_context,
GTK_TYPE_STYLE_CONTEXT,
priv->style_data = g_hash_table_new_full (style_info_hash,
style_info_equal,
(GDestroyNotify) style_info_free,
- (GDestroyNotify) style_data_free);
- priv->theming_engine = g_object_ref ((gpointer) gtk_theming_engine_load (NULL));
-
- priv->direction = GTK_TEXT_DIR_RTL;
+ (GDestroyNotify) style_data_unref);
priv->screen = gdk_screen_get_default ();
+ priv->relevant_changes = GTK_CSS_CHANGE_ANY;
/* Create default info store */
- info = style_info_new ();
- priv->info_stack = g_slist_prepend (priv->info_stack, info);
-}
-
-static GtkStyleProviderData *
-style_provider_data_new (GtkStyleProvider *provider,
- guint priority)
-{
- GtkStyleProviderData *data;
-
- data = g_slice_new (GtkStyleProviderData);
- data->provider = g_object_ref (provider);
- data->priority = priority;
+ priv->info = style_info_new ();
+ priv->info->state_flags = GTK_STATE_FLAG_DIR_LTR;
- return data;
+ gtk_style_context_set_cascade (style_context,
+ _gtk_style_cascade_get_for_screen (priv->screen));
}
static void
-style_provider_data_free (GtkStyleProviderData *data)
+gtk_style_context_update (GdkFrameClock *clock,
+ GtkStyleContext *context)
{
- g_object_unref (data->provider);
- g_slice_free (GtkStyleProviderData, data);
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANIMATE);
}
-static void
-animation_info_free (AnimationInfo *info)
+static gboolean
+gtk_style_context_is_animating (GtkStyleContext *context)
{
- g_object_unref (info->timeline);
- g_object_unref (info->window);
-
- if (info->invalidation_region)
- cairo_region_destroy (info->invalidation_region);
+ GtkStyleContextPrivate *priv = context->priv;
- g_array_free (info->rectangles, TRUE);
- g_slice_free (AnimationInfo, info);
+ return priv->animating;
}
-static AnimationInfo *
-animation_info_lookup_by_timeline (GtkStyleContext *context,
- GtkTimeline *timeline)
+static void
+gtk_style_context_disconnect_update (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- AnimationInfo *info;
- GSList *l;
-
- priv = context->priv;
+ GtkStyleContextPrivate *priv = context->priv;
- for (l = priv->animations; l; l = l->next)
+ if (priv->frame_clock && priv->frame_clock_update_id)
{
- info = l->data;
-
- if (info->timeline == timeline)
- return info;
+ g_signal_handler_disconnect (priv->frame_clock,
+ priv->frame_clock_update_id);
+ priv->frame_clock_update_id = 0;
+ gdk_frame_clock_end_updating (priv->frame_clock);
}
-
- return NULL;
}
static void
-timeline_frame_cb (GtkTimeline *timeline,
- gdouble progress,
- gpointer user_data)
+gtk_style_context_connect_update (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- GtkStyleContext *context;
- AnimationInfo *info;
+ GtkStyleContextPrivate *priv = context->priv;
- context = user_data;
- priv = context->priv;
- info = animation_info_lookup_by_timeline (context, timeline);
-
- g_assert (info != NULL);
-
- /* Cancel transition if window is gone */
- if (gdk_window_is_destroyed (info->window) ||
- !gdk_window_is_visible (info->window))
+ if (priv->frame_clock && priv->frame_clock_update_id == 0)
{
- priv->animations = g_slist_remove (priv->animations, info);
- animation_info_free (info);
- return;
+ priv->frame_clock_update_id = g_signal_connect (priv->frame_clock,
+ "update",
+ G_CALLBACK (gtk_style_context_update),
+ context);
+ gdk_frame_clock_begin_updating (priv->frame_clock);
}
-
- if (info->invalidation_region &&
- !cairo_region_is_empty (info->invalidation_region))
- gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
- else
- gdk_window_invalidate_rect (info->window, NULL, TRUE);
}
static void
-timeline_finished_cb (GtkTimeline *timeline,
- gpointer user_data)
+gtk_style_context_stop_animating (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- GtkStyleContext *context;
- AnimationInfo *info;
+ GtkStyleContextPrivate *priv = context->priv;
- context = user_data;
- priv = context->priv;
- info = animation_info_lookup_by_timeline (context, timeline);
-
- g_assert (info != NULL);
-
- priv->animations = g_slist_remove (priv->animations, info);
+ if (!gtk_style_context_is_animating (context))
+ return;
- /* Invalidate one last time the area, so the final content is painted */
- if (info->invalidation_region &&
- !cairo_region_is_empty (info->invalidation_region))
- gdk_window_invalidate_region (info->window, info->invalidation_region, TRUE);
- else
- gdk_window_invalidate_rect (info->window, NULL, TRUE);
+ priv->animating = FALSE;
- animation_info_free (info);
+ gtk_style_context_disconnect_update (context);
}
-static AnimationInfo *
-animation_info_new (GtkStyleContext *context,
- gpointer region_id,
- guint duration,
- GtkTimelineProgressType progress_type,
- gboolean loop,
- GtkStateType state,
- gboolean target_value,
- GdkWindow *window)
+static void
+gtk_style_context_start_animating (GtkStyleContext *context)
{
- AnimationInfo *info;
-
- info = g_slice_new0 (AnimationInfo);
-
- info->rectangles = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
- info->timeline = _gtk_timeline_new (duration);
- info->window = g_object_ref (window);
- info->state = state;
- info->target_value = target_value;
- info->region_id = region_id;
+ GtkStyleContextPrivate *priv = context->priv;
- _gtk_timeline_set_progress_type (info->timeline, progress_type);
- _gtk_timeline_set_loop (info->timeline, loop);
-
- if (!loop && !target_value)
- {
- _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
- _gtk_timeline_rewind (info->timeline);
- }
-
- g_signal_connect (info->timeline, "frame",
- G_CALLBACK (timeline_frame_cb), context);
- g_signal_connect (info->timeline, "finished",
- G_CALLBACK (timeline_finished_cb), context);
+ if (gtk_style_context_is_animating (context))
+ return;
- _gtk_timeline_start (info->timeline);
+ priv->animating = TRUE;
- return info;
+ gtk_style_context_connect_update (context);
}
-static AnimationInfo *
-animation_info_lookup (GtkStyleContext *context,
- gpointer region_id,
- GtkStateType state)
+static gboolean
+gtk_style_context_should_animate (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
- GSList *l;
+ StyleData *data;
+ gboolean animate;
priv = context->priv;
- for (l = priv->animations; l; l = l->next)
- {
- AnimationInfo *info;
+ if (priv->widget == NULL)
+ return FALSE;
- info = l->data;
+ if (!gtk_widget_get_mapped (priv->widget))
+ return FALSE;
- if (info->state == state &&
- info->region_id == region_id)
- return info;
- }
+ data = style_data_lookup (context);
+ if (!style_data_is_animating (data))
+ return FALSE;
+
+ g_object_get (gtk_widget_get_settings (context->priv->widget),
+ "gtk-enable-animations", &animate,
+ NULL);
+
+ return animate;
+}
- return NULL;
+void
+_gtk_style_context_update_animating (GtkStyleContext *context)
+{
+ if (gtk_style_context_should_animate (context))
+ gtk_style_context_start_animating (context);
+ else
+ gtk_style_context_stop_animating (context);
}
static void
{
GtkStyleContextPrivate *priv;
GtkStyleContext *style_context;
- GSList *l;
style_context = GTK_STYLE_CONTEXT (object);
priv = style_context->priv;
+ gtk_style_context_stop_animating (style_context);
+
+ /* children hold a reference to us */
+ g_assert (priv->children == NULL);
+
+ gtk_style_context_set_parent (style_context, NULL);
+
+ gtk_style_context_set_cascade (style_context, NULL);
+
if (priv->widget_path)
gtk_widget_path_free (priv->widget_path);
g_hash_table_destroy (priv->style_data);
- g_list_foreach (priv->providers, (GFunc) style_provider_data_free, NULL);
- g_list_free (priv->providers);
-
- g_slist_foreach (priv->info_stack, (GFunc) style_info_free, NULL);
- g_slist_free (priv->info_stack);
-
- g_slist_free (priv->animation_regions);
-
- for (l = priv->animations; l; l = l->next)
- animation_info_free ((AnimationInfo *) l->data);
-
- g_slist_free (priv->animations);
-
- if (priv->theming_engine)
- g_object_unref (priv->theming_engine);
+ while (priv->info)
+ priv->info = style_info_pop (priv->info);
G_OBJECT_CLASS (gtk_style_context_parent_class)->finalize (object);
}
const GValue *value,
GParamSpec *pspec)
{
- GtkStyleContextPrivate *priv;
GtkStyleContext *style_context;
style_context = GTK_STYLE_CONTEXT (object);
- priv = style_context->priv;
switch (prop_id)
{
g_value_get_object (value));
break;
case PROP_DIRECTION:
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gtk_style_context_set_direction (style_context,
g_value_get_enum (value));
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ break;
+ case PROP_FRAME_CLOCK:
+ gtk_style_context_set_frame_clock (style_context,
+ g_value_get_object (value));
+ break;
+ case PROP_PARENT:
+ gtk_style_context_set_parent (style_context,
+ g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GValue *value,
GParamSpec *pspec)
{
- GtkStyleContextPrivate *priv;
GtkStyleContext *style_context;
+ GtkStyleContextPrivate *priv;
style_context = GTK_STYLE_CONTEXT (object);
priv = style_context->priv;
g_value_set_object (value, priv->screen);
break;
case PROP_DIRECTION:
- g_value_set_enum (value, priv->direction);
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ g_value_set_enum (value, gtk_style_context_get_direction (style_context));
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ break;
+ case PROP_FRAME_CLOCK:
+ g_value_set_object (value, priv->frame_clock);
+ break;
+ case PROP_PARENT:
+ g_value_set_object (value, priv->parent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
-static GList *
-find_next_candidate (GList *local,
- GList *global,
- gboolean ascending)
-{
- if (local && global)
- {
- GtkStyleProviderData *local_data, *global_data;
-
- local_data = local->data;
- global_data = global->data;
-
- if (local_data->priority < global_data->priority)
- return (ascending) ? local : global;
- else
- return (ascending) ? global : local;
- }
- else if (local)
- return local;
- else if (global)
- return global;
-
- return NULL;
-}
-
-static void
-build_properties (GtkStyleContext *context,
- StyleData *style_data,
- GtkWidgetPath *path)
-{
- GtkStyleContextPrivate *priv;
- GList *elem, *list, *global_list = NULL;
-
- priv = context->priv;
- list = priv->providers;
-
- if (priv->screen)
- global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
-
- while ((elem = find_next_candidate (list, global_list, TRUE)) != NULL)
- {
- GtkStyleProviderData *data;
- GtkStyleProperties *provider_style;
-
- data = elem->data;
-
- if (elem == list)
- list = list->next;
- else
- global_list = global_list->next;
-
- provider_style = gtk_style_provider_get_style (data->provider, path);
-
- if (provider_style)
- {
- gtk_style_properties_merge (style_data->store, provider_style, TRUE);
- g_object_unref (provider_style);
- }
- }
-}
-
-static void
-build_icon_factories (GtkStyleContext *context,
- StyleData *style_data,
- GtkWidgetPath *path)
-{
- GtkStyleContextPrivate *priv;
- GList *elem, *list, *global_list = NULL;
-
- priv = context->priv;
- list = priv->providers_last;
-
- if (priv->screen)
- {
- global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
- global_list = g_list_last (global_list);
- }
-
- while ((elem = find_next_candidate (list, global_list, FALSE)) != NULL)
- {
- GtkIconFactory *factory;
- GtkStyleProviderData *data;
-
- data = elem->data;
-
- if (elem == list)
- list = list->prev;
- else
- global_list = global_list->prev;
-
- factory = gtk_style_provider_get_icon_factory (data->provider, path);
-
- if (factory)
- style_data->icon_factories = g_slist_prepend (style_data->icon_factories, factory);
- }
-}
-
static GtkWidgetPath *
-create_query_path (GtkStyleContext *context)
+create_query_path (GtkStyleContext *context,
+ GtkStyleInfo *info)
{
GtkStyleContextPrivate *priv;
GtkWidgetPath *path;
- GtkStyleInfo *info;
guint i, pos;
priv = context->priv;
- path = gtk_widget_path_copy (priv->widget_path);
+ path = priv->widget ? _gtk_widget_create_path (priv->widget) : gtk_widget_path_copy (priv->widget_path);
pos = gtk_widget_path_length (path) - 1;
- info = priv->info_stack->data;
-
/* Set widget regions */
for (i = 0; i < info->regions->len; i++)
{
return path;
}
-static StyleData *
-style_data_lookup (GtkStyleContext *context)
+static void
+build_properties (GtkStyleContext *context,
+ GtkCssComputedValues *values,
+ GtkStyleInfo *info,
+ const GtkBitmask *relevant_changes)
{
GtkStyleContextPrivate *priv;
- StyleData *data;
+ GtkCssMatcher matcher;
+ GtkWidgetPath *path;
+ GtkCssLookup *lookup;
priv = context->priv;
- /* Current data in use is cached, just return it */
- if (priv->current_data)
- return priv->current_data;
+ path = create_query_path (context, info);
+ lookup = _gtk_css_lookup_new (relevant_changes);
- g_assert (priv->widget_path != NULL);
+ if (_gtk_css_matcher_init (&matcher, path, info->state_flags))
+ _gtk_style_provider_private_lookup (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ &matcher,
+ lookup);
- data = g_hash_table_lookup (priv->style_data, priv->info_stack->data);
+ _gtk_css_lookup_resolve (lookup,
+ GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ values,
+ priv->parent ? style_data_lookup (priv->parent)->store : NULL);
- if (!data)
- {
- GtkWidgetPath *path;
+ _gtk_css_lookup_free (lookup);
+ gtk_widget_path_free (path);
+}
+
+static StyleData *
+style_data_lookup (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+ GtkStyleInfo *info;
+ StyleData *data;
- data = style_data_new ();
- path = create_query_path (context);
+ priv = context->priv;
+ info = priv->info;
- build_properties (context, data, path);
- build_icon_factories (context, data, path);
+ /* Current data in use is cached, just return it */
+ if (info->data)
+ return info->data;
- g_hash_table_insert (priv->style_data,
- style_info_copy (priv->info_stack->data),
- data);
+ g_assert (priv->widget != NULL || priv->widget_path != NULL);
- gtk_widget_path_free (path);
+ data = g_hash_table_lookup (priv->style_data, info);
+ if (data)
+ {
+ style_info_set_data (info, data);
+ return data;
}
- priv->current_data = data;
+ data = style_data_new ();
+ data->store = _gtk_css_computed_values_new ();
+ style_info_set_data (info, data);
+ g_hash_table_insert (priv->style_data,
+ style_info_copy (info),
+ data);
- if (priv->theming_engine)
- g_object_unref (priv->theming_engine);
+ build_properties (context, data->store, info, NULL);
- gtk_style_properties_get (data->store, 0,
- "engine", &priv->theming_engine,
- NULL);
return data;
}
-static void
-style_provider_add (GList **list,
- GtkStyleProvider *provider,
- guint priority)
+static StyleData *
+style_data_lookup_for_state (GtkStyleContext *context,
+ GtkStateFlags state)
{
- GtkStyleProviderData *new_data;
- gboolean added = FALSE;
- GList *l = *list;
-
- new_data = style_provider_data_new (provider, priority);
-
- while (l)
- {
- GtkStyleProviderData *data;
+ StyleData *data;
- data = l->data;
+ if (context->priv->info->state_flags == state)
+ return style_data_lookup (context);
- /* Provider was already attached to the style
- * context, remove in order to add the new data
- */
- if (data->provider == provider)
- {
- GList *link;
+ gtk_style_context_save (context);
+ gtk_style_context_set_state (context, state);
+ data = style_data_lookup (context);
+ gtk_style_context_restore (context);
- link = l;
- l = l->next;
+ return data;
+}
- /* Remove and free link */
- *list = g_list_remove_link (*list, link);
- style_provider_data_free (link->data);
- g_list_free_1 (link);
+static void
+gtk_style_context_set_invalid (GtkStyleContext *context,
+ gboolean invalid)
+{
+ GtkStyleContextPrivate *priv;
+
+ priv = context->priv;
- continue;
- }
+ if (priv->invalid == invalid)
+ return;
- if (!added &&
- data->priority > priority)
- {
- *list = g_list_insert_before (*list, l, new_data);
- added = TRUE;
- }
+ priv->invalid = invalid;
- l = l->next;
+ if (invalid)
+ {
+ if (priv->parent)
+ gtk_style_context_set_invalid (priv->parent, TRUE);
+ else if (GTK_IS_RESIZE_CONTAINER (priv->widget))
+ _gtk_container_queue_restyle (GTK_CONTAINER (priv->widget));
}
-
- if (!added)
- *list = g_list_append (*list, new_data);
}
+/* returns TRUE if someone called gtk_style_context_save() but hasn't
+ * called gtk_style_context_restore() yet.
+ * In those situations we don't invalidate the context when somebody
+ * changes state/regions/classes.
+ */
static gboolean
-style_provider_remove (GList **list,
- GtkStyleProvider *provider)
+gtk_style_context_is_saved (GtkStyleContext *context)
{
- GList *l = *list;
-
- while (l)
- {
- GtkStyleProviderData *data;
-
- data = l->data;
-
- if (data->provider == provider)
- {
- *list = g_list_remove_link (*list, l);
- style_provider_data_free (l->data);
- g_list_free_1 (l);
+ return context->priv->info->next != NULL;
+}
- return TRUE;
- }
+static void
+gtk_style_context_queue_invalidate_internal (GtkStyleContext *context,
+ GtkCssChange change)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+ GtkStyleInfo *info = priv->info;
- l = l->next;
+ if (gtk_style_context_is_saved (context))
+ {
+ style_info_set_data (info, NULL);
+ }
+ else
+ {
+ _gtk_style_context_queue_invalidate (context, change);
+ /* XXX: We need to invalidate siblings here somehow */
}
-
- return FALSE;
}
/**
return g_object_new (GTK_TYPE_STYLE_CONTEXT, NULL);
}
+void
+_gtk_style_context_set_widget (GtkStyleContext *context,
+ GtkWidget *widget)
+{
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
+
+ context->priv->widget = widget;
+
+ _gtk_style_context_update_animating (context);
+
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_SELF);
+}
+
/**
* gtk_style_context_add_provider:
* @context: a #GtkStyleContext
* %GTK_STYLE_PROVIDER_PRIORITY_USER
*
* Adds a style provider to @context, to be used in style construction.
+ * Note that a style provider added by this function only affects
+ * the style of the widget to which @context belongs. If you want
+ * to affect the style of all widgets, use
+ * gtk_style_context_add_provider_for_screen().
+ *
+ * <note><para>If both priorities are the same, A #GtkStyleProvider
+ * added through this function takes precedence over another added
+ * through gtk_style_context_add_provider_for_screen().</para></note>
*
* Since: 3.0
**/
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
priv = context->priv;
- style_provider_add (&priv->providers, provider, priority);
- priv->providers_last = g_list_last (priv->providers);
- gtk_style_context_invalidate (context);
+ if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+ {
+ GtkStyleCascade *new_cascade;
+
+ new_cascade = _gtk_style_cascade_new ();
+ _gtk_style_cascade_set_parent (new_cascade, priv->cascade);
+ _gtk_style_cascade_add_provider (new_cascade, provider, priority);
+ gtk_style_context_set_cascade (context, new_cascade);
+ g_object_unref (new_cascade);
+ }
+ else
+ {
+ _gtk_style_cascade_add_provider (priv->cascade, provider, priority);
+ }
}
/**
priv = context->priv;
- if (style_provider_remove (&priv->providers, provider))
- {
- priv->providers_last = g_list_last (priv->providers);
+ if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+ return;
- gtk_style_context_invalidate (context);
- }
+ _gtk_style_cascade_remove_provider (priv->cascade, provider);
}
/**
* %GTK_STYLE_PROVIDER_PRIORITY_USER
*
* Adds a global style provider to @screen, which will be used
- * in style construction for all #GtkStyleContext<!-- -->s under
- * @screen.
+ * in style construction for all #GtkStyleContexts under @screen.
*
* GTK+ uses this to make styling information from #GtkSettings
* available.
*
+ * <note><para>If both priorities are the same, A #GtkStyleProvider
+ * added through gtk_style_context_add_provider() takes precedence
+ * over another added through this function.</para></note>
+ *
* Since: 3.0
**/
void
GtkStyleProvider *provider,
guint priority)
{
- GList *providers, *list;
+ GtkStyleCascade *cascade;
g_return_if_fail (GDK_IS_SCREEN (screen));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
+ g_return_if_fail (!GTK_IS_SETTINGS (provider) || _gtk_settings_get_screen (GTK_SETTINGS (provider)) == screen);
- if (G_UNLIKELY (!provider_list_quark))
- provider_list_quark = g_quark_from_static_string ("gtk-provider-list-quark");
-
- list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
- style_provider_add (&list, provider, priority);
-
- if (list != providers)
- g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
-
- gtk_style_context_reset_widgets (screen);
+ cascade = _gtk_style_cascade_get_for_screen (screen);
+ _gtk_style_cascade_add_provider (cascade, provider, priority);
}
/**
gtk_style_context_remove_provider_for_screen (GdkScreen *screen,
GtkStyleProvider *provider)
{
- GList *providers, *list;
+ GtkStyleCascade *cascade;
g_return_if_fail (GDK_IS_SCREEN (screen));
g_return_if_fail (GTK_IS_STYLE_PROVIDER (provider));
+ g_return_if_fail (!GTK_IS_SETTINGS (provider));
- if (G_UNLIKELY (!provider_list_quark))
- return;
+ cascade = _gtk_style_cascade_get_for_screen (screen);
+ _gtk_style_cascade_remove_provider (cascade, provider);
+}
+
+/**
+ * gtk_style_context_get_section:
+ * @context: a #GtkStyleContext
+ * @property: style property name
+ *
+ * Queries the location in the CSS where @property was defined for the
+ * current @context. Note that the state to be queried is taken from
+ * gtk_style_context_get_state().
+ *
+ * If the location is not available, %NULL will be returned. The
+ * location might not be available for various reasons, such as the
+ * property being overridden, @property not naming a supported CSS
+ * property or tracking of definitions being disabled for performance
+ * reasons.
+ *
+ * Shorthand CSS properties cannot be queried for a location and will
+ * always return %NULL.
+ *
+ * Returns: %NULL or the section where value was defined
+ **/
+GtkCssSection *
+gtk_style_context_get_section (GtkStyleContext *context,
+ const gchar *property)
+{
+ GtkStyleContextPrivate *priv;
+ GtkStyleProperty *prop;
+ StyleData *data;
+
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+ g_return_val_if_fail (property != NULL, NULL);
- list = providers = g_object_get_qdata (G_OBJECT (screen), provider_list_quark);
+ priv = context->priv;
+ g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
- if (style_provider_remove (&list, provider))
- {
- if (list != providers)
- g_object_set_qdata (G_OBJECT (screen), provider_list_quark, list);
+ prop = _gtk_style_property_lookup (property);
+ if (!GTK_IS_CSS_STYLE_PROPERTY (prop))
+ return NULL;
- gtk_style_context_reset_widgets (screen);
- }
+ data = style_data_lookup (context);
+ return _gtk_css_computed_values_get_section (data->store, _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)));
+}
+
+static GtkCssValue *
+gtk_style_context_query_func (guint id,
+ gpointer values)
+{
+ return _gtk_css_computed_values_get_value (values, id);
}
/**
GValue *value)
{
GtkStyleContextPrivate *priv;
+ GtkStyleProperty *prop;
StyleData *data;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (value != NULL);
priv = context->priv;
+ g_return_if_fail (priv->widget != NULL || priv->widget_path != NULL);
- g_return_if_fail (priv->widget_path != NULL);
+ prop = _gtk_style_property_lookup (property);
+ if (prop == NULL)
+ {
+ g_warning ("Style property \"%s\" is not registered", property);
+ return;
+ }
+ if (_gtk_style_property_get_value_type (prop) == G_TYPE_NONE)
+ {
+ g_warning ("Style property \"%s\" is not gettable", property);
+ return;
+ }
- data = style_data_lookup (context);
- gtk_style_properties_get_property (data->store, property, state, value);
+ data = style_data_lookup_for_state (context, state);
+ _gtk_style_property_query (prop, value, gtk_style_context_query_func, data->store);
}
/**
GtkStateFlags state,
va_list args)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
+ const gchar *property_name;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ property_name = va_arg (args, const gchar *);
- data = style_data_lookup (context);
- gtk_style_properties_get_valist (data->store, state, args);
+ while (property_name)
+ {
+ gchar *error = NULL;
+ GValue value = G_VALUE_INIT;
+
+ gtk_style_context_get_property (context,
+ property_name,
+ state,
+ &value);
+
+ G_VALUE_LCOPY (&value, args, 0, &error);
+ g_value_unset (&value);
+
+ if (error)
+ {
+ g_warning ("Could not get style property \"%s\": %s", property_name, error);
+ g_free (error);
+ break;
+ }
+
+ property_name = va_arg (args, const gchar *);
+ }
}
/**
GtkStateFlags state,
...)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
va_list args;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
-
- data = style_data_lookup (context);
-
va_start (args, state);
- gtk_style_properties_get_valist (data->store, state, args);
+ gtk_style_context_get_valist (context, state, args);
va_end (args);
}
gtk_style_context_set_state (GtkStyleContext *context,
GtkStateFlags flags)
{
- GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
-
+ GtkStateFlags old_flags;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- info = priv->info_stack->data;
- info->state_flags = flags;
+ old_flags = context->priv->info->state_flags;
+ if (old_flags == flags)
+ return;
+
+ context->priv->info->state_flags = flags;
+
+ if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) &&
+ !gtk_style_context_is_saved (context))
+ g_object_notify (G_OBJECT (context), "direction");
+
+ gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_STATE);
}
/**
GtkStateFlags
gtk_style_context_get_state (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
-
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
- priv = context->priv;
- info = priv->info_stack->data;
-
- return info->state_flags;
-}
-
-static gboolean
-context_has_animatable_region (GtkStyleContext *context,
- gpointer region_id)
-{
- GtkStyleContextPrivate *priv;
- GSList *r;
-
- /* NULL region_id means everything
- * rendered through the style context
- */
- if (!region_id)
- return TRUE;
-
- priv = context->priv;
-
- for (r = priv->animation_regions; r; r = r->next)
- {
- if (r->data == region_id)
- return TRUE;
- }
-
- return FALSE;
+ return context->priv->info->state_flags;
}
/**
* Returns: %TRUE if there is a running transition animation for @state.
*
* Since: 3.0
+ *
+ * Deprecated: 3.6: This function always returns %FALSE
**/
gboolean
gtk_style_context_state_is_running (GtkStyleContext *context,
GtkStateType state,
gdouble *progress)
{
- GtkStyleContextPrivate *priv;
- AnimationInfo *info;
- GSList *l;
-
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
- priv = context->priv;
-
- for (l = priv->animations; l; l = l->next)
- {
- info = l->data;
-
- if (info->state == state &&
- context_has_animatable_region (context, info->region_id))
- {
- if (progress)
- *progress = _gtk_timeline_get_progress (info->timeline);
-
- return TRUE;
- }
- }
-
return FALSE;
}
g_return_if_fail (path != NULL);
priv = context->priv;
+ g_return_if_fail (priv->widget == NULL);
if (priv->widget_path)
{
if (path)
priv->widget_path = gtk_widget_path_copy (path);
- gtk_style_context_invalidate (context);
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY);
}
/**
*
* Since: 3.0
**/
-G_CONST_RETURN GtkWidgetPath *
+const GtkWidgetPath *
gtk_style_context_get_path (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv;
priv = context->priv;
- return priv->widget_path;
+ if (priv->widget)
+ return gtk_widget_get_path (priv->widget);
+ else
+ return priv->widget_path;
}
/**
- * gtk_style_context_save:
+ * gtk_style_context_set_parent:
* @context: a #GtkStyleContext
+ * @parent: (allow-none): the new parent or %NULL
*
- * Saves the @context state, so all modifications done through
- * gtk_style_context_add_class(), gtk_style_context_remove_class(),
- * gtk_style_context_add_region(), gtk_style_context_remove_region()
- * or gtk_style_context_set_junction_sides() can be reverted in one
- * go through gtk_style_context_restore().
+ * Sets the parent style context for @context. The parent style
+ * context is used to implement
+ * <ulink url="http://www.w3.org/TR/css3-cascade/#inheritance">inheritance</ulink>
+ * of properties.
*
- * Since: 3.0
+ * If you are using a #GtkStyleContext returned from
+ * gtk_widget_get_style_context(), the parent will be set for you.
+ *
+ * Since: 3.4
**/
void
-gtk_style_context_save (GtkStyleContext *context)
+gtk_style_context_set_parent (GtkStyleContext *context,
+ GtkStyleContext *parent)
{
GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (parent == NULL || GTK_IS_STYLE_CONTEXT (parent));
priv = context->priv;
- g_assert (priv->info_stack != NULL);
+ if (priv->parent == parent)
+ return;
+
+ if (parent)
+ {
+ parent->priv->children = g_slist_prepend (parent->priv->children, context);
+ g_object_ref (parent);
+ if (priv->invalid)
+ gtk_style_context_set_invalid (parent, TRUE);
+ }
+
+ if (priv->parent)
+ {
+ priv->parent->priv->children = g_slist_remove (priv->parent->priv->children, context);
+ g_object_unref (priv->parent);
+ }
+
+ priv->parent = parent;
- info = style_info_copy (priv->info_stack->data);
- priv->info_stack = g_slist_prepend (priv->info_stack, info);
+ g_object_notify (G_OBJECT (context), "parent");
+ _gtk_style_context_queue_invalidate (context, GTK_CSS_CHANGE_ANY_PARENT | GTK_CSS_CHANGE_ANY_SIBLING);
}
/**
- * gtk_style_context_restore:
+ * gtk_style_context_get_parent:
* @context: a #GtkStyleContext
*
- * Restores @context state to a previous stage.
- * See gtk_style_context_save().
+ * Gets the parent context set via gtk_style_context_set_parent().
+ * See that function for details.
*
- * Since: 3.0
+ * Returns: (transfer none): the parent context or %NULL
+ *
+ * Since: 3.4
**/
-void
-gtk_style_context_restore (GtkStyleContext *context)
+GtkStyleContext *
+gtk_style_context_get_parent (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ return context->priv->parent;
+}
+
+/**
+ * gtk_style_context_save:
+ * @context: a #GtkStyleContext
+ *
+ * Saves the @context state, so all modifications done through
+ * gtk_style_context_add_class(), gtk_style_context_remove_class(),
+ * gtk_style_context_add_region(), gtk_style_context_remove_region()
+ * or gtk_style_context_set_junction_sides() can be reverted in one
+ * go through gtk_style_context_restore().
+ *
+ * Since: 3.0
+ **/
+void
+gtk_style_context_save (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
- if (priv->info_stack)
- {
- info = priv->info_stack->data;
- priv->info_stack = g_slist_remove (priv->info_stack, info);
- style_info_free (info);
- }
+ priv->info = style_info_copy (priv->info);
+ /* Need to unset animations here because we can not know what style
+ * class potential transitions came from once we save().
+ */
+ if (priv->info->data && style_data_is_animating (priv->info->data))
+ style_info_set_data (priv->info, NULL);
+}
- if (!priv->info_stack)
+/**
+ * gtk_style_context_restore:
+ * @context: a #GtkStyleContext
+ *
+ * Restores @context state to a previous stage.
+ * See gtk_style_context_save().
+ *
+ * Since: 3.0
+ **/
+void
+gtk_style_context_restore (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+
+ priv = context->priv;
+
+ priv->info = style_info_pop (priv->info);
+
+ if (!priv->info)
{
g_warning ("Unpaired gtk_style_context_restore() call");
/* Create default region */
- info = style_info_new ();
- priv->info_stack = g_slist_prepend (priv->info_stack, info);
+ priv->info = style_info_new ();
}
-
- priv->current_data = NULL;
}
static gboolean
priv = context->priv;
class_quark = g_quark_from_string (class_name);
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (!style_class_find (info->style_classes, class_quark, &position))
{
g_array_insert_val (info->style_classes, position, class_quark);
- /* Unset current data, as it likely changed due to the class change */
- priv->current_data = NULL;
+ gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
}
}
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (style_class_find (info->style_classes, class_quark, &position))
{
g_array_remove_index (info->style_classes, position);
- /* Unset current data, as it likely changed due to the class change */
- priv->current_data = NULL;
+ gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS);
}
}
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (style_class_find (info->style_classes, class_quark, NULL))
return TRUE;
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
for (i = 0; i < info->style_classes->len; i++)
{
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
for (i = 0; i < info->regions->len; i++)
{
return classes;
}
+gboolean
+_gtk_style_context_check_region_name (const gchar *str)
+{
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ if (!g_ascii_islower (str[0]))
+ return FALSE;
+
+ while (*str)
+ {
+ if (*str != '-' &&
+ !g_ascii_islower (*str))
+ return FALSE;
+
+ str++;
+ }
+
+ return TRUE;
+}
+
/**
* gtk_style_context_add_region:
* @context: a #GtkStyleContext
* Pseudo-classes are used for matching @flags, so the two
* following rules:
* <programlisting>
- * GtkTreeView row:nth-child (even) { ... }
- * GtkTreeView row:nth-child (odd) { ... }
+ * GtkTreeView row:nth-child(even) { ... }
+ * GtkTreeView row:nth-child(odd) { ... }
* </programlisting>
*
* would apply to even and odd rows, respectively.
*
+ * <note><para>Region names must only contain lowercase letters
+ * and '-', starting always with a lowercase letter.</para></note>
+ *
* Since: 3.0
**/
void
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (region_name != NULL);
+ g_return_if_fail (_gtk_style_context_check_region_name (region_name));
priv = context->priv;
region_quark = g_quark_from_string (region_name);
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (!region_find (info->regions, region_quark, &position))
{
g_array_insert_val (info->regions, position, region);
- /* Unset current data, as it likely changed due to the region change */
- priv->current_data = NULL;
+ gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
}
}
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (region_find (info->regions, region_quark, &position))
{
g_array_remove_index (info->regions, position);
- /* Unset current data, as it likely changed due to the region change */
- priv->current_data = NULL;
+ gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION);
}
}
priv = context->priv;
- g_assert (priv->info_stack != NULL);
- info = priv->info_stack->data;
+ info = priv->info;
if (region_find (info->regions, region_quark, &position))
{
return 0;
}
+GtkCssValue *
+_gtk_style_context_peek_property (GtkStyleContext *context,
+ guint property_id)
+{
+ StyleData *data = style_data_lookup (context);
+
+ return _gtk_css_computed_values_get_value (data->store, property_id);
+}
+
const GValue *
_gtk_style_context_peek_style_property (GtkStyleContext *context,
GType widget_type,
{
GtkStyleContextPrivate *priv;
PropertyValue *pcache, key = { 0 };
- GList *global_list = NULL;
StyleData *data;
guint i;
priv = context->priv;
- data = style_data_lookup (context);
+
+ data = style_data_lookup_for_state (context, state);
key.widget_type = widget_type;
key.state = state;
g_param_spec_ref (pcache->pspec);
g_value_init (&pcache->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
- if (priv->screen)
+ if (priv->widget || priv->widget_path)
{
- global_list = g_object_get_qdata (G_OBJECT (priv->screen), provider_list_quark);
- global_list = g_list_last (global_list);
- }
+ GtkWidgetPath *widget_path = priv->widget ? _gtk_widget_create_path (priv->widget) : priv->widget_path;
- if (priv->widget_path)
- {
- GList *list, *global, *elem;
+ if (gtk_style_provider_get_style_property (GTK_STYLE_PROVIDER (priv->cascade),
+ widget_path,
+ state, pspec, &pcache->value))
+ {
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- list = priv->providers_last;
- global = global_list;
+ /* Resolve symbolic colors to GdkColor/GdkRGBA */
+ if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
+ {
+ GtkSymbolicColor *color;
+ GdkRGBA rgba;
- while ((elem = find_next_candidate (list, global, FALSE)) != NULL)
- {
- GtkStyleProviderData *provider_data;
+ color = g_value_dup_boxed (&pcache->value);
- provider_data = elem->data;
+ g_value_unset (&pcache->value);
- if (elem == list)
- list = list->prev;
- else
- global = global->prev;
+ if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
+ g_value_init (&pcache->value, GDK_TYPE_RGBA);
+ else
+ g_value_init (&pcache->value, GDK_TYPE_COLOR);
- if (gtk_style_provider_get_style_property (provider_data->provider,
- priv->widget_path, state,
- pspec, &pcache->value))
- {
- /* Resolve symbolic colors to GdkColor/GdkRGBA */
- if (G_VALUE_TYPE (&pcache->value) == GTK_TYPE_SYMBOLIC_COLOR)
+ if (_gtk_style_context_resolve_color (context, _gtk_symbolic_color_get_css_value (color), &rgba, NULL))
{
- GtkSymbolicColor *color;
- GdkRGBA rgba;
+ if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
+ g_value_set_boxed (&pcache->value, &rgba);
+ else
+ {
+ GdkColor rgb;
- color = g_value_get_boxed (&pcache->value);
+ rgb.red = rgba.red * 65535. + 0.5;
+ rgb.green = rgba.green * 65535. + 0.5;
+ rgb.blue = rgba.blue * 65535. + 0.5;
- if (gtk_symbolic_color_resolve (color, data->store, &rgba))
- {
- g_value_unset (&pcache->value);
-
- if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_RGBA)
- {
- g_value_init (&pcache->value, GDK_TYPE_RGBA);
- g_value_set_boxed (&pcache->value, &rgba);
- }
- else
- {
- GdkColor rgb;
-
- rgb.red = rgba.red * 65535. + 0.5;
- rgb.green = rgba.green * 65535. + 0.5;
- rgb.blue = rgba.blue * 65535. + 0.5;
-
- g_value_init (&pcache->value, GDK_TYPE_COLOR);
- g_value_set_boxed (&pcache->value, &rgb);
- }
+ g_value_set_boxed (&pcache->value, &rgb);
}
- else
- g_param_value_set_default (pspec, &pcache->value);
}
+ else
+ g_param_value_set_default (pspec, &pcache->value);
- return &pcache->value;
+ gtk_symbolic_color_unref (color);
}
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ if (priv->widget)
+ gtk_widget_path_free (widget_path);
+
+ return &pcache->value;
}
+
+ if (priv->widget)
+ gtk_widget_path_free (widget_path);
}
/* not supplied by any provider, revert to default */
* gtk_style_context_get_style_property:
* @context: a #GtkStyleContext
* @property_name: the name of the widget style property
- * @value: (out) (transfer full): Return location for the property value
+ * @value: Return location for the property value
*
* Gets the value for a widget style property.
*
priv = context->priv;
- if (!priv->widget_path)
- return;
+ if (priv->widget)
+ {
+ widget_type = G_OBJECT_TYPE (priv->widget);
+ }
+ else
+ {
+ if (!priv->widget_path)
+ return;
- widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
+ widget_type = gtk_widget_path_get_object_type (priv->widget_path);
+
+ if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
+ {
+ g_warning ("%s: can't get style properties for non-widget class `%s'",
+ G_STRLOC,
+ g_type_name (widget_type));
+ return;
+ }
+ }
widget_class = g_type_class_ref (widget_type);
pspec = gtk_widget_class_find_style_property (widget_class, property_name);
GtkStyleContextPrivate *priv;
const gchar *prop_name;
GtkStateFlags state;
+ GType widget_type;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
prop_name = va_arg (args, const gchar *);
priv = context->priv;
- if (!priv->widget_path)
- return;
+ if (priv->widget)
+ {
+ widget_type = G_OBJECT_TYPE (priv->widget);
+ }
+ else
+ {
+ if (!priv->widget_path)
+ return;
+
+ widget_type = gtk_widget_path_get_object_type (priv->widget_path);
+
+ if (!g_type_is_a (widget_type, GTK_TYPE_WIDGET))
+ {
+ g_warning ("%s: can't get style properties for non-widget class `%s'",
+ G_STRLOC,
+ g_type_name (widget_type));
+ return;
+ }
+ }
state = gtk_style_context_get_state (context);
GtkWidgetClass *widget_class;
GParamSpec *pspec;
const GValue *peek_value;
- GType widget_type;
gchar *error;
- widget_type = gtk_widget_path_get_widget_type (priv->widget_path);
-
widget_class = g_type_class_ref (widget_type);
pspec = gtk_widget_class_find_style_property (widget_class, prop_name);
g_type_class_unref (widget_class);
G_STRLOC,
g_type_name (widget_type),
prop_name);
- continue;
+ break;
}
peek_value = _gtk_style_context_peek_style_property (context, widget_type,
G_VALUE_TYPE_NAME (peek_value),
error);
g_free (error);
+ break;
}
prop_name = va_arg (args, const gchar *);
const gchar *stock_id)
{
GtkStyleContextPrivate *priv;
- StyleData *data;
- GSList *list;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
g_return_val_if_fail (stock_id != NULL, NULL);
priv = context->priv;
- g_return_val_if_fail (priv->widget_path != NULL, NULL);
-
- data = style_data_lookup (context);
-
- for (list = data->icon_factories; list; list = list->next)
- {
- GtkIconFactory *factory;
- GtkIconSet *icon_set;
-
- factory = list->data;
- icon_set = gtk_icon_factory_lookup (factory, stock_id);
-
- if (icon_set)
- return icon_set;
- }
+ g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
return gtk_icon_factory_lookup_default (stock_id);
}
if (priv->screen == screen)
return;
+ if (priv->cascade == _gtk_style_cascade_get_for_screen (priv->screen))
+ {
+ gtk_style_context_set_cascade (context, _gtk_style_cascade_get_for_screen (screen));
+ }
+ else
+ {
+ _gtk_style_cascade_set_parent (priv->cascade, _gtk_style_cascade_get_for_screen (screen));
+ }
+
priv->screen = screen;
g_object_notify (G_OBJECT (context), "screen");
-
- gtk_style_context_invalidate (context);
}
/**
*
* Returns the #GdkScreen to which @context is attached.
*
- * Returns: a #GdkScreen.
+ * Returns: (transfer none): a #GdkScreen.
**/
GdkScreen *
gtk_style_context_get_screen (GtkStyleContext *context)
return priv->screen;
}
+/**
+ * gtk_style_context_set_frame_clock:
+ * @context: a #GdkFrameClock
+ * @frame_clock: a #GdkFrameClock
+ *
+ * Attaches @context to the given frame clock.
+ *
+ * The frame clock is used for the timing of animations.
+ *
+ * If you are using a #GtkStyleContext returned from
+ * gtk_widget_get_style_context(), you do not need to
+ * call this yourself.
+ *
+ * Since: 3.8
+ **/
+void
+gtk_style_context_set_frame_clock (GtkStyleContext *context,
+ GdkFrameClock *frame_clock)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (frame_clock == NULL || GDK_IS_FRAME_CLOCK (frame_clock));
+
+ priv = context->priv;
+ if (priv->frame_clock == frame_clock)
+ return;
+
+ if (priv->animating)
+ gtk_style_context_disconnect_update (context);
+
+ if (priv->frame_clock)
+ g_object_unref (priv->frame_clock);
+ priv->frame_clock = frame_clock;
+ if (priv->frame_clock)
+ g_object_ref (priv->frame_clock);
+
+ if (priv->animating)
+ gtk_style_context_connect_update (context);
+
+ g_object_notify (G_OBJECT (context), "paint-clock");
+}
+
+/**
+ * gtk_style_context_get_frame_clock:
+ * @context: a #GtkStyleContext
+ *
+ * Returns the #GdkFrameClock to which @context is attached.
+ *
+ * Returns: (transfer none): a #GdkFrameClock, or %NULL
+ * if @context does not have an attached frame clock.
+ * Since: 3.8
+ **/
+GdkFrameClock *
+gtk_style_context_get_frame_clock (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ priv = context->priv;
+ return priv->frame_clock;
+}
+
/**
* gtk_style_context_set_direction:
* @context: a #GtkStyleContext
* call this yourself.
*
* Since: 3.0
+ *
+ * Deprecated: 3.8: Use gtk_style_context_set_state() with
+ * #GTK_STATE_FLAG_DIR_LTR and #GTK_STATE_FLAG_DIR_RTL
+ * instead.
**/
void
gtk_style_context_set_direction (GtkStyleContext *context,
GtkTextDirection direction)
{
- GtkStyleContextPrivate *priv;
+ GtkStateFlags state;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- priv->direction = direction;
+ state = gtk_style_context_get_state (context);
+ state &= ~(GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL);
- g_object_notify (G_OBJECT (context), "direction");
+ switch (direction)
+ {
+ case GTK_TEXT_DIR_LTR:
+ state |= GTK_STATE_FLAG_DIR_LTR;
+ break;
+
+ case GTK_TEXT_DIR_RTL:
+ state |= GTK_STATE_FLAG_DIR_RTL;
+ break;
+
+ case GTK_TEXT_DIR_NONE:
+ default:
+ break;
+ }
+
+ gtk_style_context_set_state (context, state);
}
/**
* Returns: the widget direction
*
* Since: 3.0
+ *
+ * Deprecated: 3.8: Use gtk_style_context_get_state() and
+ * check for #GTK_STATE_FLAG_DIR_LTR and
+ * #GTK_STATE_FLAG_DIR_RTL instead.
**/
GtkTextDirection
gtk_style_context_get_direction (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
+ GtkStateFlags state;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), GTK_TEXT_DIR_LTR);
- priv = context->priv;
- return priv->direction;
+ state = gtk_style_context_get_state (context);
+
+ if (state & GTK_STATE_FLAG_DIR_LTR)
+ return GTK_TEXT_DIR_LTR;
+ else if (state & GTK_STATE_FLAG_DIR_RTL)
+ return GTK_TEXT_DIR_RTL;
+ else
+ return GTK_TEXT_DIR_NONE;
}
/**
gtk_style_context_set_junction_sides (GtkStyleContext *context,
GtkJunctionSides sides)
{
- GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
-
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- info = priv->info_stack->data;
- info->junction_sides = sides;
+ context->priv->info->junction_sides = sides;
}
/**
GtkJunctionSides
gtk_style_context_get_junction_sides (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
- GtkStyleInfo *info;
-
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0);
- priv = context->priv;
- info = priv->info_stack->data;
- return info->junction_sides;
+ return context->priv->info->junction_sides;
+}
+
+gboolean
+_gtk_style_context_resolve_color (GtkStyleContext *context,
+ GtkCssValue *color,
+ GdkRGBA *result,
+ GtkCssDependencies *dependencies)
+{
+ GtkCssValue *val;
+
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
+ g_return_val_if_fail (color != NULL, FALSE);
+ g_return_val_if_fail (result != NULL, FALSE);
+
+ val = _gtk_css_color_value_resolve (color,
+ GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade),
+ _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_COLOR),
+ GTK_CSS_DEPENDS_ON_COLOR,
+ dependencies);
+ if (val == NULL)
+ return FALSE;
+
+ *result = *_gtk_css_rgba_value_get_rgba (val);
+ _gtk_css_value_unref (val);
+ return TRUE;
}
/**
const gchar *color_name,
GdkRGBA *color)
{
- GtkStyleContextPrivate *priv;
- GtkSymbolicColor *sym_color;
- StyleData *data;
+ GtkCssValue *value;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
g_return_val_if_fail (color_name != NULL, FALSE);
g_return_val_if_fail (color != NULL, FALSE);
- priv = context->priv;
- g_return_val_if_fail (priv->widget_path != NULL, FALSE);
-
- data = style_data_lookup (context);
- sym_color = gtk_style_properties_lookup_color (data->store, color_name);
-
- if (!sym_color)
+ value = _gtk_style_provider_private_get_color (GTK_STYLE_PROVIDER_PRIVATE (context->priv->cascade), color_name);
+ if (value == NULL)
return FALSE;
- return gtk_symbolic_color_resolve (sym_color, data->store, color);
+ return _gtk_style_context_resolve_color (context, value, color, NULL);
}
/**
* is why the style places the transition under the :hover pseudo-class.
*
* Since: 3.0
+ *
+ * Deprecated: 3.6: This function does nothing.
**/
void
gtk_style_context_notify_state_change (GtkStyleContext *context,
GtkStateType state,
gboolean state_value)
{
- GtkStyleContextPrivate *priv;
- GtkAnimationDescription *desc;
- AnimationInfo *info;
- GtkStateFlags flags;
- StyleData *data;
-
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GDK_IS_WINDOW (window));
g_return_if_fail (state > GTK_STATE_NORMAL && state <= GTK_STATE_FOCUSED);
+ g_return_if_fail (context->priv->widget != NULL || context->priv->widget_path != NULL);
+}
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
-
- state_value = (state_value == TRUE);
-
- switch (state)
- {
- case GTK_STATE_ACTIVE:
- flags = GTK_STATE_FLAG_ACTIVE;
- break;
- case GTK_STATE_PRELIGHT:
- flags = GTK_STATE_FLAG_PRELIGHT;
- break;
- case GTK_STATE_SELECTED:
- flags = GTK_STATE_FLAG_SELECTED;
- break;
- case GTK_STATE_INSENSITIVE:
- flags = GTK_STATE_FLAG_INSENSITIVE;
- break;
- case GTK_STATE_INCONSISTENT:
- flags = GTK_STATE_FLAG_INCONSISTENT;
- break;
- case GTK_STATE_FOCUSED:
- flags = GTK_STATE_FLAG_FOCUSED;
- break;
- case GTK_STATE_NORMAL:
- default:
- flags = 0;
- break;
- }
-
- /* Find out if there is any animation description for the given
- * state, it will fallback to the normal state as well if necessary.
- */
- data = style_data_lookup (context);
- gtk_style_properties_get (data->store, flags,
- "transition", &desc,
- NULL);
-
- if (!desc)
- return;
-
- if (_gtk_animation_description_get_duration (desc) == 0)
- {
- _gtk_animation_description_unref (desc);
- return;
- }
-
- info = animation_info_lookup (context, region_id, state);
-
- if (info &&
- info->target_value != state_value)
- {
- /* Target values are the opposite */
- if (!_gtk_timeline_get_loop (info->timeline))
- {
- /* Reverse the animation */
- if (_gtk_timeline_get_direction (info->timeline) == GTK_TIMELINE_DIRECTION_FORWARD)
- _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_BACKWARD);
- else
- _gtk_timeline_set_direction (info->timeline, GTK_TIMELINE_DIRECTION_FORWARD);
-
- info->target_value = state_value;
- }
- else
- {
- /* Take it out of its looping state */
- _gtk_timeline_set_loop (info->timeline, FALSE);
- }
- }
- else if (!info &&
- (!_gtk_animation_description_get_loop (desc) ||
- state_value))
- {
- info = animation_info_new (context, region_id,
- _gtk_animation_description_get_duration (desc),
- _gtk_animation_description_get_progress_type (desc),
- _gtk_animation_description_get_loop (desc),
- state, state_value, window);
-
- priv->animations = g_slist_prepend (priv->animations, info);
- priv->animations_invalidated = TRUE;
- }
+/**
+ * gtk_style_context_cancel_animations:
+ * @context: a #GtkStyleContext
+ * @region_id: (allow-none): animatable region to stop, or %NULL.
+ * See gtk_style_context_push_animatable_region()
+ *
+ * Stops all running animations for @region_id and all animatable
+ * regions underneath.
+ *
+ * A %NULL @region_id will stop all ongoing animations in @context,
+ * when dealing with a #GtkStyleContext obtained through
+ * gtk_widget_get_style_context(), this is normally done for you
+ * in all circumstances you would expect all widget to be stopped,
+ * so this should be only used in complex widgets with different
+ * animatable regions.
+ *
+ * Since: 3.0
+ *
+ * Deprecated: 3.6: This function does nothing.
+ **/
+void
+gtk_style_context_cancel_animations (GtkStyleContext *context,
+ gpointer region_id)
+{
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+}
- _gtk_animation_description_unref (desc);
+/**
+ * gtk_style_context_scroll_animations:
+ * @context: a #GtkStyleContext
+ * @window: a #GdkWindow used previously in
+ * gtk_style_context_notify_state_change()
+ * @dx: Amount to scroll in the X axis
+ * @dy: Amount to scroll in the Y axis
+ *
+ * This function is analogous to gdk_window_scroll(), and
+ * should be called together with it so the invalidation
+ * areas for any ongoing animation are scrolled together
+ * with it.
+ *
+ * Since: 3.0
+ *
+ * Deprecated: 3.6: This function does nothing.
+ **/
+void
+gtk_style_context_scroll_animations (GtkStyleContext *context,
+ GdkWindow *window,
+ gint dx,
+ gint dy)
+{
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (GDK_IS_WINDOW (window));
}
/**
* can uniquely identify rendered elements subject to a state transition.
*
* Since: 3.0
+ *
+ * Deprecated: 3.6: This function does nothing.
**/
void
gtk_style_context_push_animatable_region (GtkStyleContext *context,
gpointer region_id)
{
- GtkStyleContextPrivate *priv;
-
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (region_id != NULL);
-
- priv = context->priv;
- priv->animation_regions = g_slist_prepend (priv->animation_regions, region_id);
}
/**
* See gtk_style_context_push_animatable_region().
*
* Since: 3.0
+ *
+ * Deprecated: 3.6: This function does nothing.
**/
void
gtk_style_context_pop_animatable_region (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
-
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+}
+
+static void
+gtk_style_context_clear_cache (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+ GtkStyleInfo *info;
priv = context->priv;
- priv->animation_regions = g_slist_delete_link (priv->animation_regions,
- priv->animation_regions);
+
+ for (info = priv->info; info; info = info->next)
+ {
+ style_info_set_data (info, NULL);
+ }
+ g_hash_table_remove_all (priv->style_data);
}
-void
-_gtk_style_context_invalidate_animation_areas (GtkStyleContext *context)
+static void
+gtk_style_context_update_cache (GtkStyleContext *context,
+ const GtkBitmask *parent_changes)
{
GtkStyleContextPrivate *priv;
- GSList *l;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (_gtk_bitmask_is_empty (parent_changes))
+ return;
priv = context->priv;
- for (l = priv->animations; l; l = l->next)
+ g_hash_table_iter_init (&iter, priv->style_data);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- AnimationInfo *info;
+ GtkStyleInfo *info = key;
+ StyleData *data = value;
+ GtkBitmask *changes;
- info = l->data;
+ changes = _gtk_css_computed_values_compute_dependencies (data->store, parent_changes);
- /* A NULL invalidation region means it has to be recreated on
- * the next expose event, this happens usually after a widget
- * allocation change, so the next expose after it will update
- * the invalidation region.
- */
- if (info->invalidation_region)
- {
- cairo_region_destroy (info->invalidation_region);
- info->invalidation_region = NULL;
- }
- }
+ if (!_gtk_bitmask_is_empty (changes))
+ build_properties (context, data->store, info, changes);
- priv->animations_invalidated = TRUE;
+ _gtk_bitmask_free (changes);
+ }
}
-void
-_gtk_style_context_coalesce_animation_areas (GtkStyleContext *context,
- gint rel_x,
- gint rel_y)
+static void
+gtk_style_context_do_invalidate (GtkStyleContext *context,
+ const GtkBitmask *changes)
{
GtkStyleContextPrivate *priv;
- GSList *l;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
- if (!priv->animations_invalidated)
+ /* Avoid reentrancy */
+ if (priv->invalidating_context)
return;
- l = priv->animations;
+ priv->invalidating_context = changes;
- while (l)
- {
- AnimationInfo *info;
- GSList *cur;
- guint i;
+ g_signal_emit (context, signals[CHANGED], 0);
- cur = l;
- info = cur->data;
- l = l->next;
+ priv->invalidating_context = NULL;
+}
- if (info->invalidation_region)
- continue;
+static GtkBitmask *
+gtk_style_context_update_animations (GtkStyleContext *context,
+ gint64 timestamp)
+{
+ GtkBitmask *differences;
+ StyleData *style_data;
+
+ style_data = style_data_lookup (context);
- /* There's not much point in keeping the animation running */
- if (info->rectangles->len == 0)
- {
- priv->animations = g_slist_remove (priv->animations, info);
- animation_info_free (info);
- continue;
- }
+ differences = _gtk_css_computed_values_advance (style_data->store,
+ timestamp);
+
+ if (_gtk_css_computed_values_is_static (style_data->store))
+ _gtk_style_context_update_animating (context);
+
+ return differences;
+}
- info->invalidation_region = cairo_region_create ();
+static gboolean
+gtk_style_context_needs_full_revalidate (GtkStyleContext *context,
+ GtkCssChange change)
+{
+ GtkStyleContextPrivate *priv = context->priv;
- for (i = 0; i < info->rectangles->len; i++)
+ /* Try to avoid invalidating if we can */
+ if (change & GTK_STYLE_CONTEXT_RADICAL_CHANGE)
+ {
+ priv->relevant_changes = GTK_CSS_CHANGE_ANY;
+ }
+ else
+ {
+ if (priv->relevant_changes == GTK_CSS_CHANGE_ANY)
{
- cairo_rectangle_int_t *rect;
+ GtkWidgetPath *path;
+ GtkCssMatcher matcher, superset;
- rect = &g_array_index (info->rectangles, cairo_rectangle_int_t, i);
- rect->x += rel_x;
- rect->y += rel_y;
+ path = create_query_path (context, priv->info);
+ if (_gtk_css_matcher_init (&matcher, path, priv->info->state_flags))
+ {
+ _gtk_css_matcher_superset_init (&superset, &matcher, GTK_STYLE_CONTEXT_RADICAL_CHANGE & ~GTK_CSS_CHANGE_SOURCE);
+ priv->relevant_changes = _gtk_style_provider_private_get_change (GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ &superset);
+ }
+ else
+ priv->relevant_changes = 0;
- cairo_region_union_rectangle (info->invalidation_region, rect);
- }
+ priv->relevant_changes &= ~GTK_STYLE_CONTEXT_RADICAL_CHANGE;
- g_array_remove_range (info->rectangles, 0, info->rectangles->len);
+ gtk_widget_path_unref (path);
+ }
}
- priv->animations_invalidated = FALSE;
+ if (priv->relevant_changes & change)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static gboolean
+gtk_style_context_should_create_transitions (GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv;
+ gboolean animate;
+
+ priv = context->priv;
+
+ if (priv->widget == NULL)
+ return FALSE;
+
+ if (!gtk_widget_get_mapped (priv->widget))
+ return FALSE;
+
+ g_object_get (gtk_widget_get_settings (context->priv->widget),
+ "gtk-enable-animations", &animate,
+ NULL);
+
+ return animate;
}
-static void
-store_animation_region (GtkStyleContext *context,
- gdouble x,
- gdouble y,
- gdouble width,
- gdouble height)
+void
+_gtk_style_context_validate (GtkStyleContext *context,
+ gint64 timestamp,
+ GtkCssChange change,
+ const GtkBitmask *parent_changes)
{
GtkStyleContextPrivate *priv;
- GSList *l;
+ GtkStyleInfo *info;
+ StyleData *current;
+ GtkBitmask *changes;
+ GSList *list;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
priv = context->priv;
- if (!priv->animations_invalidated)
+ change |= priv->pending_changes;
+
+ /* If you run your application with
+ * GTK_DEBUG=no-css-cache
+ * every invalidation will purge the cache and completely query
+ * everything anew form the cache. This is slow (in particular
+ * when animating), but useful for figuring out bugs.
+ *
+ * We achieve that by pretending that everything that could have
+ * changed has and so we of course totally need to redo everything.
+ *
+ * Note that this also completely revalidates child widgets all
+ * the time.
+ */
+ if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_NO_CSS_CACHE))
+ change = GTK_CSS_CHANGE_ANY;
+
+ if (!priv->invalid && change == 0 && _gtk_bitmask_is_empty (parent_changes))
return;
- for (l = priv->animations; l; l = l->next)
- {
- AnimationInfo *info;
+ priv->pending_changes = 0;
+ gtk_style_context_set_invalid (context, FALSE);
- info = l->data;
+ info = priv->info;
+ if (info->data)
+ current = style_data_ref (info->data);
+ else
+ current = NULL;
- /* The animation doesn't need updating
- * the invalidation area, bail out.
- */
- if (info->invalidation_region)
- continue;
+ /* Try to avoid invalidating if we can */
+ if (current == NULL ||
+ gtk_style_context_needs_full_revalidate (context, change))
+ {
+ StyleData *data;
- if (context_has_animatable_region (context, info->region_id))
+ if ((priv->relevant_changes & change) & ~GTK_STYLE_CONTEXT_CACHED_CHANGE)
{
- cairo_rectangle_int_t rect;
+ gtk_style_context_clear_cache (context);
+ }
+ else
+ {
+ gtk_style_context_update_cache (context, parent_changes);
+ style_info_set_data (info, NULL);
+ }
- rect.x = (gint) x;
- rect.y = (gint) y;
- rect.width = (gint) width;
- rect.height = (gint) height;
+ data = style_data_lookup (context);
+
+ _gtk_css_computed_values_create_animations (data->store,
+ priv->parent ? style_data_lookup (priv->parent)->store : NULL,
+ timestamp,
+ GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ current && gtk_style_context_should_create_transitions (context) ? current->store : NULL);
+ if (_gtk_css_computed_values_is_static (data->store))
+ change &= ~GTK_CSS_CHANGE_ANIMATE;
+ else
+ change |= GTK_CSS_CHANGE_ANIMATE;
+ _gtk_style_context_update_animating (context);
- g_array_append_val (info->rectangles, rect);
+ if (current)
+ {
+ changes = _gtk_css_computed_values_get_difference (data->store, current->store);
+
+ /* In the case where we keep the cache, we want unanimated values */
+ _gtk_css_computed_values_cancel_animations (current->store);
}
+ else
+ {
+ changes = _gtk_bitmask_new ();
+ changes = _gtk_bitmask_invert_range (changes, 0, _gtk_css_style_property_get_n_properties ());
+ }
+ }
+ else
+ {
+ changes = _gtk_css_computed_values_compute_dependencies (current->store, parent_changes);
+
+ gtk_style_context_update_cache (context, parent_changes);
+ }
+
+ if (current)
+ style_data_unref (current);
+
+ if (change & GTK_CSS_CHANGE_ANIMATE &&
+ gtk_style_context_is_animating (context))
+ {
+ GtkBitmask *animation_changes;
+
+ animation_changes = gtk_style_context_update_animations (context, timestamp);
+ changes = _gtk_bitmask_union (changes, animation_changes);
+ _gtk_bitmask_free (animation_changes);
+ }
+
+ if (change & GTK_CSS_CHANGE_FORCE_INVALIDATE)
+ {
+ GtkBitmask *full = _gtk_bitmask_new ();
+ full = _gtk_bitmask_invert_range (full,
+ 0,
+ _gtk_css_style_property_get_n_properties ());
+ gtk_style_context_do_invalidate (context, full);
+ _gtk_bitmask_free (full);
+ }
+ else if (!_gtk_bitmask_is_empty (changes))
+ {
+ gtk_style_context_do_invalidate (context, changes);
+ }
+
+ change = _gtk_css_change_for_child (change);
+ for (list = priv->children; list; list = list->next)
+ {
+ _gtk_style_context_validate (list->data, timestamp, change, changes);
+ }
+
+ _gtk_bitmask_free (changes);
+}
+
+void
+_gtk_style_context_queue_invalidate (GtkStyleContext *context,
+ GtkCssChange change)
+{
+ GtkStyleContextPrivate *priv;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (change != 0);
+
+ priv = context->priv;
+
+ if (priv->widget != NULL)
+ {
+ priv->pending_changes |= change;
+ gtk_style_context_set_invalid (context, TRUE);
+ }
+ else if (priv->widget_path == NULL)
+ {
+ gtk_style_context_invalidate (context);
}
}
void
gtk_style_context_invalidate (GtkStyleContext *context)
{
- GtkStyleContextPrivate *priv;
+ GtkBitmask *changes;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
+ gtk_style_context_clear_cache (context);
- /* Avoid reentrancy */
- if (priv->invalidating_context)
- return;
-
- priv->invalidating_context = TRUE;
-
- g_hash_table_remove_all (priv->style_data);
- priv->current_data = NULL;
-
- g_signal_emit (context, signals[CHANGED], 0);
+ changes = _gtk_bitmask_new ();
+ changes = _gtk_bitmask_invert_range (changes,
+ 0,
+ _gtk_css_style_property_get_n_properties ());
+ gtk_style_context_do_invalidate (context, changes);
+ _gtk_bitmask_free (changes);
+}
- priv->invalidating_context = FALSE;
+static gboolean
+corner_value_is_right_angle (GtkCssValue *value)
+{
+ return _gtk_css_corner_value_get_x (value, 100) <= 0.0 &&
+ _gtk_css_corner_value_get_y (value, 100) <= 0.0;
}
/**
gtk_style_context_set_background (GtkStyleContext *context,
GdkWindow *window)
{
- GtkStateFlags state;
- cairo_pattern_t *pattern;
- GdkRGBA *color;
+ const GdkRGBA *color;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (GDK_IS_WINDOW (window));
- state = gtk_style_context_get_state (context);
- gtk_style_context_get (context, state,
- "background-image", &pattern,
- NULL);
- if (pattern)
- {
- gdk_window_set_background_pattern (window, pattern);
- cairo_pattern_destroy (pattern);
- return;
- }
+ /* This is a sophisitcated optimization.
+ * If we know the GDK window's background will be opaque, we mark
+ * it as opaque. This is so GDK can do all the optimizations it does
+ * for opaque windows and be fast.
+ * This is mainly used when scrolling.
+ *
+ * We could indeed just set black instead of the color we have.
+ */
+ color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR));
- gtk_style_context_get (context, state,
- "background-color", &color,
- NULL);
- if (color)
+ if (color->alpha >= 1.0 &&
+ corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS)) &&
+ corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS)) &&
+ corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)) &&
+ corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)))
{
gdk_window_set_background_rgba (window, color);
- gdk_rgba_free (color);
+ }
+ else
+ {
+ GdkRGBA transparent = { 0.0, 0.0, 0.0, 0.0 };
+ gdk_window_set_background_rgba (window, &transparent);
}
}
GtkStateFlags state,
GdkRGBA *color)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
- const GValue *value;
GdkRGBA *c;
+ g_return_if_fail (color != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ gtk_style_context_get (context,
+ state,
+ "color", &c,
+ NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "color", state);
- c = g_value_get_boxed (value);
*color = *c;
+ gdk_rgba_free (c);
}
/**
GtkStateFlags state,
GdkRGBA *color)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
- const GValue *value;
GdkRGBA *c;
+ g_return_if_fail (color != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ gtk_style_context_get (context,
+ state,
+ "background-color", &c,
+ NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "background-color", state);
- c = g_value_get_boxed (value);
*color = *c;
+ gdk_rgba_free (c);
}
/**
GtkStateFlags state,
GdkRGBA *color)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
- const GValue *value;
GdkRGBA *c;
+ g_return_if_fail (color != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ gtk_style_context_get (context,
+ state,
+ "border-color", &c,
+ NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "border-color", state);
- c = g_value_get_boxed (value);
*color = *c;
+ gdk_rgba_free (c);
}
/**
* gtk_style_context_get_border:
* @context: a #GtkStyleContext
* @state: state to retrieve the border for
- * @color: (out): return value for the border settings
+ * @border: (out): return value for the border settings
*
* Gets the border for a given state as a #GtkBorder.
+ * See %GTK_STYLE_PROPERTY_BORDER_WIDTH.
*
* Since: 3.0
**/
GtkStateFlags state,
GtkBorder *border)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
- const GValue *value;
- GtkBorder *b;
+ int top, left, bottom, right;
+ g_return_if_fail (border != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ gtk_style_context_get (context,
+ state,
+ "border-top-width", &top,
+ "border-left-width", &left,
+ "border-bottom-width", &bottom,
+ "border-right-width", &right,
+ NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "border-width", state);
- b = g_value_get_boxed (value);
- *border = *b;
+ border->top = top;
+ border->left = left;
+ border->bottom = bottom;
+ border->right = right;
}
/**
* gtk_style_context_get_padding:
* @context: a #GtkStyleContext
* @state: state to retrieve the padding for
- * @color: (out): return value for the padding settings
+ * @padding: (out): return value for the padding settings
*
* Gets the padding for a given state as a #GtkBorder.
+ * See %GTK_STYLE_PROPERTY_PADDING.
*
* Since: 3.0
**/
GtkStateFlags state,
GtkBorder *padding)
{
- GtkStyleContextPrivate *priv;
- StyleData *data;
- const GValue *value;
- GtkBorder *b;
+ int top, left, bottom, right;
+ g_return_if_fail (padding != NULL);
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
- priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ gtk_style_context_get (context,
+ state,
+ "padding-top", &top,
+ "padding-left", &left,
+ "padding-bottom", &bottom,
+ "padding-right", &right,
+ NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "padding", state);
- b = g_value_get_boxed (value);
- *padding = *b;
+ padding->top = top;
+ padding->left = left;
+ padding->bottom = bottom;
+ padding->right = right;
}
/**
* gtk_style_context_get_margin:
* @context: a #GtkStyleContext
* @state: state to retrieve the border for
- * @color: (out): return value for the margin settings
+ * @margin: (out): return value for the margin settings
*
* Gets the margin for a given state as a #GtkBorder.
+ * See %GTK_STYLE_PROPERTY_MARGIN.
*
* Since: 3.0
**/
gtk_style_context_get_margin (GtkStyleContext *context,
GtkStateFlags state,
GtkBorder *margin)
+{
+ int top, left, bottom, right;
+
+ g_return_if_fail (margin != NULL);
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+
+ gtk_style_context_get (context,
+ state,
+ "margin-top", &top,
+ "margin-left", &left,
+ "margin-bottom", &bottom,
+ "margin-right", &right,
+ NULL);
+
+ margin->top = top;
+ margin->left = left;
+ margin->bottom = bottom;
+ margin->right = right;
+}
+
+/**
+ * gtk_style_context_get_font:
+ * @context: a #GtkStyleContext
+ * @state: state to retrieve the font for
+ *
+ * Returns the font description for a given state. The returned
+ * object is const and will remain valid until the
+ * #GtkStyleContext::changed signal happens.
+ *
+ * Returns: (transfer none): the #PangoFontDescription for the given
+ * state. This object is owned by GTK+ and should not be
+ * freed.
+ *
+ * Since: 3.0
+ *
+ * Deprecated: 3.8: Use gtk_style_context_get() for "font" or
+ * subproperties instead.
+ **/
+const PangoFontDescription *
+gtk_style_context_get_font (GtkStyleContext *context,
+ GtkStateFlags state)
{
GtkStyleContextPrivate *priv;
StyleData *data;
- const GValue *value;
- GtkBorder *b;
+ PangoFontDescription *description, *previous;
- g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
priv = context->priv;
- g_return_if_fail (priv->widget_path != NULL);
+ g_return_val_if_fail (priv->widget != NULL || priv->widget_path != NULL, NULL);
- data = style_data_lookup (context);
- value = _gtk_style_properties_peek_property (data->store,
- "margin", state);
- b = g_value_get_boxed (value);
- *margin = *b;
+ data = style_data_lookup_for_state (context, state);
+
+ /* Yuck, fonts are created on-demand but we don't return a ref.
+ * Do bad things to achieve this requirement */
+ gtk_style_context_get (context, state, "font", &description, NULL);
+
+ previous = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
+
+ if (previous)
+ {
+ pango_font_description_merge (previous, description, TRUE);
+ pango_font_description_free (description);
+ description = previous;
+ }
+ else
+ {
+ g_object_set_data_full (G_OBJECT (data->store),
+ "font-cache-for-get_font",
+ description,
+ (GDestroyNotify) pango_font_description_free);
+ }
+
+ return description;
+}
+
+static void
+get_cursor_color (GtkStyleContext *context,
+ gboolean primary,
+ GdkRGBA *color)
+{
+ GdkColor *style_color;
+
+ gtk_style_context_get_style (context,
+ primary ? "cursor-color" : "secondary-cursor-color",
+ &style_color,
+ NULL);
+
+ if (style_color)
+ {
+ color->red = style_color->red / 65535.0;
+ color->green = style_color->green / 65535.0;
+ color->blue = style_color->blue / 65535.0;
+ color->alpha = 1;
+
+ gdk_color_free (style_color);
+ }
+ else
+ {
+ gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, color);
+
+ if (!primary)
+ {
+ GdkRGBA bg;
+
+ gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &bg);
+
+ color->red = (color->red + bg.red) * 0.5;
+ color->green = (color->green + bg.green) * 0.5;
+ color->blue = (color->blue + bg.blue) * 0.5;
+ }
+ }
+}
+
+void
+_gtk_style_context_get_cursor_color (GtkStyleContext *context,
+ GdkRGBA *primary_color,
+ GdkRGBA *secondary_color)
+{
+ if (primary_color)
+ get_cursor_color (context, TRUE, primary_color);
+
+ if (secondary_color)
+ get_cursor_color (context, FALSE, secondary_color);
}
/* Paint methods */
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
- store_animation_region (context, x, y, width, height);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_check (priv->theming_engine, cr,
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_check (engine, cr,
x, y, width, height);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
- store_animation_region (context, x, y, width, height);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_option (priv->theming_engine, cr,
+ cairo_save (cr);
+
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_option (engine, cr,
x, y, width, height);
+
+ cairo_restore (cr);
}
/**
* @context: a #GtkStyleContext
* @cr: a #cairo_t
* @angle: arrow angle from 0 to 2 * %G_PI, being 0 the arrow pointing to the north
- * @x: Center X for the render area
- * @y: Center Y for the render area
+ * @x: X origin of the render area
+ * @y: Y origin of the render area
* @size: square side for render area
*
* Renders an arrow pointing to @angle.
gdouble y,
gdouble size)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (size > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (size <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- store_animation_region (context, x, y, size, size);
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_arrow (priv->theming_engine, cr,
+ gtk_style_context_save (context);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW);
+
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_arrow (engine, cr,
angle, x, y, size);
+
+ gtk_style_context_restore (context);
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- store_animation_region (context, x, y, width, height);
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_background (priv->theming_engine, cr, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_background (engine, cr, x, y, width, height);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
- store_animation_region (context, x, y, width, height);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_frame (priv->theming_engine, cr, x, y, width, height);
+ cairo_save (cr);
+
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_frame (engine, cr, x, y, width, height);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- store_animation_region (context, x, y, width, height);
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_expander (priv->theming_engine, cr, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_expander (engine, cr, x, y, width, height);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
- store_animation_region (context, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_focus (engine, cr, x, y, width, height);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_focus (priv->theming_engine, cr, x, y, width, height);
+ cairo_restore (cr);
}
/**
gdouble y,
PangoLayout *layout)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
PangoRectangle extents;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (PANGO_IS_LAYOUT (layout));
g_return_if_fail (cr != NULL);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
pango_layout_get_extents (layout, &extents, NULL);
- store_animation_region (context,
- x + extents.x,
- y + extents.y,
- extents.width,
- extents.height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_layout (engine, cr, x, y, layout);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_layout (priv->theming_engine, cr, x, y, layout);
+ cairo_restore (cr);
}
/**
gdouble x1,
gdouble y1)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_line (priv->theming_engine, cr, x0, y0, x1, y1);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_line (engine, cr, x0, y0, x1, y1);
+
+ cairo_restore (cr);
}
/**
gdouble height,
GtkOrientation orientation)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
- store_animation_region (context, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_slider (engine, cr, x, y, width, height, orientation);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_slider (priv->theming_engine, cr, x, y, width, height, orientation);
+ cairo_restore (cr);
}
/**
gdouble xy0_gap,
gdouble xy1_gap)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- g_return_if_fail (xy0_gap < xy1_gap);
+ g_return_if_fail (xy0_gap <= xy1_gap);
g_return_if_fail (xy0_gap >= 0);
+ if (width <= 0 || height <= 0)
+ return;
+
if (gap_side == GTK_POS_LEFT ||
gap_side == GTK_POS_RIGHT)
g_return_if_fail (xy1_gap <= height);
else
g_return_if_fail (xy1_gap <= width);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- store_animation_region (context, x, y, width, height);
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_frame_gap (priv->theming_engine, cr,
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_frame_gap (engine, cr,
x, y, width, height, gap_side,
xy0_gap, xy1_gap);
+
+ cairo_restore (cr);
}
/**
gdouble height,
GtkPositionType gap_side)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
- store_animation_region (context, x, y, width, height);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_extension (priv->theming_engine, cr, x, y, width, height, gap_side);
+ cairo_save (cr);
+
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_extension (engine, cr, x, y, width, height, gap_side);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
- store_animation_region (context, x, y, width, height);
+ cairo_save (cr);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_handle (priv->theming_engine, cr, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_handle (engine, cr, x, y, width, height);
+
+ cairo_restore (cr);
}
/**
gdouble width,
gdouble height)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (cr != NULL);
- g_return_if_fail (width > 0);
- g_return_if_fail (height > 0);
- priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
+ if (width <= 0 || height <= 0)
+ return;
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
- store_animation_region (context, x, y, width, height);
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_activity (engine, cr, x, y, width, height);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- engine_class->render_activity (priv->theming_engine, cr, x, y, width, height);
+ cairo_restore (cr);
}
/**
const GtkIconSource *source,
GtkIconSize size)
{
- GtkStyleContextPrivate *priv;
GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
- g_return_val_if_fail (size == -1 || size <= GTK_ICON_SIZE_DIALOG, NULL);
+ g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
g_return_val_if_fail (source != NULL, NULL);
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ _gtk_theming_engine_set_context (engine, context);
+ return engine_class->render_icon_pixbuf (engine, source, size);
+}
+
+/**
+ * gtk_render_icon:
+ * @context: a #GtkStyleContext
+ * @cr: a #cairo_t
+ * @pixbuf: a #GdkPixbuf containing the icon to draw
+ * @x: X position for the @pixbuf
+ * @y: Y position for the @pixbuf
+ *
+ * Renders the icon in @pixbuf at the specified @x and @y coordinates.
+ *
+ * Since: 3.2
+ **/
+void
+gtk_render_icon (GtkStyleContext *context,
+ cairo_t *cr,
+ GdkPixbuf *pixbuf,
+ gdouble x,
+ gdouble y)
+{
+ GtkThemingEngineClass *engine_class;
+ GtkThemingEngine *engine;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (cr != NULL);
+
+ engine = _gtk_css_engine_value_get_engine (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_ENGINE));
+ engine_class = GTK_THEMING_ENGINE_GET_CLASS (engine);
+
+ cairo_save (cr);
+
+ _gtk_theming_engine_set_context (engine, context);
+ engine_class->render_icon (engine, cr, pixbuf, x, y);
+
+ cairo_restore (cr);
+}
+
+static void
+draw_insertion_cursor (GtkStyleContext *context,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble height,
+ gboolean is_primary,
+ PangoDirection direction,
+ gboolean draw_arrow)
+
+{
+ GdkRGBA primary_color;
+ GdkRGBA secondary_color;
+ gfloat cursor_aspect_ratio;
+ gint stem_width;
+ gint offset;
+
+ cairo_save (cr);
+
+ _gtk_style_context_get_cursor_color (context, &primary_color, &secondary_color);
+ gdk_cairo_set_source_rgba (cr, is_primary ? &primary_color : &secondary_color);
+
+ /* When changing the shape or size of the cursor here,
+ * propagate the changes to gtktextview.c:text_window_invalidate_cursors().
+ */
+
+ gtk_style_context_get_style (context,
+ "cursor-aspect-ratio", &cursor_aspect_ratio,
+ NULL);
+
+ stem_width = height * cursor_aspect_ratio + 1;
+
+ /* put (stem_width % 2) on the proper side of the cursor */
+ if (direction == PANGO_DIRECTION_LTR)
+ offset = stem_width / 2;
+ else
+ offset = stem_width - stem_width / 2;
+
+ cairo_rectangle (cr, x - offset, y, stem_width, height);
+ cairo_fill (cr);
+
+ if (draw_arrow)
+ {
+ gint arrow_width;
+ gint ax, ay;
+
+ arrow_width = stem_width + 1;
+
+ if (direction == PANGO_DIRECTION_RTL)
+ {
+ ax = x - offset - 1;
+ ay = y + height - arrow_width * 2 - arrow_width + 1;
+
+ cairo_move_to (cr, ax, ay + 1);
+ cairo_line_to (cr, ax - arrow_width, ay + arrow_width);
+ cairo_line_to (cr, ax, ay + 2 * arrow_width);
+ cairo_fill (cr);
+ }
+ else if (direction == PANGO_DIRECTION_LTR)
+ {
+ ax = x + stem_width - offset;
+ ay = y + height - arrow_width * 2 - arrow_width + 1;
+
+ cairo_move_to (cr, ax, ay + 1);
+ cairo_line_to (cr, ax + arrow_width, ay + arrow_width);
+ cairo_line_to (cr, ax, ay + 2 * arrow_width);
+ cairo_fill (cr);
+ }
+ else
+ g_assert_not_reached();
+ }
+
+ cairo_restore (cr);
+}
+
+/**
+ * gtk_render_insertion_cursor:
+ * @context: a #GtkStyleContext
+ * @cr: a #cairo_t
+ * @x: X origin
+ * @y: Y origin
+ * @layout: the #PangoLayout of the text
+ * @index: the index in the #PangoLayout
+ * @direction: the #PangoDirection of the text
+ *
+ * Draws a text caret on @cr at the specified index of @layout.
+ *
+ * Since: 3.4
+ **/
+void
+gtk_render_insertion_cursor (GtkStyleContext *context,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ PangoLayout *layout,
+ int index,
+ PangoDirection direction)
+{
+ GtkStyleContextPrivate *priv;
+ gboolean split_cursor;
+ PangoRectangle strong_pos, weak_pos;
+ PangoRectangle *cursor1, *cursor2;
+ PangoDirection keymap_direction;
+ PangoDirection direction2;
+
+ g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (PANGO_IS_LAYOUT (layout));
+ g_return_if_fail (index >= 0);
+
priv = context->priv;
- engine_class = GTK_THEMING_ENGINE_GET_CLASS (priv->theming_engine);
- _gtk_theming_engine_set_context (priv->theming_engine, context);
- return engine_class->render_icon_pixbuf (priv->theming_engine, source, size);
+ g_object_get (gtk_settings_get_for_screen (priv->screen),
+ "gtk-split-cursor", &split_cursor,
+ NULL);
+
+ keymap_direction = gdk_keymap_get_direction (gdk_keymap_get_for_display (gdk_screen_get_display (priv->screen)));
+
+ pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
+
+ direction2 = PANGO_DIRECTION_NEUTRAL;
+
+ if (split_cursor)
+ {
+ cursor1 = &strong_pos;
+
+ if (strong_pos.x != weak_pos.x || strong_pos.y != weak_pos.y)
+ {
+ direction2 = (direction == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+ cursor2 = &weak_pos;
+ }
+ }
+ else
+ {
+ if (keymap_direction == direction)
+ cursor1 = &strong_pos;
+ else
+ cursor1 = &weak_pos;
+ }
+
+ draw_insertion_cursor (context,
+ cr,
+ x + PANGO_PIXELS (cursor1->x),
+ y + PANGO_PIXELS (cursor1->y),
+ PANGO_PIXELS (cursor1->height),
+ TRUE,
+ direction,
+ direction2 != PANGO_DIRECTION_NEUTRAL);
+
+ if (direction2 != PANGO_DIRECTION_NEUTRAL)
+ {
+ draw_insertion_cursor (context,
+ cr,
+ x + PANGO_PIXELS (cursor2->x),
+ y + PANGO_PIXELS (cursor2->y),
+ PANGO_PIXELS (cursor2->height),
+ FALSE,
+ direction2,
+ TRUE);
+ }
+}
+
+/**
+ * gtk_draw_insertion_cursor:
+ * @widget: a #GtkWidget
+ * @cr: cairo context to draw to
+ * @location: location where to draw the cursor (@location->width is ignored)
+ * @is_primary: if the cursor should be the primary cursor color.
+ * @direction: whether the cursor is left-to-right or
+ * right-to-left. Should never be #GTK_TEXT_DIR_NONE
+ * @draw_arrow: %TRUE to draw a directional arrow on the
+ * cursor. Should be %FALSE unless the cursor is split.
+ *
+ * Draws a text caret on @cr at @location. This is not a style function
+ * but merely a convenience function for drawing the standard cursor shape.
+ *
+ * Since: 3.0
+ * Deprecated: 3.4: Use gtk_render_insertion_cursor() instead.
+ */
+void
+gtk_draw_insertion_cursor (GtkWidget *widget,
+ cairo_t *cr,
+ const GdkRectangle *location,
+ gboolean is_primary,
+ GtkTextDirection direction,
+ gboolean draw_arrow)
+{
+ GtkStyleContext *context;
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (location != NULL);
+ g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
+
+ context = gtk_widget_get_style_context (widget);
+
+ draw_insertion_cursor (context, cr,
+ location->x, location->y, location->height,
+ is_primary,
+ (direction == GTK_TEXT_DIR_RTL) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR,
+ draw_arrow);
+}
+
+/**
+ * _gtk_style_context_get_changes:
+ * @context: the context to query
+ *
+ * Queries the context for the changes for the currently executing
+ * GtkStyleContext::invalidate signal. If no signal is currently
+ * emitted, this function returns %NULL.
+ *
+ * FIXME 4.0: Make this part of the signal.
+ *
+ * Returns: %NULL or the currently invalidating changes
+ **/
+const GtkBitmask *
+_gtk_style_context_get_changes (GtkStyleContext *context)
+{
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ return context->priv->invalidating_context;
+}
+
+static AtkAttributeSet *
+add_attribute (AtkAttributeSet *attributes,
+ AtkTextAttribute attr,
+ const gchar *value)
+{
+ AtkAttribute *at;
+
+ at = g_new (AtkAttribute, 1);
+ at->name = g_strdup (atk_text_attribute_get_name (attr));
+ at->value = g_strdup (value);
+
+ return g_slist_prepend (attributes, at);
+}
+
+/*
+ * _gtk_style_context_get_attributes:
+ * @attributes: a #AtkAttributeSet to add attributes to
+ * @context: the #GtkStyleContext to get attributes from
+ * @flags: the state to use with @context
+ *
+ * Adds the foreground and background color from @context to
+ * @attributes, after translating them to ATK attributes.
+ *
+ * This is a convenience function that can be used in
+ * implementing the #AtkText interface in widgets.
+ *
+ * Returns: the modified #AtkAttributeSet
+ */
+AtkAttributeSet *
+_gtk_style_context_get_attributes (AtkAttributeSet *attributes,
+ GtkStyleContext *context,
+ GtkStateFlags flags)
+{
+ GdkRGBA color;
+ gchar *value;
+
+ gtk_style_context_get_background_color (context, flags, &color);
+ value = g_strdup_printf ("%u,%u,%u",
+ (guint) ceil (color.red * 65536 - color.red),
+ (guint) ceil (color.green * 65536 - color.green),
+ (guint) ceil (color.blue * 65536 - color.blue));
+ attributes = add_attribute (attributes, ATK_TEXT_ATTR_BG_COLOR, value);
+ g_free (value);
+
+ gtk_style_context_get_color (context, flags, &color);
+ value = g_strdup_printf ("%u,%u,%u",
+ (guint) ceil (color.red * 65536 - color.red),
+ (guint) ceil (color.green * 65536 - color.green),
+ (guint) ceil (color.blue * 65536 - color.blue));
+ attributes = add_attribute (attributes, ATK_TEXT_ATTR_FG_COLOR, value);
+ g_free (value);
+
+ return attributes;
+}
+
+cairo_pattern_t *
+gtk_gradient_resolve_for_context (GtkGradient *gradient,
+ GtkStyleContext *context)
+{
+ GtkStyleContextPrivate *priv = context->priv;
+ GtkCssDependencies ignored = 0;
+
+ g_return_val_if_fail (gradient != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
+
+ return _gtk_gradient_resolve_full (gradient,
+ GTK_STYLE_PROVIDER_PRIVATE (priv->cascade),
+ style_data_lookup (context)->store,
+ priv->parent ? style_data_lookup (priv->parent)->store : NULL,
+ &ignored);
}
+