static gboolean xfce_arrow_button_draw (GtkWidget *widget, cairo_t *cr) { gint x, y, w; GtkStyleContext *context; xfce_arrow_button_thickness thickness; GtkAllocation allocation; if (G_LIKELY (gtk_widget_is_drawable (widget))) { context = gtk_widget_get_style_context (widget); xfce_arrow_button_get_thickness (context, &thickness); gtk_widget_get_allocation (widget, &allocation); w = MIN (allocation.height - 2 * thickness.y, allocation.width - 2 * thickness.x); w = MIN (w, ARROW_WIDTH); x = (allocation.width - w) / 2; y = (allocation.height - w) / 2; GTK_WIDGET_CLASS (parent_class)->draw (widget, cr); gtk_style_context_save (context); gtk_style_context_set_state (context, gtk_widget_get_state_flags (widget)); gtk_render_arrow (context, cr, G_PI, x, y, w); gtk_style_context_restore (context); } return TRUE; }
static gboolean draw_cb_arrows (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); gtk_style_context_set_state (context, 0); gtk_render_arrow (context, cr, 0, 12, 12, 12); gtk_render_arrow (context, cr, G_PI/2, 36, 12, 12); gtk_render_arrow (context, cr, G_PI, 60, 12, 12); gtk_render_arrow (context, cr, G_PI*3/2, 84, 12, 12); gtk_style_context_restore (context); return TRUE; }
/********************************************************************\ * Draw an arrow on a Widget so it can be altered with css * * * * Args: widget - widget to add arrow to in the draw callback * * cr - cairo context for the draw callback * * direction - 0 for up, 1 for down * * Returns: TRUE, stop other handlers being invoked for the event * \********************************************************************/ gboolean gnc_draw_arrow_cb (GtkWidget *widget, cairo_t *cr, gpointer direction) { GtkStyleContext *context = gtk_widget_get_style_context (widget); gint width = gtk_widget_get_allocated_width (widget); gint height = gtk_widget_get_allocated_height (widget); gint size; gtk_render_background (context, cr, 0, 0, width, height); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW); size = MIN(width / 2, height / 2); if (GPOINTER_TO_INT(direction) == 0) gtk_render_arrow (context, cr, 0, (width - size)/2, (height - size)/2, size); else gtk_render_arrow (context, cr, G_PI, (width - size)/2, (height - size)/2, size); return TRUE; }
void ScrollbarThemeGtk::paintButton(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part) { GtkStyleContext* styleContext = gtkScrollbarStyleContext(); gtk_style_context_save(styleContext); ScrollbarOrientation orientation = scrollbar->orientation(); applyScrollbarStyleContextClasses(styleContext, orientation); guint flags = 0; if ((BackButtonStartPart == part && scrollbar->currentPos()) || (BackButtonEndPart == part && scrollbar->currentPos()) || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum()) || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) { if (part == scrollbar->pressedPart()) flags |= GTK_STATE_FLAG_ACTIVE; if (part == scrollbar->hoveredPart()) flags |= GTK_STATE_FLAG_PRELIGHT; } else flags |= GTK_STATE_FLAG_INSENSITIVE; gtk_style_context_set_state(styleContext, static_cast<GtkStateFlags>(flags)); gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_BUTTON); gtk_render_background(styleContext, context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); gtk_render_frame(styleContext, context->platformContext()->cr(), rect.x(), rect.y(), rect.width(), rect.height()); gfloat arrowScaling; gtk_style_context_get_style(styleContext, "arrow-scaling", &arrowScaling, nullptr); double arrowSize = std::min(rect.width(), rect.height()) * arrowScaling; FloatPoint arrowPoint( rect.x() + (rect.width() - arrowSize) / 2, rect.y() + (rect.height() - arrowSize) / 2); if (flags & GTK_STATE_FLAG_ACTIVE) { gint arrowDisplacementX, arrowDisplacementY; gtk_style_context_get_style(styleContext, "arrow-displacement-x", &arrowDisplacementX, "arrow-displacement-y", &arrowDisplacementY, nullptr); arrowPoint.move(arrowDisplacementX, arrowDisplacementY); } gdouble angle; if (orientation == VerticalScrollbar) angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI : 0; else angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI / 2 : 3 * (G_PI / 2); gtk_render_arrow(styleContext, context->platformContext()->cr(), angle, arrowPoint.x(), arrowPoint.y(), arrowSize); gtk_style_context_restore(styleContext); }
static gboolean draw_arrow_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { GncItemEdit *item_edit = GNC_ITEM_EDIT (data); GtkStyleContext *context = gtk_widget_get_style_context (widget); gint width = gtk_widget_get_allocated_width (widget); gint height = gtk_widget_get_allocated_height (widget); gint size; gtk_render_background (context, cr, 0, 0, width, height); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW); size = MIN(width / 2, height / 2); if (item_edit->popup_toggle.arrow_down == 0) gtk_render_arrow (context, cr, 0, (width - size)/2, (height - size)/2, size); else gtk_render_arrow (context, cr, G_PI, (width - size)/2, (height - size)/2, size); return FALSE; }
/* This code was originally rendering anti-aliased using X primitives, and * now has been switched to draw anti-aliased using cairo. In general, the * closest correspondence between X rendering and cairo rendering is given * by offsetting the geometry by 0.5 pixels in both directions before rendering * with cairo. This is because X samples at the upper left corner of the * pixel while cairo averages over the entire pixel. However, in the cases * where the X rendering was an exact rectangle with no "jaggies" * we need to be a bit careful about applying the offset. We want to produce * the exact same pixel-aligned rectangle, rather than a rectangle with * fuzz around the edges. */ static void draw_op_draw_with_env (const MetaDrawOp *op, GtkStyleContext *context, cairo_t *cr, const MetaDrawInfo *info, MetaPositionExprEnv *env) { GdkRGBA color; cairo_save (cr); cairo_set_line_width (cr, 1.0); switch (op->type) { case META_DRAW_LINE: { gdouble x1, x2, y1, y2; meta_color_spec_render (op->data.line.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); if (op->data.line.width > 0) cairo_set_line_width (cr, op->data.line.width); if (op->data.line.dash_on_length > 0 && op->data.line.dash_off_length > 0) { double dash_list[2]; dash_list[0] = op->data.line.dash_on_length; dash_list[1] = op->data.line.dash_off_length; cairo_set_dash (cr, dash_list, 2, 0); } x1 = meta_draw_spec_parse_x_position (op->data.line.x1, env); y1 = meta_draw_spec_parse_y_position (op->data.line.y1, env); if (!op->data.line.x2 && !op->data.line.y2 && op->data.line.width == 0) { cairo_rectangle (cr, x1, y1, 1, 1); cairo_fill (cr); } else { if (op->data.line.x2) x2 = meta_draw_spec_parse_x_position (op->data.line.x2, env); else x2 = x1; if (op->data.line.y2) y2 = meta_draw_spec_parse_y_position (op->data.line.y2, env); else y2 = y1; /* This is one of the cases where we are matching the exact * pixel aligned rectangle produced by X; for zero-width lines * the generic algorithm produces the right result so we don't * need to handle them here. */ if ((y1 == y2 || x1 == x2) && op->data.line.width != 0) { double offset = op->data.line.width % 2 ? .5 : 0; if (y1 == y2) { cairo_move_to (cr, x1, y1 + offset); cairo_line_to (cr, x2, y2 + offset); } else { cairo_move_to (cr, x1 + offset, y1); cairo_line_to (cr, x2 + offset, y2); } } else { /* zero-width lines include both end-points in X, unlike wide lines */ if (op->data.line.width == 0) cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to (cr, x1 + .5, y1 + .5); cairo_line_to (cr, x2 + .5, y2 + .5); } cairo_stroke (cr); } } break; case META_DRAW_RECTANGLE: { gdouble rx, ry, rwidth, rheight; meta_color_spec_render (op->data.rectangle.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.rectangle.x, env); ry = meta_draw_spec_parse_y_position (op->data.rectangle.y, env); rwidth = meta_draw_spec_parse_size (op->data.rectangle.width, env); rheight = meta_draw_spec_parse_size (op->data.rectangle.height, env); /* Filled and stroked rectangles are the other cases * we pixel-align to X rasterization */ if (op->data.rectangle.filled) { cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_fill (cr); } else { cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight); cairo_stroke (cr); } } break; case META_DRAW_ARC: { gdouble rx, ry, rwidth, rheight; double start_angle, end_angle; double center_x, center_y; meta_color_spec_render (op->data.arc.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.arc.x, env); ry = meta_draw_spec_parse_y_position (op->data.arc.y, env); rwidth = meta_draw_spec_parse_size (op->data.arc.width, env); rheight = meta_draw_spec_parse_size (op->data.arc.height, env); start_angle = op->data.arc.start_angle * (M_PI / 180.) - (.5 * M_PI); /* start at 12 instead of 3 oclock */ end_angle = start_angle + op->data.arc.extent_angle * (M_PI / 180.); center_x = rx + (double)rwidth / 2. + .5; center_y = ry + (double)rheight / 2. + .5; cairo_save (cr); cairo_translate (cr, center_x, center_y); cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.); if (op->data.arc.extent_angle >= 0) cairo_arc (cr, 0, 0, 1, start_angle, end_angle); else cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle); cairo_restore (cr); if (op->data.arc.filled) { cairo_line_to (cr, center_x, center_y); cairo_fill (cr); } else cairo_stroke (cr); } break; case META_DRAW_CLIP: break; case META_DRAW_TINT: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.tint.x, env); ry = meta_draw_spec_parse_y_position (op->data.tint.y, env); rwidth = meta_draw_spec_parse_size (op->data.tint.width, env); rheight = meta_draw_spec_parse_size (op->data.tint.height, env); meta_color_spec_render (op->data.tint.color_spec, context, &color); meta_alpha_gradient_spec_render (op->data.tint.alpha_spec, color, cr, rx, ry, rwidth, rheight); } break; case META_DRAW_GRADIENT: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.gradient.x, env); ry = meta_draw_spec_parse_y_position (op->data.gradient.y, env); rwidth = meta_draw_spec_parse_size (op->data.gradient.width, env); rheight = meta_draw_spec_parse_size (op->data.gradient.height, env); meta_gradient_spec_render (op->data.gradient.gradient_spec, op->data.gradient.alpha_spec, cr, context, rx, ry, rwidth, rheight); } break; case META_DRAW_IMAGE: { gdouble scale; gdouble rx, ry, rwidth, rheight; cairo_surface_t *surface; scale = info->scale; cairo_scale (cr, 1.0 / scale, 1.0 / scale); if (op->data.image.pixbuf) { env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf); env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf); } rwidth = meta_draw_spec_parse_size (op->data.image.width, env) * scale; rheight = meta_draw_spec_parse_size (op->data.image.height, env) * scale; surface = draw_op_as_surface (op, context, info, rwidth, rheight); if (surface) { rx = meta_draw_spec_parse_x_position (op->data.image.x, env) * scale; ry = meta_draw_spec_parse_y_position (op->data.image.y, env) * scale; cairo_set_source_surface (cr, surface, rx, ry); if (op->data.image.alpha_spec) { cairo_pattern_t *pattern; cairo_translate (cr, rx, ry); cairo_scale (cr, rwidth, rheight); pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); } else { cairo_paint (cr); } cairo_surface_destroy (surface); } } break; case META_DRAW_GTK_ARROW: { gdouble rx, ry, rwidth, rheight; double angle = 0, size; rx = meta_draw_spec_parse_x_position (op->data.gtk_arrow.x, env); ry = meta_draw_spec_parse_y_position (op->data.gtk_arrow.y, env); rwidth = meta_draw_spec_parse_size (op->data.gtk_arrow.width, env); rheight = meta_draw_spec_parse_size (op->data.gtk_arrow.height, env); size = MAX(rwidth, rheight); switch (op->data.gtk_arrow.arrow) { case GTK_ARROW_UP: angle = 0; break; case GTK_ARROW_RIGHT: angle = M_PI / 2; break; case GTK_ARROW_DOWN: angle = M_PI; break; case GTK_ARROW_LEFT: angle = 3 * M_PI / 2; break; case GTK_ARROW_NONE: return; default: break; } gtk_style_context_set_state (context, op->data.gtk_arrow.state); gtk_render_arrow (context, cr, angle, rx, ry, size); } break; case META_DRAW_GTK_BOX: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.gtk_box.x, env); ry = meta_draw_spec_parse_y_position (op->data.gtk_box.y, env); rwidth = meta_draw_spec_parse_size (op->data.gtk_box.width, env); rheight = meta_draw_spec_parse_size (op->data.gtk_box.height, env); gtk_style_context_set_state (context, op->data.gtk_box.state); gtk_render_background (context, cr, rx, ry, rwidth, rheight); gtk_render_frame (context, cr, rx, ry, rwidth, rheight); } break; case META_DRAW_GTK_VLINE: { gdouble rx, ry1, ry2; rx = meta_draw_spec_parse_x_position (op->data.gtk_vline.x, env); ry1 = meta_draw_spec_parse_y_position (op->data.gtk_vline.y1, env); ry2 = meta_draw_spec_parse_y_position (op->data.gtk_vline.y2, env); gtk_style_context_set_state (context, op->data.gtk_vline.state); gtk_render_line (context, cr, rx, ry1, rx, ry2); } break; case META_DRAW_ICON: { gdouble rx, ry, rwidth, rheight; cairo_surface_t *surface; rwidth = meta_draw_spec_parse_size (op->data.icon.width, env); rheight = meta_draw_spec_parse_size (op->data.icon.height, env); surface = draw_op_as_surface (op, context, info, rwidth, rheight); if (surface) { rx = meta_draw_spec_parse_x_position (op->data.icon.x, env); ry = meta_draw_spec_parse_y_position (op->data.icon.y, env); cairo_set_source_surface (cr, surface, rx, ry); if (op->data.icon.alpha_spec) { cairo_pattern_t *pattern; cairo_translate (cr, rx, ry); cairo_scale (cr, rwidth, rheight); pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); } else { cairo_paint (cr); } cairo_surface_destroy (surface); } } break; case META_DRAW_TITLE: if (info->title_layout) { gdouble rx, ry; PangoRectangle ink_rect, logical_rect; meta_color_spec_render (op->data.title.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.title.x, env); ry = meta_draw_spec_parse_y_position (op->data.title.y, env); if (op->data.title.ellipsize_width) { gdouble ellipsize_width; int right_bearing; ellipsize_width = meta_draw_spec_parse_x_position (op->data.title.ellipsize_width, env); /* HACK: meta_draw_spec_parse_x_position adds in env->rect.x, subtract out again */ ellipsize_width -= env->rect.x; pango_layout_set_width (info->title_layout, -1); pango_layout_get_pixel_extents (info->title_layout, &ink_rect, &logical_rect); /* Pango's idea of ellipsization is with respect to the logical rect. * correct for this, by reducing the ellipsization width by the overflow * of the un-ellipsized text on the right... it's always the visual * right we want regardless of bidi, since since the X we pass in to * cairo_move_to() is always the left edge of the line. */ right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width); right_bearing = MAX (right_bearing, 0); ellipsize_width -= right_bearing; ellipsize_width = MAX (ellipsize_width, 0); /* Only ellipsizing when necessary is a performance optimization - * pango_layout_set_width() will force a relayout if it isn't the * same as the current width of -1. */ if (ellipsize_width < logical_rect.width) pango_layout_set_width (info->title_layout, PANGO_SCALE * ellipsize_width); } else if (rx - env->rect.x + env->title_width >= env->rect.width) { const double alpha_margin = 30.0; int text_space = env->rect.x + env->rect.width - (rx - env->rect.x) - env->right_width; double startalpha = 1.0 - (alpha_margin/((double)text_space)); cairo_pattern_t *linpat; linpat = cairo_pattern_create_linear (rx, ry, text_space, env->title_height); cairo_pattern_add_color_stop_rgba (linpat, 0, color.red, color.green, color.blue, color.alpha); cairo_pattern_add_color_stop_rgba (linpat, startalpha, color.red, color.green, color.blue, color.alpha); cairo_pattern_add_color_stop_rgba (linpat, 1, color.red, color.green, color.blue, 0); cairo_set_source(cr, linpat); cairo_pattern_destroy(linpat); } cairo_move_to (cr, rx, ry); pango_cairo_show_layout (cr, info->title_layout); /* Remove any ellipsization we might have set; will short-circuit * if the width is already -1 */ pango_layout_set_width (info->title_layout, -1); } break; case META_DRAW_OP_LIST: { MetaRectangleDouble d_rect; d_rect.x = meta_draw_spec_parse_x_position (op->data.op_list.x, env); d_rect.y = meta_draw_spec_parse_y_position (op->data.op_list.y, env); d_rect.width = meta_draw_spec_parse_size (op->data.op_list.width, env); d_rect.height = meta_draw_spec_parse_size (op->data.op_list.height, env); meta_draw_op_list_draw_with_style (op->data.op_list.op_list, context, cr, info, d_rect); } break; case META_DRAW_TILE: { gdouble rx, ry, rwidth, rheight; gdouble tile_xoffset, tile_yoffset; MetaRectangleDouble tile; rx = meta_draw_spec_parse_x_position (op->data.tile.x, env); ry = meta_draw_spec_parse_y_position (op->data.tile.y, env); rwidth = meta_draw_spec_parse_size (op->data.tile.width, env); rheight = meta_draw_spec_parse_size (op->data.tile.height, env); cairo_save (cr); cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_clip (cr); tile_xoffset = meta_draw_spec_parse_x_position (op->data.tile.tile_xoffset, env); tile_yoffset = meta_draw_spec_parse_y_position (op->data.tile.tile_yoffset, env); /* tile offset should not include x/y */ tile_xoffset -= env->rect.x; tile_yoffset -= env->rect.y; tile.width = meta_draw_spec_parse_size (op->data.tile.tile_width, env); tile.height = meta_draw_spec_parse_size (op->data.tile.tile_height, env); tile.x = rx - tile_xoffset; while (tile.x < (rx + rwidth)) { tile.y = ry - tile_yoffset; while (tile.y < (ry + rheight)) { meta_draw_op_list_draw_with_style (op->data.tile.op_list, context, cr, info, tile); tile.y += tile.height; } tile.x += tile.width; } cairo_restore (cr); } break; default: break; } cairo_restore (cr); }
static void draw_combobox (GtkWidget *widget, cairo_t *cr, gint x, gint y, gint width, gboolean has_entry, gint *height) { GtkStyleContext *combo_context; GtkStyleContext *box_context; GtkStyleContext *button_context; GtkStyleContext *button_box_context; GtkStyleContext *entry_context; GtkStyleContext *arrow_context; gint contents_x, contents_y, contents_width, contents_height; gint button_width; gint arrow_width, arrow_height, arrow_size; /* This information is taken from the GtkComboBox docs, see "CSS nodes" */ combo_context = get_style (NULL, "combobox:focus"); box_context = get_style (combo_context, "box.horizontal.linked"); if (has_entry) { const char *siblings[3] = { "entry.combo:focus", "button.combo" , NULL }; entry_context = get_style_with_siblings (box_context, "entry.combo:focus", siblings, 0); button_context = get_style_with_siblings (box_context, "button.combo", siblings, 1); } else { const char *siblings[2] = { "button.combo" , NULL }; button_context = get_style_with_siblings (box_context, "button.combo", siblings, 0); } button_box_context = get_style (button_context, "box.horizontal"); arrow_context = get_style (button_box_context, "arrow"); *height = 0; query_size (combo_context, NULL, height); query_size (box_context, NULL, height); if (has_entry) query_size (entry_context, NULL, height); query_size (button_context, NULL, height); query_size (button_box_context, NULL, height); query_size (arrow_context, NULL, height); gtk_style_context_get (arrow_context, "min-width", &arrow_width, "min-height", &arrow_height, NULL); arrow_size = MIN (arrow_width, arrow_height); draw_style_common (combo_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL); draw_style_common (box_context, cr, x, y, width, *height, NULL, NULL, NULL, NULL); if (has_entry) { button_width = *height; draw_style_common (entry_context, cr, x, y, width - button_width, *height, NULL, NULL, NULL, NULL); draw_style_common (button_context, cr, x + width - button_width, y, button_width, *height, &contents_x, &contents_y, &contents_width, &contents_height); } else { button_width = width; draw_style_common (button_context, cr, x, y, width, *height, &contents_x, &contents_y, &contents_width, &contents_height); } draw_style_common (button_box_context, cr, contents_x, contents_y, contents_width, contents_height, NULL, NULL, NULL, NULL); draw_style_common (arrow_context, cr, contents_x, contents_y, contents_width, contents_height, NULL, NULL, NULL, NULL); gtk_render_arrow (arrow_context, cr, G_PI / 2, contents_x + contents_width - arrow_size, contents_y + (contents_height - arrow_size) / 2, arrow_size); g_object_unref (arrow_context); if (has_entry) g_object_unref (entry_context); g_object_unref (button_context); g_object_unref (combo_context); }
static void draw_menu (GtkWidget *widget, cairo_t *cr, gint x, gint y, gint width, gint *height) { GtkStyleContext *menu_context; GtkStyleContext *menuitem_context; GtkStyleContext *hovermenuitem_context; GtkStyleContext *hoveredarrowmenuitem_context; GtkStyleContext *arrowmenuitem_context; GtkStyleContext *checkmenuitem_context; GtkStyleContext *disabledarrowmenuitem_context; GtkStyleContext *disabledcheckmenuitem_context; GtkStyleContext *radiomenuitem_context; GtkStyleContext *disablemenuitem_context; GtkStyleContext *disabledradiomenuitem_context; GtkStyleContext *separatormenuitem_context; gint menuitem1_height, menuitem2_height, menuitem3_height, menuitem4_height, menuitem5_height; gint contents_x, contents_y, contents_width, contents_height; gint menu_x, menu_y, menu_width, menu_height; gint arrow_width, arrow_height, arrow_size; gint toggle_x, toggle_y, toggle_width, toggle_height; /* This information is taken from the GtkMenu docs, see "CSS nodes" */ menu_context = get_style (gtk_widget_get_style_context(widget), "menu"); hovermenuitem_context = get_style (menu_context, "menuitem:hover"); hoveredarrowmenuitem_context = get_style (hovermenuitem_context, "arrow.right:dir(ltr)"); menuitem_context = get_style (menu_context, "menuitem"); arrowmenuitem_context = get_style (menuitem_context, "arrow:dir(rtl)"); disablemenuitem_context = get_style (menu_context, "menuitem:disabled"); disabledarrowmenuitem_context = get_style (disablemenuitem_context, "arrow:dir(rtl)"); checkmenuitem_context = get_style (menuitem_context, "check:checked"); disabledcheckmenuitem_context = get_style (disablemenuitem_context, "check"); separatormenuitem_context = get_style (menu_context, "separator:disabled"); radiomenuitem_context = get_style (menuitem_context, "radio:checked"); disabledradiomenuitem_context = get_style (disablemenuitem_context, "radio"); *height = 0; query_size (menu_context, NULL, height); menuitem1_height = 0; query_size (hovermenuitem_context, NULL, &menuitem1_height); query_size (hoveredarrowmenuitem_context, NULL, &menuitem1_height); *height += menuitem1_height; menuitem2_height = 0; query_size (menu_context, NULL, &menuitem5_height); query_size (menuitem_context, NULL, &menuitem2_height); query_size (arrowmenuitem_context, NULL, &menuitem2_height); query_size (disabledarrowmenuitem_context, NULL, &menuitem2_height); *height += menuitem2_height; menuitem3_height = 0; query_size (menu_context, NULL, &menuitem5_height); query_size (menuitem_context, NULL, &menuitem3_height); query_size (checkmenuitem_context, NULL, &menuitem3_height); query_size (disabledcheckmenuitem_context, NULL, &menuitem3_height); *height += menuitem3_height; menuitem4_height = 0; query_size (menu_context, NULL, &menuitem5_height); query_size (separatormenuitem_context, NULL, &menuitem4_height); *height += menuitem4_height; menuitem5_height = 0; query_size (menu_context, NULL, &menuitem5_height); query_size (menuitem_context, NULL, &menuitem5_height); query_size (radiomenuitem_context, NULL, &menuitem5_height); query_size (disabledradiomenuitem_context, NULL, &menuitem5_height); *height += menuitem5_height; draw_style_common (menu_context, cr, x, y, width, *height, &menu_x, &menu_y, &menu_width, &menu_height); /* Hovered with right arrow */ gtk_style_context_get (hoveredarrowmenuitem_context, "min-width", &arrow_width, "min-height", &arrow_height, NULL); arrow_size = MIN (arrow_width, arrow_height); draw_style_common (hovermenuitem_context, cr, menu_x, menu_y, menu_width, menuitem1_height, &contents_x, &contents_y, &contents_width, &contents_height); gtk_render_arrow (hoveredarrowmenuitem_context, cr, G_PI / 2, contents_x + contents_width - arrow_size, contents_y + (contents_height - arrow_size) / 2, arrow_size); /* Left arrow sensitive, and right arrow insensitive */ draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height, menu_width, menuitem2_height, &contents_x, &contents_y, &contents_width, &contents_height); gtk_style_context_get (arrowmenuitem_context, "min-width", &arrow_width, "min-height", &arrow_height, NULL); arrow_size = MIN (arrow_width, arrow_height); gtk_render_arrow (arrowmenuitem_context, cr, G_PI / 2, contents_x, contents_y + (contents_height - arrow_size) / 2, arrow_size); gtk_style_context_get (disabledarrowmenuitem_context, "min-width", &arrow_width, "min-height", &arrow_height, NULL); arrow_size = MIN (arrow_width, arrow_height); gtk_render_arrow (disabledarrowmenuitem_context, cr, G_PI / 2, contents_x + contents_width - arrow_size, contents_y + (contents_height - arrow_size) / 2, arrow_size); /* Left check enabled, sensitive, and right check unchecked, insensitive */ draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height, menu_width, menuitem3_height, &contents_x, &contents_y, &contents_width, &contents_height); gtk_style_context_get (checkmenuitem_context, "min-width", &toggle_width, "min-height", &toggle_height, NULL); draw_style_common (checkmenuitem_context, cr, contents_x, contents_y, toggle_width, toggle_height, &toggle_x, &toggle_y, &toggle_width, &toggle_height); gtk_render_check (checkmenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height); gtk_style_context_get (disabledcheckmenuitem_context, "min-width", &toggle_width, "min-height", &toggle_height, NULL); draw_style_common (disabledcheckmenuitem_context, cr, contents_x + contents_width - toggle_width, contents_y, toggle_width, toggle_height, &toggle_x, &toggle_y, &toggle_width, &toggle_height); gtk_render_check (disabledcheckmenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height); /* Separator */ draw_style_common (separatormenuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height + menuitem3_height, menu_width, menuitem4_height, NULL, NULL, NULL, NULL); /* Left check enabled, sensitive, and right check unchecked, insensitive */ draw_style_common (menuitem_context, cr, menu_x, menu_y + menuitem1_height + menuitem2_height + menuitem3_height + menuitem4_height, menu_width, menuitem5_height, &contents_x, &contents_y, &contents_width, &contents_height); gtk_style_context_get (radiomenuitem_context, "min-width", &toggle_width, "min-height", &toggle_height, NULL); draw_style_common (radiomenuitem_context, cr, contents_x, contents_y, toggle_width, toggle_height, &toggle_x, &toggle_y, &toggle_width, &toggle_height); gtk_render_check (radiomenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height); gtk_style_context_get (disabledradiomenuitem_context, "min-width", &toggle_width, "min-height", &toggle_height, NULL); draw_style_common (disabledradiomenuitem_context, cr, contents_x + contents_width - toggle_width, contents_y, toggle_width, toggle_height, &toggle_x, &toggle_y, &toggle_width, &toggle_height); gtk_render_check (disabledradiomenuitem_context, cr, toggle_x, toggle_y, toggle_width, toggle_height); g_object_unref (menu_context); g_object_unref (menuitem_context); g_object_unref (hovermenuitem_context); g_object_unref (hoveredarrowmenuitem_context); g_object_unref (arrowmenuitem_context); g_object_unref (checkmenuitem_context); g_object_unref (disabledarrowmenuitem_context); g_object_unref (disabledcheckmenuitem_context); g_object_unref (radiomenuitem_context); g_object_unref (disablemenuitem_context); g_object_unref (disabledradiomenuitem_context); g_object_unref (separatormenuitem_context); }
static gboolean gtk_tearoff_menu_item_draw (GtkWidget *widget, cairo_t *cr) { GtkMenuItem *menu_item; GtkStateFlags state; GtkStyleContext *context; GtkBorder padding; gint x, y, width, height; gint right_max; guint border_width; GtkTextDirection direction; GtkWidget *parent; gdouble angle; menu_item = GTK_MENU_ITEM (widget); context = gtk_widget_get_style_context (widget); direction = gtk_widget_get_direction (widget); state = gtk_widget_get_state_flags (widget); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_item)); x = border_width; y = border_width; width = gtk_widget_get_allocated_width (widget) - border_width * 2; height = gtk_widget_get_allocated_height (widget) - border_width * 2; right_max = x + width; gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_style_context_get_padding (context, state, &padding); if (state & GTK_STATE_FLAG_PRELIGHT) { gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); } parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU (parent) && gtk_menu_get_tearoff_state (GTK_MENU (parent))) { gint arrow_x; if (menu_item->priv->toggle_size > ARROW_SIZE) { if (direction == GTK_TEXT_DIR_LTR) { arrow_x = x + (menu_item->priv->toggle_size - ARROW_SIZE)/2; angle = (3 * G_PI) / 2; } else { arrow_x = x + width - menu_item->priv->toggle_size + (menu_item->priv->toggle_size - ARROW_SIZE)/2; angle = G_PI / 2; } x += menu_item->priv->toggle_size + BORDER_SPACING; } else { if (direction == GTK_TEXT_DIR_LTR) { arrow_x = ARROW_SIZE / 2; angle = (3 * G_PI) / 2; } else { arrow_x = x + width - 2 * ARROW_SIZE + ARROW_SIZE / 2; angle = G_PI / 2; } x += 2 * ARROW_SIZE; } gtk_render_arrow (context, cr, angle, arrow_x, height / 2 - 5, ARROW_SIZE); } while (x < right_max) { gint x1, x2; if (direction == GTK_TEXT_DIR_LTR) { x1 = x; x2 = MIN (x + TEAR_LENGTH, right_max); } else { x1 = right_max - x; x2 = MAX (right_max - x - TEAR_LENGTH, 0); } gtk_render_line (context, cr, x1, y + (height - padding.bottom) / 2, x2, y + (height - padding.bottom) / 2); x += 2 * TEAR_LENGTH; } gtk_style_context_restore (context); return FALSE; }