summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorDave Davenport <qball@gmpclient.org>2017-05-31 11:18:30 +0200
committerDave Davenport <qball@gmpclient.org>2017-05-31 11:18:30 +0200
commitd8b0e24b09e6e0aa9aaaf17e6ee9c92e0ebdc05e (patch)
treeed961b08bed65b4adc4ff14978282c2ad506d641 /source
parent9a6fd1c6c3d54c4a6db6ba7d15f317927f4036ec (diff)
parent4d8784cf85a5108340a2b2a684e2bd1d9f77269d (diff)
Merge remote-tracking branch 'origin/master' into barview
Diffstat (limited to 'source')
-rw-r--r--source/dialogs/combi.c13
-rw-r--r--source/dialogs/drun.c104
-rw-r--r--source/dialogs/window.c118
-rw-r--r--source/helper.c10
-rw-r--r--source/mode.c12
-rw-r--r--source/view.c4
-rw-r--r--source/widgets/listview.c1
-rw-r--r--source/widgets/textbox.c43
-rw-r--r--source/x11-helper.c24
-rw-r--r--source/xrmoptions.c5
10 files changed, 314 insertions, 20 deletions
diff --git a/source/dialogs/combi.c b/source/dialogs/combi.c
index 8fa4a438..5631c519 100644
--- a/source/dialogs/combi.c
+++ b/source/dialogs/combi.c
@@ -247,6 +247,18 @@ static char * combi_get_completion ( const Mode *sw, unsigned int index )
return NULL;
}
+static cairo_surface_t * combi_get_icon ( const Mode *sw, unsigned int index, int height )
+{
+ CombiModePrivateData *pd = mode_get_private_data ( sw );
+ for ( unsigned i = 0; i < pd->num_switchers; i++ ) {
+ if ( index >= pd->starts[i] && index < ( pd->starts[i] + pd->lengths[i] ) ) {
+ cairo_surface_t *icon = mode_get_icon ( pd->switchers[i].mode, index - pd->starts[i], height );
+ return icon;
+ }
+ }
+ return NULL;
+}
+
static char * combi_preprocess_input ( Mode *sw, const char *input )
{
CombiModePrivateData *pd = mode_get_private_data ( sw );
@@ -285,6 +297,7 @@ Mode combi_mode =
._token_match = combi_mode_match,
._get_completion = combi_get_completion,
._get_display_value = combi_mgrv,
+ ._get_icon = combi_get_icon,
._preprocess_input = combi_preprocess_input,
.private_data = NULL,
.free = NULL
diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c
index f17fa1ae..a10057e6 100644
--- a/source/dialogs/drun.c
+++ b/source/dialogs/drun.c
@@ -49,6 +49,7 @@
#include "widgets/textbox.h"
#include "history.h"
#include "dialogs/drun.h"
+#include "nkutils-xdg-theme.h"
#define DRUN_CACHE_FILE "rofi2.druncache"
@@ -61,31 +62,36 @@
typedef struct
{
/* Root */
- char *root;
+ char *root;
/* Path to desktop file */
- char *path;
+ char *path;
+ /* Icon stuff */
+ char *icon_name;
+ cairo_surface_t *icon;
/* Executable */
- char *exec;
+ char *exec;
/* Name of the Entry */
- char *name;
+ char *name;
/* Generic Name */
- char *generic_name;
+ char *generic_name;
#ifdef GET_CAT_PARSE_TIME
- char **categories;
+ char **categories;
#endif
- GKeyFile *key_file;
+ GKeyFile *key_file;
} DRunModeEntry;
typedef struct
{
- DRunModeEntry *entry_list;
- unsigned int cmd_list_length;
- unsigned int cmd_list_length_actual;
- unsigned int history_length;
+ NkXdgThemeContext *xdg_context;
+ DRunModeEntry *entry_list;
+ unsigned int cmd_list_length;
+ unsigned int cmd_list_length_actual;
+ unsigned int history_length;
// List of disabled entries.
GHashTable *disabled_entries;
unsigned int disabled_entries_length;
+ GThread *thread;
} DRunModePrivateData;
struct RegexEvalArg
@@ -279,6 +285,14 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c
#endif
pd->entry_list[pd->cmd_list_length].exec = g_key_file_get_string ( kf, "Desktop Entry", "Exec", NULL );
+ if ( config.show_icons ) {
+ pd->entry_list[pd->cmd_list_length].icon_name = g_key_file_get_locale_string ( kf, "Desktop Entry", "Icon", NULL, NULL );
+ }
+ else{
+ pd->entry_list[pd->cmd_list_length].icon_name = NULL;
+ }
+ pd->entry_list[pd->cmd_list_length].icon = NULL;
+
// Keep keyfile around.
pd->entry_list[pd->cmd_list_length].key_file = kf;
// We don't want to parse items with this id anymore.
@@ -405,13 +419,56 @@ 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 ) {
DRunModePrivateData *pd = g_malloc0 ( sizeof ( *pd ) );
pd->disabled_entries = g_hash_table_new_full ( g_str_hash, g_str_equal, g_free, NULL );
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;
}
@@ -419,6 +476,10 @@ static void drun_entry_clear ( DRunModeEntry *e )
{
g_free ( e->root );
g_free ( e->path );
+ if ( e->icon != NULL ) {
+ cairo_surface_destroy ( e->icon );
+ }
+ g_free ( e->icon_name );
g_free ( e->exec );
g_free ( e->name );
g_free ( e->generic_name );
@@ -452,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],
@@ -466,11 +531,16 @@ 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] ) );
}
g_hash_table_destroy ( rmpd->disabled_entries );
g_free ( rmpd->entry_list );
+ nk_xdg_theme_context_free ( rmpd->xdg_context );
g_free ( rmpd );
mode_set_private_data ( sw, NULL );
}
@@ -490,13 +560,22 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in
/* Free temp storage. */
DRunModeEntry *dr = &( pd->entry_list[selected_line] );
if ( dr->generic_name == NULL ) {
- return g_markup_escape_text ( dr->name, -1 );
+ return g_markup_printf_escaped ( "%s", dr->name );
}
else {
return g_markup_printf_escaped ( "%s <span weight='light' size='small'><i>(%s)</i></span>", dr->name,
dr->generic_name );
}
}
+
+static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line, int height )
+{
+ 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] );
+ return dr->icon;
+}
+
static char *drun_get_completion ( const Mode *sw, unsigned int index )
{
DRunModePrivateData *pd = (DRunModePrivateData *) mode_get_private_data ( sw );
@@ -572,6 +651,7 @@ Mode drun_mode =
._token_match = drun_token_match,
._get_completion = drun_get_completion,
._get_display_value = _get_display_value,
+ ._get_icon = _get_icon,
._preprocess_input = NULL,
.private_data = NULL,
.free = NULL
diff --git a/source/dialogs/window.c b/source/dialogs/window.c
index 535c2e72..d19e1c61 100644
--- a/source/dialogs/window.c
+++ b/source/dialogs/window.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
@@ -77,6 +78,8 @@ typedef struct
long hint_flags;
uint32_t wmdesktop;
char *wmdesktopstr;
+ cairo_surface_t *icon;
+ gboolean icon_checked;
} client;
// window lists
@@ -149,6 +152,9 @@ static void winlist_empty ( winlist *l )
while ( l->len > 0 ) {
client *c = l->data[--l->len];
if ( c != NULL ) {
+ if ( c->icon ) {
+ cairo_surface_destroy ( c->icon );
+ }
g_free ( c->title );
g_free ( c->class );
g_free ( c->name );
@@ -726,6 +732,116 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, in
return get_entry ? _generate_display_string ( rmpd, c ) : NULL;
}
+/**
+ * Icon code borrowed from https://github.com/olejorgenb/extract-window-icon
+ */
+static cairo_user_data_key_t data_key;
+
+/** Create a surface object from this image data.
+ * \param width The width of the image.
+ * \param height The height of the image
+ * \param data The image's data in ARGB format, will be copied by this function.
+ */
+static cairo_surface_t * draw_surface_from_data ( int width, int height, uint32_t *data )
+{
+ unsigned long int len = width * height;
+ unsigned long int i;
+ uint32_t *buffer = g_new0 ( uint32_t, len );
+ cairo_surface_t *surface;
+
+ /* Cairo wants premultiplied alpha, meh :( */
+ for ( i = 0; i < len; i++ ) {
+ uint8_t a = ( data[i] >> 24 ) & 0xff;
+ double alpha = a / 255.0;
+ uint8_t r = ( ( data[i] >> 16 ) & 0xff ) * alpha;
+ uint8_t g = ( ( data[i] >> 8 ) & 0xff ) * alpha;
+ uint8_t b = ( ( data[i] >> 0 ) & 0xff ) * alpha;
+ buffer[i] = ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
+ }
+
+ surface = cairo_image_surface_create_for_data ( (unsigned char *) buffer,
+ CAIRO_FORMAT_ARGB32,
+ width,
+ height,
+ width * 4 );
+ /* This makes sure that buffer will be freed */
+ cairo_surface_set_user_data ( surface, &data_key, buffer, g_free );
+
+ return surface;
+}
+static cairo_surface_t * ewmh_window_icon_from_reply ( xcb_get_property_reply_t *r, uint32_t preferred_size )
+{
+ uint32_t *data, *end, *found_data = 0;
+ uint32_t found_size = 0;
+
+ if ( !r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || r->length < 2 ) {
+ return 0;
+ }
+
+ data = (uint32_t *) xcb_get_property_value ( r );
+ if ( !data ) {
+ return 0;
+ }
+
+ end = data + r->length;
+
+ /* Goes over the icon data and picks the icon that best matches the size preference.
+ * In case the size match is not exact, picks the closest bigger size if present,
+ * closest smaller size otherwise.
+ */
+ while ( data + 1 < end ) {
+ /* check whether the data size specified by width and height fits into the array we got */
+ uint64_t data_size = (uint64_t) data[0] * data[1];
+ if ( data_size > (uint64_t) ( end - data - 2 ) ) {
+ break;
+ }
+
+ /* use the greater of the two dimensions to match against the preferred size */
+ uint32_t size = MAX ( data[0], data[1] );
+
+ /* pick the icon if it's a better match than the one we already have */
+ gboolean found_icon_too_small = found_size < preferred_size;
+ gboolean found_icon_too_large = found_size > preferred_size;
+ gboolean icon_empty = data[0] == 0 || data[1] == 0;
+ gboolean better_because_bigger = found_icon_too_small && size > found_size;
+ gboolean better_because_smaller = found_icon_too_large &&
+ size >= preferred_size && size < found_size;
+ if ( !icon_empty && ( better_because_bigger || better_because_smaller || found_size == 0 ) ) {
+ found_data = data;
+ found_size = size;
+ }
+
+ data += data_size + 2;
+ }
+
+ if ( !found_data ) {
+ return 0;
+ }
+
+ return draw_surface_from_data ( found_data[0], found_data[1], found_data + 2 );
+}
+/** Get NET_WM_ICON. */
+static cairo_surface_t * get_net_wm_icon ( xcb_window_t xid, uint32_t preferred_size )
+{
+ xcb_get_property_cookie_t cookie = xcb_get_property_unchecked (
+ xcb->connection, FALSE, xid,
+ xcb->ewmh._NET_WM_ICON, XCB_ATOM_CARDINAL, 0, UINT32_MAX );
+ xcb_get_property_reply_t *r = xcb_get_property_reply ( xcb->connection, cookie, NULL );
+ cairo_surface_t *surface = ewmh_window_icon_from_reply ( r, preferred_size );
+ free ( r );
+ return surface;
+}
+static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line, int size )
+{
+ ModeModePrivateData *rmpd = mode_get_private_data ( sw );
+ client *c = window_client ( rmpd, rmpd->ids->array[selected_line] );
+ if ( c->icon_checked == FALSE ) {
+ c->icon = get_net_wm_icon ( rmpd->ids->array[selected_line], size );
+ c->icon_checked = TRUE;
+ }
+ return c->icon;
+}
+
#include "mode-private.h"
Mode window_mode =
{
@@ -737,6 +853,7 @@ Mode window_mode =
._destroy = window_mode_destroy,
._token_match = window_match,
._get_display_value = _get_display_value,
+ ._get_icon = _get_icon,
._get_completion = NULL,
._preprocess_input = NULL,
.private_data = NULL,
@@ -752,6 +869,7 @@ Mode window_mode_cd =
._destroy = window_mode_destroy,
._token_match = window_match,
._get_display_value = _get_display_value,
+ ._get_icon = _get_icon,
._get_completion = NULL,
._preprocess_input = NULL,
.private_data = NULL,
diff --git a/source/helper.c b/source/helper.c
index f6b3b74d..5299ced3 100644
--- a/source/helper.c
+++ b/source/helper.c
@@ -730,6 +730,16 @@ char * rofi_latin_to_utf8_strdup ( const char *input, gssize length )
return g_convert_with_fallback ( input, length, "UTF-8", "latin1", "\uFFFD", NULL, &slength, NULL );
}
+gchar *rofi_escape_markup ( gchar *text )
+{
+ if ( text == NULL ) {
+ return NULL;
+ }
+ gchar *ret = g_markup_escape_text ( text, -1 );
+ g_free ( text );
+ return ret;
+}
+
char * rofi_force_utf8 ( const gchar *data, ssize_t length )
{
if ( data == NULL ) {
diff --git a/source/mode.c b/source/mode.c
index a7e552d3..5e070e3c 100644
--- a/source/mode.c
+++ b/source/mode.c
@@ -70,6 +70,18 @@ char * mode_get_display_value ( const Mode *mode, unsigned int selected_line, in
return mode->_get_display_value ( mode, selected_line, state, attribute_list, get_entry );
}
+cairo_surface_t * mode_get_icon ( const Mode *mode, unsigned int selected_line, int height )
+{
+ g_assert ( mode != NULL );
+
+ if ( mode->_get_icon != NULL ) {
+ return mode->_get_icon ( mode, selected_line, height );
+ }
+ else {
+ return NULL;
+ }
+}
+
char * mode_get_completion ( const Mode *mode, unsigned int selected_line )
{
g_assert ( mode != NULL );
diff --git a/source/view.c b/source/view.c
index 7250b2b9..5020eb00 100644
--- a/source/view.c
+++ b/source/view.c
@@ -906,6 +906,10 @@ 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 );
+
+ cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height );
+ textbox_icon ( t, icon );
if ( state->tokens && config.show_match ) {
ThemeHighlight th = { HL_BOLD | HL_UNDERLINE, { 0.0, 0.0, 0.0, 0.0 } };
diff --git a/source/widgets/listview.c b/source/widgets/listview.c
index af06001f..547df049 100644
--- a/source/widgets/listview.c
+++ b/source/widgets/listview.c
@@ -367,6 +367,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 c17ca575..8b9b0c47 100644
--- a/source/widgets/textbox.c
+++ b/source/widgets/textbox.c
@@ -144,6 +144,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;
@@ -315,13 +318,19 @@ void textbox_text ( textbox *tb, const char *text )
widget_queue_redraw ( WIDGET ( tb ) );
}
+void textbox_icon ( textbox *tb, cairo_surface_t *icon )
+{
+ tb->icon = icon;
+
+ widget_queue_redraw ( WIDGET ( tb ) );
+}
+
// 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 {
@@ -380,14 +389,34 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
return;
}
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 );
}
// Skip the side MARGIN on the X axis.
- int x = widget_padding_get_left ( WIDGET ( tb ) ) + offset;
+ int x = widget_padding_get_left ( WIDGET ( tb ) ) + offset;
+ int top = widget_padding_get_top ( WIDGET ( tb ) );
+ int y = top + ( pango_font_metrics_get_ascent ( tb->metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE;
+
+ // draw Icon
+ 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;
+
+ 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;
@@ -400,7 +429,6 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
x = ( ( tb->widget.w - tw - widget_padding_get_padding_width ( WIDGET ( tb ) ) - offset ) ) / 2;
}
- int top = widget_padding_get_top ( WIDGET ( tb ) );
if ( tb->yalign > 0.001 ) {
int height = (pango_font_metrics_get_ascent ( tb->metrics ) + pango_font_metrics_get_descent ( tb->metrics ))/PANGO_SCALE;
int bottom = widget_padding_get_bottom ( WIDGET ( tb ) );
@@ -412,7 +440,6 @@ static void textbox_draw ( widget *wid, cairo_t *draw )
rofi_theme_get_color ( WIDGET ( tb ), "text", draw );
// draw the cursor
if ( tb->flags & TB_EDITABLE && tb->blink ) {
- int y = top + ( pango_font_metrics_get_ascent ( tb->metrics ) - pango_layout_get_baseline ( tb->layout ) ) / PANGO_SCALE;
// We want to place the cursor based on the text shown.
const char *text = pango_layout_get_text ( tb->layout );
// Clamp the position, should not be needed, but we are paranoid.
@@ -437,7 +464,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 );
}
}
@@ -866,7 +893,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 ( wid->expand && tb->flags & TB_AUTOWIDTH ) {
return textbox_get_font_width ( tb ) + widget_padding_get_padding_width ( wid ) + offset;
}
diff --git a/source/x11-helper.c b/source/x11-helper.c
index 689d0519..94b5b53d 100644
--- a/source/x11-helper.c
+++ b/source/x11-helper.c
@@ -133,6 +133,30 @@ cairo_surface_t * x11_helper_get_bg_surface ( void )
xcb->screen->width_in_pixels, xcb->screen->height_in_pixels );
}
+cairo_surface_t* cairo_image_surface_create_from_svg ( const gchar* file, int height )
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ RsvgHandle * handle;
+ RsvgDimensionData dimensions;
+
+ handle = rsvg_handle_new_from_file ( file, NULL );
+ rsvg_handle_get_dimensions ( handle, &dimensions );
+ double scale = (double) height / dimensions.height;
+ surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32,
+ (double) dimensions.width * scale,
+ (double) dimensions.height * scale );
+ cr = cairo_create ( surface );
+ cairo_scale ( cr, scale, scale );
+ rsvg_handle_render_cairo ( handle, cr );
+ cairo_destroy ( cr );
+
+ rsvg_handle_close ( handle, NULL );
+ g_object_unref ( handle );
+
+ return surface;
+}
+
// retrieve a text property from a window
// technically we could use window_get_prop(), but this is better for character set support
char* window_get_text_prop ( xcb_window_t w, xcb_atom_t atom )
diff --git a/source/xrmoptions.c b/source/xrmoptions.c
index ef0c7dfe..7fd87e56 100644
--- a/source/xrmoptions.c
+++ b/source/xrmoptions.c
@@ -105,6 +105,9 @@ static XrmOption xrmOptions[] = {
{ xrm_Boolean, "fixed-num-lines", { .num = &config.fixed_num_lines }, NULL,
"Always show number of lines", CONFIG_DEFAULT },
+ { xrm_Boolean, "show-icons", { .snum = &config.show_icons }, NULL,
+ "Whether to load and show icons", CONFIG_DEFAULT },
+
{ xrm_String, "terminal", { .str = &config.terminal_emulator }, NULL,
"Terminal to use", CONFIG_DEFAULT },
{ xrm_String, "ssh-client", { .str = &config.ssh_client }, NULL,
@@ -119,6 +122,8 @@ static XrmOption xrmOptions[] = {
"Run command to execute that runs in shell", CONFIG_DEFAULT },
{ xrm_String, "window-command", { .str = &config.window_command }, NULL,
"Command executed on accep-entry-custom for window modus", CONFIG_DEFAULT },
+ { xrm_String, "drun-icon-theme", { .str = &config.drun_icon_theme }, NULL,
+ "Theme to use to look for icons", CONFIG_DEFAULT },
{ xrm_Boolean, "disable-history", { .num = &config.disable_history }, NULL,
"Disable history in run/ssh", CONFIG_DEFAULT },