From 4d8784cf85a5108340a2b2a684e2bd1d9f77269d Mon Sep 17 00:00:00 2001 From: Dave Davenport Date: Wed, 31 May 2017 11:05:45 +0200 Subject: Port fixes from icon-cleanup branch. - Thread for fetching icons for drun. - Fixed placing of icons instead of adding place-holder token that can mis-render. - Give textbox TB_ICON flag. --- source/dialogs/drun.c | 115 +++++++++++++++++++++++----------------------- source/dialogs/window.c | 14 ++---- source/view.c | 14 ++---- source/widgets/listview.c | 1 + source/widgets/textbox.c | 42 ++++++++--------- 5 files changed, 84 insertions(+), 102 deletions(-) (limited to 'source') diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c index 907d5f2e..a10057e6 100644 --- a/source/dialogs/drun.c +++ b/source/dialogs/drun.c @@ -89,8 +89,9 @@ typedef struct unsigned int cmd_list_length_actual; unsigned int history_length; // List of disabled entries. - GHashTable *disabled_entries; - unsigned int disabled_entries_length; + GHashTable *disabled_entries; + unsigned int disabled_entries_length; + GThread *thread; } DRunModePrivateData; struct RegexEvalArg @@ -418,6 +419,47 @@ static void get_apps ( DRunModePrivateData *pd ) TICK_N ( "Get Desktop apps (system dirs)" ); } +static void drun_icon_fetch ( gpointer data ) +{ + // as long as dr->icon is updated atomicly.. (is a pointer write atomic?) + // this should be fine running in another thread. + GTimer *t = g_timer_new (); + DRunModePrivateData *pd = (DRunModePrivateData*)data; + for ( size_t i = 0; i < pd->cmd_list_length; i++ ) { + DRunModeEntry *dr = &( pd->entry_list[i] ); + if ( dr->icon_name == NULL ) + continue; + gchar *icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, NULL, "Applications", dr->icon_name, 32, 1, TRUE ); + if ( icon_path == NULL ) { + g_free(dr->icon_name); + dr->icon_name = NULL; + continue; + } + else + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Found Icon %s(%d): %s", dr->icon_name, 32, icon_path ); + + if ( g_str_has_suffix ( icon_path, ".png" ) ) + dr->icon = cairo_image_surface_create_from_png(icon_path); + else if ( g_str_has_suffix ( icon_path, ".svg" ) ) + dr->icon = cairo_image_surface_create_from_svg(icon_path, 32); + else { + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Icon type not yet supported: %s", icon_path ); + char *r = dr->icon_name; + dr->icon_name = NULL; + g_free(r); + } + g_free(icon_path); + // if ( (i%100) == 99 ) + { + + rofi_view_reload(); + } + } + rofi_view_reload(); + g_log ( G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "elapsed: %f\n" , g_timer_elapsed ( t, NULL)); + g_timer_destroy ( t ); +} + static int drun_mode_init ( Mode *sw ) { if ( mode_get_private_data ( sw ) == NULL ) { @@ -426,6 +468,7 @@ static int drun_mode_init ( Mode *sw ) mode_set_private_data ( sw, (void *) pd ); pd->xdg_context = nk_xdg_theme_context_new (); get_apps ( pd ); + pd->thread = g_thread_new ( "icon-fetch-drun", drun_icon_fetch, pd ); } return TRUE; } @@ -470,6 +513,10 @@ static ModeMode drun_mode_result ( Mode *sw, int mretv, char **input, unsigned i } else if ( ( mretv & MENU_ENTRY_DELETE ) && selected_line < rmpd->cmd_list_length ) { if ( selected_line < rmpd->history_length ) { + if ( rmpd->thread ) { + g_thread_join ( rmpd->thread ); + rmpd->thread = NULL; + } delete_entry_history ( &( rmpd->entry_list[selected_line] ) ); drun_entry_clear ( &( rmpd->entry_list[selected_line] ) ); memmove ( &( rmpd->entry_list[selected_line] ), &rmpd->entry_list[selected_line + 1], @@ -484,6 +531,10 @@ static void drun_mode_destroy ( Mode *sw ) { DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( sw ); if ( rmpd != NULL ) { + if ( rmpd->thread ){ + g_thread_join ( rmpd->thread ); + rmpd->thread = NULL; + } for ( size_t i = 0; i < rmpd->cmd_list_length; i++ ) { drun_entry_clear ( &( rmpd->entry_list[i] ) ); } @@ -508,13 +559,12 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in } /* Free temp storage. */ DRunModeEntry *dr = &( pd->entry_list[selected_line] ); - /* We use '\t' as the icon placeholder for now */ if ( dr->generic_name == NULL ) { - return g_markup_printf_escaped ( "\uFFFC%s", dr->name ); + return g_markup_printf_escaped ( "%s", dr->name ); } else { - return g_markup_printf_escaped ( "\uFFFC%s (%s)", - dr->name, dr->generic_name ); + return g_markup_printf_escaped ( "%s (%s)", dr->name, + dr->generic_name ); } } @@ -522,58 +572,7 @@ static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line, { DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw ); g_return_val_if_fail ( pd->entry_list != NULL, NULL ); - DRunModeEntry *dr = &( pd->entry_list[selected_line] ); - if ( dr->icon != NULL ) { - return dr->icon; - } - if ( dr->icon_name == NULL ) { - return NULL; - } - - gchar *icon_path; - - if ( g_path_is_absolute ( dr->icon_name ) ) { - icon_path = dr->icon_name; - } - else { - const gchar *name = dr->icon_name; - if ( g_str_has_suffix ( name, ".png" ) || g_str_has_suffix ( name, ".svg" ) || g_str_has_suffix ( name, ".xpm" ) ) { - /* We truncate the extension if the .desktop file is not compliant - * We cannot just strip at '.' because D-Bus-styled names are now common. - */ - gchar *c = g_utf8_strrchr ( name, -1, '.' ); - g_assert_nonnull ( c ); - *c = '\0'; - c = g_utf8_strchr ( name, -1, G_DIR_SEPARATOR ); - if ( c != NULL ) { - /* And just in case, we strip any path component too */ - *c = '\0'; - name = ++c; - } - } - icon_path = nk_xdg_theme_get_icon ( pd->xdg_context, config.drun_icon_theme, "Applications", name, height, 1, TRUE ); - if ( icon_path != NULL ) { - g_debug ( "Found Icon %s(%d): %s", name, height, icon_path ); - } - g_free ( dr->icon_name ); - } - dr->icon_name = NULL; - - if ( icon_path == NULL ) { - return NULL; - } - - if ( g_str_has_suffix ( icon_path, ".png" ) ) { - dr->icon = cairo_image_surface_create_from_png ( icon_path ); - } - else if ( g_str_has_suffix ( icon_path, ".svg" ) ) { - dr->icon = cairo_image_surface_create_from_svg ( icon_path, height ); - } - else { - g_debug ( "Icon type not yet supported: %s", icon_path ); - } - - g_free ( icon_path ); + DRunModeEntry *dr = &( pd->entry_list[selected_line] ); return dr->icon; } diff --git a/source/dialogs/window.c b/source/dialogs/window.c index 80cf880c..d19e1c61 100644 --- a/source/dialogs/window.c +++ b/source/dialogs/window.c @@ -301,18 +301,18 @@ static client* window_client ( ModeModePrivateData *pd, xcb_window_t win ) c->title = window_get_text_prop ( c->window, xcb->ewmh._NET_WM_NAME ); if ( c->title == NULL ) { - c->title = rofi_escape_markup ( window_get_text_prop ( c->window, XCB_ATOM_WM_NAME ) ); + c->title = window_get_text_prop ( c->window, XCB_ATOM_WM_NAME ); } pd->title_len = MAX ( c->title ? g_utf8_strlen ( c->title, -1 ) : 0, pd->title_len ); - c->role = rofi_escape_markup ( window_get_text_prop ( c->window, netatoms[WM_WINDOW_ROLE] ) ); + c->role = window_get_text_prop ( c->window, netatoms[WM_WINDOW_ROLE] ); pd->role_len = MAX ( c->role ? g_utf8_strlen ( c->role, -1 ) : 0, pd->role_len ); cky = xcb_icccm_get_wm_class ( xcb->connection, c->window ); xcb_icccm_get_wm_class_reply_t wcr; if ( xcb_icccm_get_wm_class_reply ( xcb->connection, cky, &wcr, NULL ) ) { - c->class = rofi_escape_markup ( rofi_latin_to_utf8_strdup ( wcr.class_name, -1 ) ); - c->name = rofi_escape_markup ( rofi_latin_to_utf8_strdup ( wcr.instance_name, -1 ) ); + c->class = rofi_latin_to_utf8_strdup ( wcr.class_name, -1 ); + c->name = rofi_latin_to_utf8_strdup ( wcr.instance_name, -1 ); pd->name_len = MAX ( c->name ? g_utf8_strlen ( c->name, -1 ) : 0, pd->name_len ); xcb_icccm_get_wm_class_reply_wipe ( &wcr ); } @@ -692,11 +692,6 @@ static gboolean helper_eval_cb ( const GMatchInfo *info, GString *str, gpointer if ( match[1] == 'w' ) { helper_eval_add_str ( str, d->c->wmdesktopstr, l, d->pd->wmdn_len ); } - else if ( match[1] == 'i' ) { - if ( config.show_icons ) { - g_string_append ( str, "\uFFFC" ); - } - } else if ( match[1] == 'c' ) { helper_eval_add_str ( str, d->c->class, l, d->pd->clf_len ); } @@ -728,7 +723,6 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in if ( c == NULL ) { return get_entry ? g_strdup ( "Window has fanished" ) : NULL; } - *state |= MARKUP; if ( c->demands ) { *state |= URGENT; } diff --git a/source/view.c b/source/view.c index fc5a4fe6..6d2b7aea 100644 --- a/source/view.c +++ b/source/view.c @@ -906,19 +906,11 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB else{ list = pango_attr_list_new (); } - int icon_height = textbox_get_font_height ( t ); + int icon_height = textbox_get_font_height ( t ); - const gchar *visible_text = textbox_get_visible_text ( t ); - const gchar *icon_placeholder = g_utf8_strchr ( visible_text, -1, 0xFFFC ); - if ( icon_placeholder != NULL ) { - cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height ); - textbox_icon ( t, icon ); + cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height ); + textbox_icon ( t, icon ); - textbox_set_icon_index ( t, g_utf8_pointer_to_offset ( visible_text, icon_placeholder ) ); - } - else { - textbox_set_icon_index ( t, -1 ); - } if ( state->tokens && config.show_match ) { ThemeHighlight th = { HL_BOLD | HL_UNDERLINE, { 0.0, 0.0, 0.0, 0.0 } }; th = rofi_theme_get_highlight ( WIDGET ( t ), "highlight", th ); diff --git a/source/widgets/listview.c b/source/widgets/listview.c index 8d048bb6..5b82a8db 100644 --- a/source/widgets/listview.c +++ b/source/widgets/listview.c @@ -243,6 +243,7 @@ static void listview_recompute_elements ( listview *lv ) char *name = g_strjoin ( ".", lv->listview_name, "element", NULL ); for ( unsigned int i = lv->cur_elements; i < newne; i++ ) { TextboxFlags flags = ( lv->multi_select ) ? TB_INDICATOR : 0; + flags |= (config.show_icons)? TB_ICON:0; lv->boxes[i] = textbox_create_full ( WIDGET_TYPE_LISTVIEW_ELEMENT, name, flags, NORMAL, "" ); widget_set_trigger_action_handler ( WIDGET ( lv->boxes[i] ), listview_element_trigger_action, lv ); } diff --git a/source/widgets/textbox.c b/source/widgets/textbox.c index ee51367a..b2fcbded 100644 --- a/source/widgets/textbox.c +++ b/source/widgets/textbox.c @@ -143,6 +143,9 @@ textbox* textbox_create_full ( WidgetType type, const char *name, TextboxFlags f tb->changed = FALSE; tb->layout = pango_layout_new ( p_context ); + if ( (tb->flags&TB_ICON) == TB_ICON) { + tb->left_offset = 1.2*textbox_get_estimated_char_height(); + } textbox_font ( tb, tbft ); tb->metrics = p_metrics; @@ -186,7 +189,6 @@ textbox* textbox_create_full ( WidgetType type, const char *name, TextboxFlags f tb->widget.trigger_action = textbox_editable_trigger_action; } - tb->icon_index = -1; //Don't draw the icon by default // Enabled by default tb->widget.enabled = rofi_theme_get_boolean ( WIDGET ( tb ), "enabled", TRUE ); @@ -269,12 +271,6 @@ void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list ) pango_layout_set_attributes ( tb->layout, list ); } -void textbox_set_icon_index ( textbox *tb, int index ) -{ - tb->icon_index = index; - widget_queue_redraw ( WIDGET ( tb ) ); -} - // set the default text to display void textbox_text ( textbox *tb, const char *text ) { @@ -315,10 +311,9 @@ void textbox_icon ( textbox *tb, cairo_surface_t *icon ) // within the parent handled auto width/height modes void textbox_moveresize ( textbox *tb, int x, int y, int w, int h ) { - unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; + unsigned int offset = tb->left_offset + ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; if ( tb->flags & TB_AUTOWIDTH ) { pango_layout_set_width ( tb->layout, -1 ); - unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; w = textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( WIDGET ( tb ) ) + offset; } else { @@ -371,7 +366,7 @@ static void textbox_free ( widget *wid ) static void textbox_draw ( widget *wid, cairo_t *draw ) { textbox *tb = (textbox *) wid; - unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; + unsigned int offset = tb->left_offset + (( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0); if ( tb->changed ) { __textbox_update_pango_text ( tb ); @@ -383,21 +378,22 @@ static void textbox_draw ( widget *wid, cairo_t *draw ) int y = top + ( pango_font_metrics_get_ascent ( tb->metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE; // draw Icon - int iconheight = textbox_get_font_height ( tb ); - int translatex = ( textbox_get_estimated_char_height () * tb->icon_index / 2 ); - if ( tb->icon != NULL && tb->icon_index != -1 ) { - cairo_save ( draw ); + if ( (tb->flags|TB_ICON) == TB_ICON && tb->icon != NULL ) { + int iconheight = textbox_get_font_height ( tb ); + int translatex = 0; + cairo_save(draw); /*int iconw = cairo_image_surface_get_width (tb->icon);*/ - int iconh = cairo_image_surface_get_height ( tb->icon ); - double scale = (double) iconheight / iconh; + int iconh = cairo_image_surface_get_height (tb->icon); + double scale = (double)iconheight / iconh; - cairo_translate ( draw, translatex, 0 ); - cairo_scale ( draw, scale, scale ); - cairo_set_source_surface ( draw, tb->icon, x, y ); - cairo_paint ( draw ); - cairo_restore ( draw ); + cairo_translate(draw, translatex, 0); + cairo_scale(draw, scale, scale); + cairo_set_source_surface(draw, tb->icon, x, y); + cairo_paint(draw); + cairo_restore(draw); } + x+=offset; if ( tb->flags & TB_RIGHT ) { int line_width = 0; @@ -438,7 +434,7 @@ static void textbox_draw ( widget *wid, cairo_t *draw ) pango_cairo_show_layout ( draw, tb->layout ); if ( ( tb->flags & TB_INDICATOR ) == TB_INDICATOR && ( tb->tbft & ( SELECTED ) ) ) { - cairo_arc ( draw, DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * G_PI ); + cairo_arc ( draw, tb->left_offset + DOT_OFFSET / 2.0, tb->widget.h / 2.0, 2.0, 0, 2.0 * M_PI ); cairo_fill ( draw ); } } @@ -852,7 +848,7 @@ int textbox_get_estimated_height ( const textbox *tb, int eh ) int textbox_get_desired_width ( widget *wid ) { textbox *tb = (textbox *) wid; - unsigned int offset = ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; + unsigned int offset = tb->left_offset + ( tb->flags & TB_INDICATOR ) ? DOT_OFFSET : 0; if ( tb->flags & TB_AUTOWIDTH ) { return textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( wid ) + offset; } -- cgit v1.2.3