diff --git a/gtk/gtkrenderlayout.c b/gtk/gtkrenderlayout.c index 1d38ff097b..454ca2fc78 100644 --- a/gtk/gtkrenderlayout.c +++ b/gtk/gtkrenderlayout.c @@ -24,6 +24,7 @@ #include "gtkpangoprivate.h" #include "gtksnapshot.h" #include "gtktypebuiltins.h" +#include "gtksettings.h" void @@ -60,3 +61,250 @@ gtk_css_style_snapshot_layout (GtkCssBoxes *boxes, gtk_snapshot_pop (snapshot); } +static void +draw_insertion_cursor (cairo_t *cr, + double x, + double y, + double width, + double height, + double aspect_ratio, + const GdkRGBA *color, + PangoDirection direction, + gboolean draw_arrow) +{ + int stem_width; + double angle; + double dx, dy; + double xx1, yy1, xx2, yy2; + + cairo_save (cr); + cairo_new_path (cr); + + gdk_cairo_set_source_rgba (cr, color); + + stem_width = height * aspect_ratio + 1; + + yy1 = y; + yy2 = y + height; + + if (width < 0) + { + xx1 = x; + xx2 = x - width; + } + else + { + xx1 = x + width; + xx2 = x; + } + + angle = atan2 (height, width); + + dx = (stem_width/2.0) * cos (M_PI/2 - angle); + dy = (stem_width/2.0) * sin (M_PI/2 - angle); + + if (draw_arrow) + { + if (direction == PANGO_DIRECTION_RTL) + { + double x0, y0, x1, y1, x2, y2; + + x0 = xx2 - dx + 2 * dy; + y0 = yy2 - dy - 2 * dx; + + x1 = x0 + 4 * dy; + y1 = y0 - 4 * dx; + x2 = x0 + 2 * dy - 3 * dx; + y2 = y0 - 2 * dx - 3 * dy; + + cairo_move_to (cr, xx1 + dx, yy1 + dy); + cairo_line_to (cr, xx2 + dx, yy2 + dy); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x1, y1); + cairo_line_to (cr, xx1 - dx, yy1 - dy); + } + else if (direction == PANGO_DIRECTION_LTR) + { + double x0, y0, x1, y1, x2, y2; + + x0 = xx2 + dx + 2 * dy; + y0 = yy2 + dy - 2 * dx; + + x1 = x0 + 4 * dy; + y1 = y0 - 4 * dx; + x2 = x0 + 2 * dy + 3 * dx; + y2 = y0 - 2 * dx + 3 * dy; + + cairo_move_to (cr, xx1 - dx, yy1 - dy); + cairo_line_to (cr, xx2 - dx, yy2 - dy); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x1, y1); + cairo_line_to (cr, xx1 + dx, yy1 + dy); + } + else + g_assert_not_reached(); + } + else + { + cairo_move_to (cr, xx1 + dx, yy1 + dy); + cairo_line_to (cr, xx2 + dx, yy2 + dy); + cairo_line_to (cr, xx2 - dx, yy2 - dy); + cairo_line_to (cr, xx1 - dx, yy1 - dy); + } + + cairo_fill (cr); + + cairo_restore (cr); +} + +static void +get_insertion_cursor_bounds (double width, + double height, + double aspect_ratio, + PangoDirection direction, + gboolean draw_arrow, + graphene_rect_t *bounds) +{ + int stem_width; + + if (width < 0) + width = - width; + + stem_width = height * aspect_ratio + 1; + + graphene_rect_init (bounds, + - 2 * stem_width, - stem_width, + width + 4 * stem_width, height + 2 * stem_width); +} + +static void +snapshot_insertion_cursor (GtkSnapshot *snapshot, + GtkCssStyle *style, + double width, + double height, + double aspect_ratio, + gboolean is_primary, + PangoDirection direction, + gboolean draw_arrow) +{ + GdkRGBA color; + + if (is_primary) + color = *gtk_css_color_value_get_rgba (style->font->caret_color ? style->font->caret_color : style->core->color); + else + color = *gtk_css_color_value_get_rgba (style->font->secondary_caret_color ? style->font->secondary_caret_color : style->core->color); + + if (width != 0 || draw_arrow) + { + cairo_t *cr; + graphene_rect_t bounds; + + get_insertion_cursor_bounds (width, height, aspect_ratio, direction, draw_arrow, &bounds); + cr = gtk_snapshot_append_cairo (snapshot, &bounds); + + draw_insertion_cursor (cr, 0, 0, width, height, aspect_ratio, &color, direction, draw_arrow); + + cairo_destroy (cr); + } + else + { + int stem_width; + int offset; + + stem_width = height * 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; + + gtk_snapshot_append_color (snapshot, + &color, + &GRAPHENE_RECT_INIT (- offset, 0, stem_width, height)); + } +} + +void +gtk_css_style_snapshot_caret (GtkCssBoxes *boxes, + GdkDisplay *display, + GtkSnapshot *snapshot, + int x, + int y, + PangoLayout *layout, + int index, + PangoDirection direction) +{ + gboolean split_cursor; + double aspect_ratio; + PangoRectangle strong_pos, weak_pos; + PangoRectangle *cursor1, *cursor2; + GdkSeat *seat; + PangoDirection keyboard_direction; + PangoDirection direction2; + + g_object_get (gtk_settings_get_for_display (display), + "gtk-split-cursor", &split_cursor, + "gtk-cursor-aspect-ratio", &aspect_ratio, + NULL); + + keyboard_direction = PANGO_DIRECTION_LTR; + seat = gdk_display_get_default_seat (display); + if (seat) + { + GdkDevice *keyboard = gdk_seat_get_keyboard (seat); + + if (keyboard) + keyboard_direction = gdk_device_get_direction (keyboard); + } + + pango_layout_get_caret_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 (keyboard_direction == direction) + cursor1 = &strong_pos; + else + cursor1 = &weak_pos; + } + + gtk_snapshot_save (snapshot); + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (MIN (cursor1->x, cursor1->x + cursor1->width)), y + PANGO_PIXELS (cursor1->y))); + snapshot_insertion_cursor (snapshot, + boxes->style, + PANGO_PIXELS (cursor1->width), + PANGO_PIXELS (cursor1->height), + aspect_ratio, + TRUE, + direction, + direction2 != PANGO_DIRECTION_NEUTRAL); + gtk_snapshot_restore (snapshot); + + if (direction2 != PANGO_DIRECTION_NEUTRAL) + { + gtk_snapshot_save (snapshot); + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x + PANGO_PIXELS (MIN (cursor2->x, cursor2->x + cursor2->width)), y + PANGO_PIXELS (cursor2->y))); + snapshot_insertion_cursor (snapshot, + boxes->style, + PANGO_PIXELS (cursor2->width), + PANGO_PIXELS (cursor2->height), + aspect_ratio, + FALSE, + direction2, + TRUE); + gtk_snapshot_restore (snapshot); + } +} + diff --git a/gtk/gtkrenderlayoutprivate.h b/gtk/gtkrenderlayoutprivate.h index ec4d13b816..e14b5c0b78 100644 --- a/gtk/gtkrenderlayoutprivate.h +++ b/gtk/gtkrenderlayoutprivate.h @@ -27,11 +27,20 @@ G_BEGIN_DECLS -void gtk_css_style_snapshot_layout (GtkCssBoxes *boxes, - GtkSnapshot *snapshot, - int x, - int y, - PangoLayout *layout); +void gtk_css_style_snapshot_layout (GtkCssBoxes *boxes, + GtkSnapshot *snapshot, + int x, + int y, + PangoLayout *layout); + +void gtk_css_style_snapshot_caret (GtkCssBoxes *boxes, + GdkDisplay *display, + GtkSnapshot *snapshot, + int x, + int y, + PangoLayout *layout, + int index, + PangoDirection direction); G_END_DECLS