static void gimp_combo_tag_entry_style_set (GtkWidget *widget, GtkStyle *previous_style) { GimpComboTagEntry *entry = GIMP_COMBO_TAG_ENTRY (widget); GtkStyle *style = gtk_widget_get_style (widget); GdkColor color; PangoAttribute *attribute; if (GTK_WIDGET_CLASS (parent_class)->style_set) GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style); if (entry->normal_item_attr) pango_attr_list_unref (entry->normal_item_attr); entry->normal_item_attr = pango_attr_list_new (); if (style->font_desc) { attribute = pango_attr_font_desc_new (style->font_desc); pango_attr_list_insert (entry->normal_item_attr, attribute); } color = style->text[GTK_STATE_NORMAL]; attribute = pango_attr_foreground_new (color.red, color.green, color.blue); pango_attr_list_insert (entry->normal_item_attr, attribute); if (entry->selected_item_attr) pango_attr_list_unref (entry->selected_item_attr); entry->selected_item_attr = pango_attr_list_copy (entry->normal_item_attr); color = style->text[GTK_STATE_SELECTED]; attribute = pango_attr_foreground_new (color.red, color.green, color.blue); pango_attr_list_insert (entry->selected_item_attr, attribute); color = style->base[GTK_STATE_SELECTED]; attribute = pango_attr_background_new (color.red, color.green, color.blue); pango_attr_list_insert (entry->selected_item_attr, attribute); if (entry->insensitive_item_attr) pango_attr_list_unref (entry->insensitive_item_attr); entry->insensitive_item_attr = pango_attr_list_copy (entry->normal_item_attr); color = style->text[GTK_STATE_INSENSITIVE]; attribute = pango_attr_foreground_new (color.red, color.green, color.blue); pango_attr_list_insert (entry->insensitive_item_attr, attribute); color = style->base[GTK_STATE_INSENSITIVE]; attribute = pango_attr_background_new (color.red, color.green, color.blue); pango_attr_list_insert (entry->insensitive_item_attr, attribute); entry->selected_item_color = style->base[GTK_STATE_SELECTED]; if (entry->arrow_pixbuf) { g_object_unref (entry->arrow_pixbuf); entry->arrow_pixbuf = NULL; } }
static void match_label_color (GstyleColorWidget *self, GstyleColor *color) { PangoLayout *layout; PangoAttrList *attr_list; PangoAttribute *attr; GdkRGBA rgba; GdkRGBA dst_rgba; g_assert (GSTYLE_IS_COLOR_WIDGET (self)); g_assert (GSTYLE_IS_COLOR (color)); layout = gtk_label_get_layout (self->label); attr_list = pango_layout_get_attributes (layout); if (attr_list == NULL) { attr_list = pango_attr_list_new (); gtk_label_set_attributes (self->label, attr_list); pango_attr_list_unref (attr_list); } gstyle_color_fill_rgba (color, &rgba); gstyle_utils_get_contrasted_rgba (rgba, &dst_rgba); attr = pango_attr_foreground_new (dst_rgba.red * 0xffff, dst_rgba.green * 0xffff, dst_rgba.blue * 0xffff); pango_attr_list_change (attr_list, attr); attr = pango_attr_background_new (rgba.red * 0xffff, rgba.green * 0xffff, rgba.blue * 0xffff); pango_attr_list_change (attr_list, attr); }
static void create_cursor_attr() { if (attr_list) pango_attr_list_unref(attr_list); GdkColor color_bg, color_fg; if (hime_win_color_use) gdk_color_parse(tsin_cursor_color, &color_bg); else gdk_color_parse(TSIN_CURSOR_COLOR_DEFAULT, &color_bg); gdk_color_parse("white", &color_fg); attr_list = pango_attr_list_new (); attr_list_blank = pango_attr_list_new (); PangoAttribute *blue_bg = pango_attr_background_new( color_bg.red, color_bg.green, color_bg.blue); blue_bg->start_index = 0; blue_bg->end_index = 128; pango_attr_list_insert (attr_list, blue_bg); PangoAttribute *white_fg = pango_attr_foreground_new( color_fg.red, color_fg.green, color_fg.blue); white_fg->start_index = 0; white_fg->end_index = 128; pango_attr_list_insert (attr_list, white_fg); }
static void set_background(CustomData *data) { PangoAttrList *attrs; attrs = pango_attr_list_new(); pango_attr_list_insert (attrs, pango_attr_background_new (65535, 0, 0)); gtk_label_set_attributes(GTK_LABEL (data->timelabel), attrs); pango_attr_list_unref (attrs); }
static void text_input_preedit_styling(void *data, struct wl_text_input *text_input, uint32_t index, uint32_t length, uint32_t style) { struct text_entry *entry = data; PangoAttribute *attr1 = NULL; PangoAttribute *attr2 = NULL; if (!entry->preedit_info.attr_list) entry->preedit_info.attr_list = pango_attr_list_new(); switch (style) { case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT: case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE: attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); break; case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT: attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR); attr2 = pango_attr_underline_color_new(65535, 0, 0); break; case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION: attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535); attr2 = pango_attr_foreground_new(65535, 65535, 65535); break; case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT: case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE: attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD); break; case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE: attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535); break; } if (attr1) { attr1->start_index = entry->cursor + index; attr1->end_index = entry->cursor + index + length; pango_attr_list_insert(entry->preedit_info.attr_list, attr1); } if (attr2) { attr2->start_index = entry->cursor + index; attr2->end_index = entry->cursor + index + length; pango_attr_list_insert(entry->preedit_info.attr_list, attr2); } }
/** * gimp_label_set_attributes: * @label: a #GtkLabel * @...: a list of PangoAttrType and value pairs terminated by -1. * * Sets Pango attributes on a #GtkLabel in a more convenient way than * gtk_label_set_attributes(). * * This function is useful if you want to change the font attributes * of a #GtkLabel. This is an alternative to using PangoMarkup which * is slow to parse and akward to handle in an i18n-friendly way. * * The attributes are set on the complete label, from start to end. If * you need to set attributes on part of the label, you will have to * use the PangoAttributes API directly. * * Since: 2.2 **/ void gimp_label_set_attributes (GtkLabel *label, ...) { PangoAttribute *attr = NULL; PangoAttrList *attrs; va_list args; g_return_if_fail (GTK_IS_LABEL (label)); attrs = pango_attr_list_new (); va_start (args, label); do { PangoAttrType attr_type = va_arg (args, PangoAttrType); if (attr_type == -1) attr_type = PANGO_ATTR_INVALID; switch (attr_type) { case PANGO_ATTR_LANGUAGE: attr = pango_attr_language_new (va_arg (args, PangoLanguage *)); break; case PANGO_ATTR_FAMILY: attr = pango_attr_family_new (va_arg (args, const gchar *)); break; case PANGO_ATTR_STYLE: attr = pango_attr_style_new (va_arg (args, PangoStyle)); break; case PANGO_ATTR_WEIGHT: attr = pango_attr_weight_new (va_arg (args, PangoWeight)); break; case PANGO_ATTR_VARIANT: attr = pango_attr_variant_new (va_arg (args, PangoVariant)); break; case PANGO_ATTR_STRETCH: attr = pango_attr_stretch_new (va_arg (args, PangoStretch)); break; case PANGO_ATTR_SIZE: attr = pango_attr_size_new (va_arg (args, gint)); break; case PANGO_ATTR_FONT_DESC: attr = pango_attr_font_desc_new (va_arg (args, const PangoFontDescription *)); break; case PANGO_ATTR_FOREGROUND: { const PangoColor *color = va_arg (args, const PangoColor *); attr = pango_attr_foreground_new (color->red, color->green, color->blue); } break; case PANGO_ATTR_BACKGROUND: { const PangoColor *color = va_arg (args, const PangoColor *); attr = pango_attr_background_new (color->red, color->green, color->blue); } break; case PANGO_ATTR_UNDERLINE: attr = pango_attr_underline_new (va_arg (args, PangoUnderline)); break; case PANGO_ATTR_STRIKETHROUGH: attr = pango_attr_strikethrough_new (va_arg (args, gboolean)); break; case PANGO_ATTR_RISE: attr = pango_attr_rise_new (va_arg (args, gint)); break; case PANGO_ATTR_SCALE: attr = pango_attr_scale_new (va_arg (args, gdouble)); break; default: g_warning ("%s: invalid PangoAttribute type %d", G_STRFUNC, attr_type); case PANGO_ATTR_INVALID: attr = NULL; break; } if (attr) { attr->start_index = 0; attr->end_index = -1; pango_attr_list_insert (attrs, attr); } } while (attr); va_end (args); gtk_label_set_attributes (label, attrs); pango_attr_list_unref (attrs); }
void scim_bridge_client_imcontext_set_preedit_attributes (ScimBridgeClientIMContext *imcontext, ScimBridgeAttribute** const preedit_attributes, int attribute_count) { if (imcontext->preedit_attributes != NULL) pango_attr_list_unref (imcontext->preedit_attributes); imcontext->preedit_attributes = pango_attr_list_new (); int preedit_string_length = 0; int preedit_wstring_length = 0; if (imcontext->preedit_string != NULL) { preedit_string_length = strlen (imcontext->preedit_string); preedit_wstring_length = g_utf8_strlen (imcontext->preedit_string, -1); } boolean *has_attribute = alloca (sizeof (boolean) * preedit_string_length); int i; for (i = 0; i < preedit_string_length; ++i) { has_attribute[i] = FALSE; } for (i = 0; i < attribute_count; ++i) { const ScimBridgeAttribute *attr = preedit_attributes[i]; const int begin_pos = scim_bridge_attribute_get_begin (attr); const int end_pos = scim_bridge_attribute_get_end (attr); if (begin_pos <= end_pos && 0 <= begin_pos && end_pos <= preedit_wstring_length) { const int start_index = g_utf8_offset_to_pointer (imcontext->preedit_string, begin_pos) - imcontext->preedit_string; const int end_index = g_utf8_offset_to_pointer (imcontext->preedit_string, end_pos) - imcontext->preedit_string; const scim_bridge_attribute_type_t attr_type = scim_bridge_attribute_get_type (attr); const scim_bridge_attribute_value_t attr_value = scim_bridge_attribute_get_value (attr); boolean valid_attribute = FALSE; if (attr_type == ATTRIBUTE_DECORATE) { if (attr_value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_UNDERLINE) { valid_attribute = TRUE; PangoAttribute *pango_attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); pango_attr->start_index = start_index; pango_attr->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr); } else if (attr_value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_REVERSE) { valid_attribute = TRUE; PangoAttribute *pango_attr0 = pango_attr_foreground_new (preedit_normal_background.red, preedit_normal_background.green, preedit_normal_background.blue); pango_attr0->start_index = start_index; pango_attr0->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr0); PangoAttribute *pango_attr1 = pango_attr_background_new (preedit_normal_foreground.red, preedit_normal_foreground.green, preedit_normal_foreground.blue); pango_attr1->start_index = start_index; pango_attr1->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr1); } else if (attr_value == SCIM_BRIDGE_ATTRIBUTE_DECORATE_HIGHLIGHT) { valid_attribute = TRUE; PangoAttribute *pango_attr0 = pango_attr_foreground_new (preedit_active_foreground.red, preedit_active_foreground.green, preedit_active_foreground.blue); pango_attr0->start_index = start_index; pango_attr0->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr0); PangoAttribute *pango_attr1 = pango_attr_background_new (preedit_active_background.red, preedit_active_background.green, preedit_active_background.blue); pango_attr1->start_index = start_index; pango_attr1->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr1); } else { scim_bridge_perrorln ("Unknown preedit decoration!"); } } else if (attr_type == ATTRIBUTE_FOREGROUND) { valid_attribute = TRUE; const unsigned int red = scim_bridge_attribute_get_red (attr) * 256; const unsigned int green = scim_bridge_attribute_get_green (attr) * 256; const unsigned int blue = scim_bridge_attribute_get_blue (attr) * 256; PangoAttribute *pango_attr = pango_attr_foreground_new (red, green, blue); pango_attr->start_index = start_index; pango_attr->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr); } else if (attr_type == ATTRIBUTE_BACKGROUND) { valid_attribute = TRUE; const unsigned int red = scim_bridge_attribute_get_red (attr) * 256; const unsigned int green = scim_bridge_attribute_get_green (attr) * 256; const unsigned int blue = scim_bridge_attribute_get_blue (attr) * 256; PangoAttribute *pango_attr = pango_attr_background_new (red, green, blue); pango_attr->start_index = start_index; pango_attr->end_index = end_index; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr); } if (valid_attribute) { int j; for (j = start_index; j < end_index; ++j) { has_attribute[j] = TRUE; } } } } // Add underlines for the all characters without attributes. for (i = 0; i < preedit_string_length; ++i) { if (has_attribute[i] == FALSE) { PangoAttribute *pango_attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE); pango_attr->start_index = i; for (; i < preedit_string_length && has_attribute[i] == FALSE; ++i); pango_attr->end_index = i; pango_attr_list_insert (imcontext->preedit_attributes, pango_attr); } } }
static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data) { DocInfo *dinfo = user_data; GeanyEditor *editor; cairo_t *cr; gdouble width, height; gdouble x = 0.0, y = 0.0; /*gint layout_h;*/ gint count; GString *str; if (dinfo == NULL || page_nr >= dinfo->n_pages) return; editor = dinfo->doc->editor; if (dinfo->n_pages > 0) { gdouble fraction = (page_nr + 1) / (gdouble) dinfo->n_pages; gchar *text = g_strdup_printf(_("Page %d of %d"), page_nr, dinfo->n_pages); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_widgets.progressbar), fraction); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), text); g_free(text); } #ifdef GEANY_PRINT_DEBUG geany_debug("draw_page = %d, pages = %d, (real) lines_per_page = %d", page_nr, dinfo->n_pages, dinfo->lines_per_page); #endif str = g_string_sized_new(256); cr = gtk_print_context_get_cairo_context(context); width = gtk_print_context_get_width(context); height = gtk_print_context_get_height(context); cairo_set_source_rgb(cr, 0, 0, 0); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.2); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_move_to(cr, 0, 0); pango_layout_set_width(dinfo->layout, width * PANGO_SCALE); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_LEFT); pango_layout_set_ellipsize(dinfo->layout, FALSE); pango_layout_set_justify(dinfo->layout, FALSE); if (printing_prefs.print_page_header) add_page_header(dinfo, cr, width, page_nr); count = 0; /* the actual line counter for the current page, might be different from * dinfo->cur_line due to possible line breaks */ while (count < dinfo->lines_per_page) { gchar c = 'a'; gint style = -1; PangoAttrList *layout_attr; PangoAttribute *attr; gint colours[3] = { 0 }; gboolean add_linenumber = TRUE; gboolean at_eol; while (count < dinfo->lines_per_page && c != '\0') { at_eol = FALSE; g_string_erase(str, 0, str->len); /* clear the string */ /* line numbers */ if (printing_prefs.print_line_numbers && add_linenumber) { /* if we had a wrapped line on the last page which needs to be continued, don't * add a line number */ if (dinfo->long_line) { add_linenumber = FALSE; } else { gchar *line_number = NULL; gint cur_line_number_margin = get_line_numbers_arity(dinfo->cur_line + 1); gchar *fill = g_strnfill( dinfo->max_line_number_margin - cur_line_number_margin - 1, ' '); line_number = g_strdup_printf("%s%d ", fill, dinfo->cur_line + 1); g_string_append(str, line_number); dinfo->cur_line++; /* increase document line */ add_linenumber = FALSE; style = STYLE_LINENUMBER; c = 'a'; /* dummy value */ g_free(fill); g_free(line_number); } } /* data */ else { style = sci_get_style_at(dinfo->doc->editor->sci, dinfo->cur_pos); c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c == '\0' || style == -1) { /* if c gets 0, we are probably out of document boundaries, * so stop to break out of outer loop */ count = dinfo->lines_per_page; break; } dinfo->cur_pos++; /* convert tabs to spaces which seems to be better than using Pango tabs */ if (c == '\t') { gint tab_width = sci_get_tab_width(editor->sci); gchar *s = g_strnfill(tab_width, ' '); g_string_append(str, s); g_free(s); } /* don't add line breaks, they are handled manually below */ else if (c == '\r' || c == '\n') { gchar c_next = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); at_eol = TRUE; if (c == '\r' && c_next == '\n') dinfo->cur_pos++; /* skip LF part of CR/LF */ } else { g_string_append_c(str, c); /* finally add the character */ /* handle UTF-8: since we add char by char (better: byte by byte), we need to * keep UTF-8 characters together(e.g. two bytes for one character) * the input is always UTF-8 and c is signed, so all non-Ascii * characters are less than 0 and consist of all bytes less than 0. * style doesn't change since it is only one character with multiple bytes. */ while (c < 0) { c = sci_get_char_at(dinfo->doc->editor->sci, dinfo->cur_pos); if (c < 0) { /* only add the byte when it is part of the UTF-8 character * otherwise we could add e.g. a '\n' and it won't be visible in the * printed document */ g_string_append_c(str, c); dinfo->cur_pos++; } } } } if (! at_eol) { /* set text */ pango_layout_set_text(dinfo->layout, str->str, -1); /* attributes */ layout_attr = pango_attr_list_new(); /* foreground colour */ get_rgb_values(dinfo->styles[style][FORE], &colours[0], &colours[1], &colours[2]); attr = pango_attr_foreground_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* background colour */ get_rgb_values(dinfo->styles[style][BACK], &colours[0], &colours[1], &colours[2]); attr = pango_attr_background_new(colours[0], colours[1], colours[2]); ADD_ATTR(layout_attr, attr); /* bold text */ if (dinfo->styles[style][BOLD]) { attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); ADD_ATTR(layout_attr, attr); } /* italic text */ if (dinfo->styles[style][ITALIC]) { attr = pango_attr_style_new(PANGO_STYLE_ITALIC); ADD_ATTR(layout_attr, attr); } pango_layout_set_attributes(dinfo->layout, layout_attr); pango_layout_context_changed(dinfo->layout); pango_attr_list_unref(layout_attr); } cairo_get_current_point(cr, &x, &y); /* normal line break at eol character in document */ if (at_eol) { /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, 0, y + (gdouble)layout_h / PANGO_SCALE);*/ cairo_move_to(cr, 0, y + dinfo->line_height); count++; /* we added a new document line so request a new line number */ add_linenumber = TRUE; } else { gint x_offset = 0; /* maybe we need to force a line break because of too long line */ if (x >= (width - dinfo->font_width)) { /* don't start the line at horizontal origin because we need to skip the * line number margin */ if (printing_prefs.print_line_numbers) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; } /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/ /*cairo_move_to(cr, x_offset, y + (gdouble)layout_h / PANGO_SCALE);*/ /* this is faster but not exactly the same as above */ cairo_move_to(cr, x_offset, y + dinfo->line_height); cairo_get_current_point(cr, &x, &y); count++; } if (count < dinfo->lines_per_page) { /* str->len is counted in bytes not characters, so use g_utf8_strlen() */ x_offset = (g_utf8_strlen(str->str, -1) * dinfo->font_width); if (dinfo->long_line && count == 0) { x_offset = (dinfo->max_line_number_margin + 1) * dinfo->font_width; dinfo->long_line = FALSE; } pango_cairo_show_layout(cr, dinfo->layout); cairo_move_to(cr, x + x_offset, y); } else /* we are on a wrapped line but we are out of lines on this page, so continue * the current line on the next page and remember to continue in current line */ dinfo->long_line = TRUE; } } } if (printing_prefs.print_line_numbers) { /* print a thin line between the line number margin and the data */ gint y_start = 0; if (printing_prefs.print_page_header) y_start = (dinfo->line_height * 3) - 2; /* "- 2": to connect the line number line to * the page header frame */ cairo_set_line_width(cr, 0.3); cairo_move_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y_start); cairo_line_to(cr, (dinfo->max_line_number_margin * dinfo->font_width) + 1, y + dinfo->line_height); /* y is last added line, we reuse it */ cairo_stroke(cr); } if (printing_prefs.print_page_numbers) { gchar *line = g_strdup_printf("<small>- %d -</small>", page_nr + 1); pango_layout_set_markup(dinfo->layout, line, -1); pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_CENTER); cairo_move_to(cr, 0, height - dinfo->line_height); pango_cairo_show_layout(cr, dinfo->layout); g_free(line); #ifdef GEANY_PRINT_DEBUG cairo_set_line_width(cr, 0.3); cairo_move_to(cr, 0, height - (1.25 * dinfo->line_height)); cairo_line_to(cr, width - 1, height - (1.25 * dinfo->line_height)); cairo_stroke(cr); #endif } g_string_free(str, TRUE); }
static void text_entry_update_layout(struct text_entry *entry) { char *text; PangoAttrList *attr_list; assert(entry->cursor <= (strlen(entry->text) + (entry->preedit.text ? strlen(entry->preedit.text) : 0))); if (entry->preedit.text) { text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1); strncpy(text, entry->text, entry->cursor); strcpy(text + entry->cursor, entry->preedit.text); strcpy(text + entry->cursor + strlen(entry->preedit.text), entry->text + entry->cursor); } else { text = strdup(entry->text); } if (entry->cursor != entry->anchor) { int start_index = MIN(entry->cursor, entry->anchor); int end_index = MAX(entry->cursor, entry->anchor); PangoAttribute *attr; attr_list = pango_attr_list_copy(entry->preedit.attr_list); if (!attr_list) attr_list = pango_attr_list_new(); attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert(attr_list, attr); attr = pango_attr_foreground_new(65535, 65535, 65535); attr->start_index = start_index; attr->end_index = end_index; pango_attr_list_insert(attr_list, attr); } else { attr_list = pango_attr_list_ref(entry->preedit.attr_list); } if (entry->preedit.text && !entry->preedit.attr_list) { PangoAttribute *attr; if (!attr_list) attr_list = pango_attr_list_new(); attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); attr->start_index = entry->cursor; attr->end_index = entry->cursor + strlen(entry->preedit.text); pango_attr_list_insert(attr_list, attr); } if (entry->layout) { pango_layout_set_text(entry->layout, text, -1); pango_layout_set_attributes(entry->layout, attr_list); } free(text); pango_attr_list_unref(attr_list); }
static gboolean span_parse_func (MarkupData *md, OpenTag *tag, const gchar **names, const gchar **values, GMarkupParseContext *context, GError **error) { int line_number, char_number; int i; const char *family = NULL; const char *size = NULL; const char *style = NULL; const char *weight = NULL; const char *variant = NULL; const char *stretch = NULL; const char *desc = NULL; const char *foreground = NULL; const char *background = NULL; const char *underline = NULL; const char *underline_color = NULL; const char *strikethrough = NULL; const char *strikethrough_color = NULL; const char *rise = NULL; const char *letter_spacing = NULL; const char *lang = NULL; const char *fallback = NULL; const char *gravity = NULL; const char *gravity_hint = NULL; g_markup_parse_context_get_position (context, &line_number, &char_number); #define CHECK_DUPLICATE(var) G_STMT_START{ \ if ((var) != NULL) { \ g_set_error (error, G_MARKUP_ERROR, \ G_MARKUP_ERROR_INVALID_CONTENT, \ _("Attribute '%s' occurs twice on <span> tag " \ "on line %d char %d, may only occur once"), \ names[i], line_number, char_number); \ return FALSE; \ }}G_STMT_END #define CHECK_ATTRIBUTE2(var, name) \ if (attr_strcmp (names[i], (name)) == 0) { \ CHECK_DUPLICATE (var); \ (var) = values[i]; \ found = TRUE; \ break; \ } #define CHECK_ATTRIBUTE(var) CHECK_ATTRIBUTE2 (var, G_STRINGIFY (var)) i = 0; while (names[i]) { gboolean found = FALSE; switch (names[i][0]) { case 'f': CHECK_ATTRIBUTE (fallback); CHECK_ATTRIBUTE2(desc, "font"); CHECK_ATTRIBUTE2(desc, "font_desc"); CHECK_ATTRIBUTE2(family, "face"); CHECK_ATTRIBUTE2(family, "font_family"); CHECK_ATTRIBUTE2(size, "font_size"); CHECK_ATTRIBUTE2(stretch, "font_stretch"); CHECK_ATTRIBUTE2(style, "font_style"); CHECK_ATTRIBUTE2(variant, "font_variant"); CHECK_ATTRIBUTE2(weight, "font_weight"); CHECK_ATTRIBUTE (foreground); CHECK_ATTRIBUTE2 (foreground, "fgcolor"); break; case 's': CHECK_ATTRIBUTE (size); CHECK_ATTRIBUTE (stretch); CHECK_ATTRIBUTE (strikethrough); CHECK_ATTRIBUTE (strikethrough_color); CHECK_ATTRIBUTE (style); break; case 'g': CHECK_ATTRIBUTE (gravity); CHECK_ATTRIBUTE (gravity_hint); break; case 'l': CHECK_ATTRIBUTE (lang); CHECK_ATTRIBUTE (letter_spacing); break; case 'u': CHECK_ATTRIBUTE (underline); CHECK_ATTRIBUTE (underline_color); break; default: CHECK_ATTRIBUTE (background); CHECK_ATTRIBUTE2 (background, "bgcolor"); CHECK_ATTRIBUTE2(foreground, "color"); CHECK_ATTRIBUTE (rise); CHECK_ATTRIBUTE (variant); CHECK_ATTRIBUTE (weight); break; } if (!found) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, _("Attribute '%s' is not allowed on the <span> tag " "on line %d char %d"), names[i], line_number, char_number); return FALSE; } ++i; } /* Parse desc first, then modify it with other font-related attributes. */ if (G_UNLIKELY (desc)) { PangoFontDescription *parsed; parsed = pango_font_description_from_string (desc); if (parsed) { add_attribute (tag, pango_attr_font_desc_new (parsed)); if (tag) open_tag_set_absolute_font_size (tag, pango_font_description_get_size (parsed)); pango_font_description_free (parsed); } } if (G_UNLIKELY (family)) { add_attribute (tag, pango_attr_family_new (family)); } if (G_UNLIKELY (size)) { if (g_ascii_isdigit (*size)) { const char *end; gint n; /* cap size from the top at an arbitrary 2048 */ #define MAX_SIZE (2048 * PANGO_SCALE) if ((end = size, !pango_scan_int (&end, &n)) || *end != '\0' || n < 0 || n > MAX_SIZE) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Value of 'size' attribute on <span> tag on line %d " "could not be parsed; should be an integer less than %d, or a " "string such as 'small', not '%s'"), line_number, MAX_SIZE+1, size); goto error; } add_attribute (tag, pango_attr_size_new (n)); if (tag) open_tag_set_absolute_font_size (tag, n); } else if (strcmp (size, "smaller") == 0) { if (tag) { tag->scale_level_delta -= 1; tag->scale_level -= 1; } } else if (strcmp (size, "larger") == 0) { if (tag) { tag->scale_level_delta += 1; tag->scale_level += 1; } } else if (parse_absolute_size (tag, size)) ; /* nothing */ else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("Value of 'size' attribute on <span> tag on line %d " "could not be parsed; should be an integer, or a " "string such as 'small', not '%s'"), line_number, size); goto error; } } if (G_UNLIKELY (style)) { PangoStyle pango_style; if (pango_parse_style (style, &pango_style, FALSE)) add_attribute (tag, pango_attr_style_new (pango_style)); else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("'%s' is not a valid value for the 'style' attribute " "on <span> tag, line %d; valid values are " "'normal', 'oblique', 'italic'"), style, line_number); goto error; } } if (G_UNLIKELY (weight)) { PangoWeight pango_weight; if (pango_parse_weight (weight, &pango_weight, FALSE)) add_attribute (tag, pango_attr_weight_new (pango_weight)); else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("'%s' is not a valid value for the 'weight' " "attribute on <span> tag, line %d; valid " "values are for example 'light', 'ultrabold' or a number"), weight, line_number); goto error; } } if (G_UNLIKELY (variant)) { PangoVariant pango_variant; if (pango_parse_variant (variant, &pango_variant, FALSE)) add_attribute (tag, pango_attr_variant_new (pango_variant)); else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("'%s' is not a valid value for the 'variant' " "attribute on <span> tag, line %d; valid values are " "'normal', 'smallcaps'"), variant, line_number); goto error; } } if (G_UNLIKELY (stretch)) { PangoStretch pango_stretch; if (pango_parse_stretch (stretch, &pango_stretch, FALSE)) add_attribute (tag, pango_attr_stretch_new (pango_stretch)); else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, _("'%s' is not a valid value for the 'stretch' " "attribute on <span> tag, line %d; valid " "values are for example 'condensed', " "'ultraexpanded', 'normal'"), stretch, line_number); goto error; } } if (G_UNLIKELY (foreground)) { PangoColor color; if (!span_parse_color ("foreground", foreground, &color, line_number, error)) goto error; add_attribute (tag, pango_attr_foreground_new (color.red, color.green, color.blue)); } if (G_UNLIKELY (background)) { PangoColor color; if (!span_parse_color ("background", background, &color, line_number, error)) goto error; add_attribute (tag, pango_attr_background_new (color.red, color.green, color.blue)); } if (G_UNLIKELY (underline)) { PangoUnderline ul = PANGO_UNDERLINE_NONE; if (!span_parse_enum ("underline", underline, PANGO_TYPE_UNDERLINE, &ul, line_number, error)) goto error; add_attribute (tag, pango_attr_underline_new (ul)); } if (G_UNLIKELY (underline_color)) { PangoColor color; if (!span_parse_color ("underline_color", underline_color, &color, line_number, error)) goto error; add_attribute (tag, pango_attr_underline_color_new (color.red, color.green, color.blue)); } if (G_UNLIKELY (gravity)) { PangoGravity gr = PANGO_GRAVITY_SOUTH; if (!span_parse_enum ("gravity", gravity, PANGO_TYPE_GRAVITY, &gr, line_number, error)) goto error; add_attribute (tag, pango_attr_gravity_new (gr)); } if (G_UNLIKELY (gravity_hint)) { PangoGravityHint hint = PANGO_GRAVITY_HINT_NATURAL; if (!span_parse_enum ("gravity_hint", gravity_hint, PANGO_TYPE_GRAVITY_HINT, &hint, line_number, error)) goto error; add_attribute (tag, pango_attr_gravity_hint_new (hint)); } if (G_UNLIKELY (strikethrough)) { gboolean b = FALSE; if (!span_parse_boolean ("strikethrough", strikethrough, &b, line_number, error)) goto error; add_attribute (tag, pango_attr_strikethrough_new (b)); } if (G_UNLIKELY (strikethrough_color)) { PangoColor color; if (!span_parse_color ("strikethrough_color", strikethrough_color, &color, line_number, error)) goto error; add_attribute (tag, pango_attr_strikethrough_color_new (color.red, color.green, color.blue)); } if (G_UNLIKELY (fallback)) { gboolean b = FALSE; if (!span_parse_boolean ("fallback", fallback, &b, line_number, error)) goto error; add_attribute (tag, pango_attr_fallback_new (b)); } if (G_UNLIKELY (rise)) { gint n = 0; if (!span_parse_int ("rise", rise, &n, line_number, error)) goto error; add_attribute (tag, pango_attr_rise_new (n)); } if (G_UNLIKELY (letter_spacing)) { gint n = 0; if (!span_parse_int ("letter_spacing", letter_spacing, &n, line_number, error)) goto error; add_attribute (tag, pango_attr_letter_spacing_new (n)); } if (G_UNLIKELY (lang)) { add_attribute (tag, pango_attr_language_new (pango_language_from_string (lang))); } return TRUE; error: return FALSE; }
static void _fcitx_im_context_update_formatted_preedit_cb(FcitxClient* im, GPtrArray* array, int cursor_pos, void* user_data) { FcitxLog(LOG_LEVEL, "_fcitx_im_context_commit_string_cb"); FcitxIMContext* context = FCITX_IM_CONTEXT(user_data); gboolean visible = false; if (context->preedit_string != NULL) { if (strlen(context->preedit_string) != 0) visible = true; g_free(context->preedit_string); context->preedit_string = NULL; } if (context->attrlist != NULL) { pango_attr_list_unref(context->attrlist); } context->attrlist = pango_attr_list_new(); GString* gstr = g_string_new(NULL); int i = 0; for (i = 0; i < array->len; i++) { size_t bytelen = strlen(gstr->str); FcitxPreeditItem* preedit = g_ptr_array_index(array, i); const gchar* s = preedit->string; gint type = preedit->type; PangoAttribute *pango_attr = NULL; if ((type & MSG_NOUNDERLINE) == 0) { pango_attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); pango_attr->start_index = bytelen; pango_attr->end_index = bytelen + strlen(s); pango_attr_list_insert(context->attrlist, pango_attr); } if (type & MSG_HIGHLIGHT) { gboolean hasColor; GdkColor fg; GdkColor bg; if (context->client_window) { GtkWidget *widget; gdk_window_get_user_data (context->client_window, (gpointer *)&widget); if (GTK_IS_WIDGET(widget)) { hasColor = true; GtkStyle* style = gtk_widget_get_style(widget); fg = style->text[GTK_STATE_SELECTED]; bg = style->bg[GTK_STATE_SELECTED]; } } if (!hasColor) { fg.red = 0xffff; fg.green = 0xffff; fg.blue = 0xffff; bg.red = 0x43ff; bg.green = 0xacff; bg.blue = 0xe8ff; } pango_attr = pango_attr_foreground_new(fg.red, fg.green, fg.blue); pango_attr->start_index = bytelen; pango_attr->end_index = bytelen + strlen(s); pango_attr_list_insert(context->attrlist, pango_attr); pango_attr = pango_attr_background_new(bg.red, bg.green, bg.blue); pango_attr->start_index = bytelen; pango_attr->end_index = bytelen + strlen(s); pango_attr_list_insert(context->attrlist, pango_attr); } gstr = g_string_append(gstr, s); } gchar* str = g_string_free(gstr, FALSE); context->preedit_string = g_strdup(str); char* tempstr = g_strndup(str, cursor_pos); context->cursor_pos = fcitx_utf8_strlen(tempstr); g_free(tempstr); gboolean new_visible = false; if (context->preedit_string != NULL) { if (strlen(context->preedit_string) != 0) new_visible = true; } gboolean flag = new_visible != visible; if (new_visible) { if (flag) { /* invisible => visible */ g_signal_emit(context, _signal_preedit_start_id, 0); } g_signal_emit(context, _signal_preedit_changed_id, 0); } else { if (flag) { /* visible => invisible */ g_signal_emit(context, _signal_preedit_changed_id, 0); g_signal_emit(context, _signal_preedit_end_id, 0); } else { /* still invisible */ /* do nothing */ } } g_signal_emit(context, _signal_preedit_changed_id, 0); }