X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcolorswatch.c;h=c6081d7907f1adadc9339f088297f497801fbf5b;hb=1074aa0c49f647ed4b2a969618051c59da5aad01;hp=0bd1d64a4b583d7c11458cc5ecb5400dc49b93e8;hpb=92618eb8e26703f9bbe1a0ca0639cb3e6213094e;p=~andy%2Fgtk diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c index 0bd1d64a4..c6081d790 100644 --- a/gtk/gtkcolorswatch.c +++ b/gtk/gtkcolorswatch.c @@ -12,15 +12,14 @@ * 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 . */ #include "config.h" #include "gtkcolorswatchprivate.h" +#include "gtkcolorchooserprivate.h" #include "gtkroundedboxprivate.h" #include "gtkthemingbackgroundprivate.h" #include "gtkdnd.h" @@ -29,8 +28,10 @@ #include "gtkmenu.h" #include "gtkmenuitem.h" #include "gtkmenushell.h" +#include "gtkpressandholdprivate.h" #include "gtkprivate.h" #include "gtkintl.h" +#include "a11y/gtkcolorswatchaccessibleprivate.h" struct _GtkColorSwatchPrivate @@ -41,13 +42,18 @@ struct _GtkColorSwatchPrivate guint has_color : 1; guint contains_pointer : 1; guint use_alpha : 1; + guint selectable : 1; + + GdkWindow *event_window; + + GtkPressAndHold *press_and_hold; }; enum { PROP_ZERO, PROP_RGBA, - PROP_SELECTED + PROP_SELECTABLE }; enum @@ -59,7 +65,7 @@ enum static guint signals[LAST_SIGNAL]; -G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_DRAWING_AREA) +G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET) static void gtk_color_swatch_init (GtkColorSwatch *swatch) @@ -69,36 +75,14 @@ gtk_color_swatch_init (GtkColorSwatch *swatch) GtkColorSwatchPrivate); gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE); - gtk_widget_set_events (GTK_WIDGET (swatch), GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_EXPOSURE_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_set_has_window (GTK_WIDGET (swatch), FALSE); + swatch->priv->use_alpha = TRUE; + swatch->priv->selectable = TRUE; } #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) - -static cairo_pattern_t * -get_checkered_pattern (void) -{ - /* need to respect pixman's stride being a multiple of 4 */ - static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00, - 0x00, 0xFF, 0x00, 0x00 }; - static cairo_surface_t *checkered = NULL; - cairo_pattern_t *pattern; - - if (checkered == NULL) - checkered = cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_A8, - 2, 2, 4); - - pattern = cairo_pattern_create_for_surface (checkered); - cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); - cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); - - return pattern; -} +#define ACTIVE_BADGE_RADIUS 10 static gboolean swatch_draw (GtkWidget *widget, @@ -136,13 +120,13 @@ swatch_draw (GtkWidget *widget, { cairo_save (cr); - _gtk_rounded_box_path (&background.clip_box, cr); + _gtk_rounded_box_path (&background.padding_box, cr); cairo_clip_preserve (cr); cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); cairo_fill_preserve (cr); - pattern = get_checkered_pattern (); + pattern = _gtk_color_chooser_get_checkered_pattern (); cairo_matrix_init_scale (&matrix, 0.125, 0.125); cairo_pattern_set_matrix (pattern, &matrix); @@ -162,6 +146,8 @@ swatch_draw (GtkWidget *widget, _gtk_theming_background_render (&background, cr); } + else + _gtk_theming_background_render (&background, cr); gtk_render_frame (context, cr, 0, 0, width, height); @@ -173,9 +159,9 @@ swatch_draw (GtkWidget *widget, cairo_set_source_rgba (cr, 1., 1., 1., 0.4); else cairo_set_source_rgba (cr, 0., 0., 0., 0.4); - _gtk_rounded_box_shrink (&background.clip_box, 3, 3, 3, 3); - _gtk_rounded_box_path (&background.clip_box, cr); - cairo_stroke (cr); + _gtk_rounded_box_shrink (&background.padding_box, 3, 3, 3, 3); + _gtk_rounded_box_path (&background.padding_box, cr); + cairo_stroke (cr); } if (swatch->priv->icon) @@ -191,28 +177,40 @@ swatch_draw (GtkWidget *widget, GIcon *gicon; gtk_style_context_add_class (context, "color-active-badge"); - gtk_style_context_get_background_color (context, state, &bg); - gtk_style_context_get_border_color (context, state, &border); - gtk_style_context_get_border (context, state, &border_width); - - cairo_new_sub_path (cr); - cairo_arc (cr, width / 2, height / 2, 10, 0, 2 * G_PI); - cairo_close_path (cr); - gdk_cairo_set_source_rgba (cr, &bg); - cairo_fill_preserve (cr); - - gdk_cairo_set_source_rgba (cr, &border); - cairo_set_line_width (cr, border_width.left); - cairo_stroke (cr); - - gicon = g_themed_icon_new ("object-select-symbolic"); - /* fallback for themes that don't have object-select-symbolic */ - g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply"); - - icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16, - GTK_ICON_LOOKUP_GENERIC_FALLBACK - | GTK_ICON_LOOKUP_USE_BUILTIN); - g_object_unref (gicon); + _gtk_theming_background_init_from_context (&background, context, + (width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2, + 2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS, + GTK_JUNCTION_NONE); + + if (_gtk_theming_background_has_background_image (&background)) + { + _gtk_theming_background_render (&background, cr); + } + else + { + gtk_style_context_get_background_color (context, state, &bg); + gtk_style_context_get_border_color (context, state, &border); + gtk_style_context_get_border (context, state, &border_width); + + cairo_new_sub_path (cr); + cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI); + cairo_close_path (cr); + gdk_cairo_set_source_rgba (cr, &bg); + cairo_fill_preserve (cr); + + gdk_cairo_set_source_rgba (cr, &border); + cairo_set_line_width (cr, border_width.left); + cairo_stroke (cr); + + gicon = g_themed_icon_new ("object-select-symbolic"); + /* fallback for themes that don't have object-select-symbolic */ + g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply"); + + icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16, + GTK_ICON_LOOKUP_GENERIC_FALLBACK + | GTK_ICON_LOOKUP_USE_BUILTIN); + g_object_unref (gicon); + } } if (icon_info != NULL) @@ -230,7 +228,7 @@ swatch_draw (GtkWidget *widget, g_object_unref (pixbuf); } - gtk_icon_info_free (icon_info); + g_object_unref (icon_info); } cairo_restore (cr); @@ -357,7 +355,9 @@ swatch_key_press (GtkWidget *widget, event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_KP_Space) { - if (swatch->priv->has_color && (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0) + if (swatch->priv->has_color && + swatch->priv->selectable && + (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0) gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE); else g_signal_emit (swatch, signals[ACTIVATE], 0); @@ -376,6 +376,8 @@ swatch_enter_notify (GtkWidget *widget, { GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); swatch->priv->contains_pointer = TRUE; + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE); + return FALSE; } @@ -385,6 +387,8 @@ swatch_leave_notify (GtkWidget *widget, { GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); swatch->priv->contains_pointer = FALSE; + gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT); + return FALSE; } @@ -483,30 +487,179 @@ swatch_button_press (GtkWidget *widget, return FALSE; } +static gboolean +swatch_primary_action (GtkColorSwatch *swatch) +{ + GtkWidget *widget = (GtkWidget *)swatch; + GtkStateFlags flags; + + flags = gtk_widget_get_state_flags (widget); + if (!swatch->priv->has_color) + { + g_signal_emit (swatch, signals[ACTIVATE], 0); + return TRUE; + } + else if (swatch->priv->selectable && + (flags & GTK_STATE_FLAG_SELECTED) == 0) + { + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE); + return TRUE; + } + + return FALSE; +} + static gboolean swatch_button_release (GtkWidget *widget, GdkEventButton *event) { GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); - GtkStateFlags flags; if (event->button == GDK_BUTTON_PRIMARY && swatch->priv->contains_pointer) + return swatch_primary_action (swatch); + + return FALSE; +} + +static void +hold_action (GtkPressAndHold *pah, + gint x, + gint y, + GtkColorSwatch *swatch) +{ + emit_customize (swatch); +} + +static void +tap_action (GtkPressAndHold *pah, + gint x, + gint y, + GtkColorSwatch *swatch) +{ + swatch_primary_action (swatch); +} + +static gboolean +swatch_touch (GtkWidget *widget, + GdkEventTouch *event) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + + if (!swatch->priv->press_and_hold) { - flags = gtk_widget_get_state_flags (widget); - if (!swatch->priv->has_color) - { - g_signal_emit (swatch, signals[ACTIVATE], 0); - return TRUE; - } - else if ((flags & GTK_STATE_FLAG_SELECTED) == 0) - { - gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE); - return TRUE; - } + gint drag_threshold; + + g_object_get (gtk_widget_get_settings (widget), + "gtk-dnd-drag-threshold", &drag_threshold, + NULL); + + swatch->priv->press_and_hold = gtk_press_and_hold_new (); + + g_object_set (swatch->priv->press_and_hold, + "drag-threshold", drag_threshold, + "hold-time", 1000, + NULL); + + g_signal_connect (swatch->priv->press_and_hold, "hold", + G_CALLBACK (hold_action), swatch); + g_signal_connect (swatch->priv->press_and_hold, "tap", + G_CALLBACK (tap_action), swatch); } - return FALSE; + gtk_press_and_hold_process_event (swatch->priv->press_and_hold, (GdkEvent *)event); + + return TRUE; +} + +static void +swatch_map (GtkWidget *widget) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + + GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->map (widget); + + if (swatch->priv->event_window) + gdk_window_show (swatch->priv->event_window); +} + +static void +swatch_unmap (GtkWidget *widget) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + + if (swatch->priv->event_window) + gdk_window_hide (swatch->priv->event_window); + + GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unmap (widget); +} + +static void +swatch_realize (GtkWidget *widget) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + GtkAllocation allocation; + GdkWindow *window; + GdkWindowAttr attributes; + gint attributes_mask; + + gtk_widget_get_allocation (widget, &allocation); + gtk_widget_set_realized (widget, TRUE); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.wclass = GDK_INPUT_ONLY; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_TOUCH_MASK; + + attributes_mask = GDK_WA_X | GDK_WA_Y; + + window = gtk_widget_get_parent_window (widget); + gtk_widget_set_window (widget, window); + g_object_ref (window); + + swatch->priv->event_window = + gdk_window_new (window, + &attributes, attributes_mask); + gtk_widget_register_window (widget, swatch->priv->event_window); +} + +static void +swatch_unrealize (GtkWidget *widget) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + + if (swatch->priv->event_window) + { + gtk_widget_unregister_window (widget, swatch->priv->event_window); + gdk_window_destroy (swatch->priv->event_window); + swatch->priv->event_window = NULL; + } + + GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->unrealize (widget); +} + +static void +swatch_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget); + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (swatch->priv->event_window, + allocation->x, + allocation->y, + allocation->width, + allocation->height); } static gboolean @@ -533,6 +686,9 @@ swatch_get_property (GObject *object, gtk_color_swatch_get_rgba (swatch, &color); g_value_set_boxed (value, &color); break; + case PROP_SELECTABLE: + g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -552,6 +708,9 @@ swatch_set_property (GObject *object, case PROP_RGBA: gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value)); break; + case PROP_SELECTABLE: + gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -564,6 +723,7 @@ swatch_finalize (GObject *object) GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object); g_free (swatch->priv->icon); + g_clear_object (&swatch->priv->press_and_hold); G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object); } @@ -590,6 +750,12 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class) widget_class->button_release_event = swatch_button_release; widget_class->enter_notify_event = swatch_enter_notify; widget_class->leave_notify_event = swatch_leave_notify; + widget_class->realize = swatch_realize; + widget_class->unrealize = swatch_unrealize; + widget_class->map = swatch_map; + widget_class->unmap = swatch_unmap; + widget_class->size_allocate = swatch_size_allocate; + widget_class->touch_event = swatch_touch; signals[ACTIVATE] = g_signal_new ("activate", @@ -608,8 +774,13 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class) g_object_class_install_property (object_class, PROP_RGBA, g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"), GDK_TYPE_RGBA, GTK_PARAM_READWRITE)); + g_object_class_install_property (object_class, PROP_SELECTABLE, + g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the swatch is selectable"), + TRUE, GTK_PARAM_READWRITE)); g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE); } /* Public API {{{1 */ @@ -714,4 +885,21 @@ gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch, gtk_widget_queue_draw (GTK_WIDGET (swatch)); } +void +gtk_color_swatch_set_selectable (GtkColorSwatch *swatch, + gboolean selectable) +{ + if (selectable == swatch->priv->selectable) + return; + + swatch->priv->selectable = selectable; + g_object_notify (G_OBJECT (swatch), "selectable"); +} + +gboolean +gtk_color_swatch_get_selectable (GtkColorSwatch *swatch) +{ + return swatch->priv->selectable; +} + /* vim:set foldmethod=marker: */