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.
This commit is contained in:
Dave Davenport 2017-05-31 11:05:45 +02:00
parent 8a6bdd827d
commit 4d8784cf85
6 changed files with 86 additions and 102 deletions

View File

@ -66,6 +66,7 @@ typedef struct
guint blink_timeout;
PangoFontMetrics *metrics;
int left_offset;
//
const char *theme_name;
} textbox;
@ -85,6 +86,7 @@ typedef enum
TB_WRAP = 1 << 21,
TB_PASSWORD = 1 << 22,
TB_INDICATOR = 1 << 23,
TB_ICON = 1<<24,
} TextboxFlags;
/**
* Flags indicating current state of the textbox.

View File

@ -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 ( "<span alpha=\"1\">\uFFFC</span>%s", dr->name );
return g_markup_printf_escaped ( "%s", dr->name );
}
else {
return g_markup_printf_escaped ( "<span alpha=\"1\">\uFFFC</span>%s <span weight='light' size='small'><i>(%s)</i></span>",
dr->name, dr->generic_name );
return g_markup_printf_escaped ( "%s <span weight='light' size='small'><i>(%s)</i></span>", 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;
}

View File

@ -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, "<span alpha=\"1\">\uFFFC</span>" );
}
}
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;
}

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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;
}