summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorDave Davenport <DaveDavenport@users.noreply.github.com>2018-06-09 19:13:57 +0200
committerGitHub <noreply@github.com>2018-06-09 19:13:57 +0200
commit441c511296dd4416b86d02ee8c0672cd08808f33 (patch)
treeb5d3f7e13fddebe40f7bd7a6210b8e587ae290be /source
parentca1ae5dfcd8170ad3978f0846b523cc0ff8980a2 (diff)
Add an generic icon fetcher that can be used by any widget and re-uses the main threadpool.
Add an generic icon fetcher that can be used by any widget and re-uses the main threadpool. * Make threadpool more generic usable. * Add generic icon fetcher, that caches icons. * Make DRUN use this fetcher. * Add icon widget. #809
Diffstat (limited to 'source')
-rw-r--r--source/dialogs/drun.c106
-rw-r--r--source/dialogs/run.c3
-rw-r--r--source/dialogs/window.c10
-rw-r--r--source/rofi-icon-fetcher.c219
-rw-r--r--source/rofi.c3
-rw-r--r--source/view.c54
-rw-r--r--source/widgets/icon.c156
-rw-r--r--source/widgets/widget.c25
8 files changed, 465 insertions, 111 deletions
diff --git a/source/dialogs/drun.c b/source/dialogs/drun.c
index 95f21768..077f0e3e 100644
--- a/source/dialogs/drun.c
+++ b/source/dialogs/drun.c
@@ -50,19 +50,24 @@
#include "widgets/textbox.h"
#include "history.h"
#include "dialogs/drun.h"
-#include "nkutils-xdg-theme.h"
#include "xcb.h"
+#include "rofi-icon-fetcher.h"
+
#define DRUN_CACHE_FILE "rofi3.druncache"
#define DRUN_GROUP_NAME "Desktop Entry"
+
+typedef struct _DRunModePrivateData DRunModePrivateData;
/**
* Store extra information about the entry.
* Currently the executable and if it should run in terminal.
*/
typedef struct
{
+ thread_state st;
+ DRunModePrivateData *pd;
/* Root */
char *root;
/* Path to desktop file */
@@ -93,6 +98,8 @@ typedef struct
GKeyFile *key_file;
gint sort_index;
+
+ uint32_t icon_fetch_uid;
} DRunModeEntry;
typedef struct
@@ -119,24 +126,21 @@ static DRunEntryField matching_entry_fields[DRUN_MATCH_NUM_FIELDS] = {
{ .entry_field_name = "comment", .enabled = FALSE, }
};
-typedef struct
+struct _DRunModePrivateData
{
- NkXdgThemeContext *xdg_context;
DRunModeEntry *entry_list;
unsigned int cmd_list_length;
unsigned int cmd_list_length_actual;
// List of disabled entries.
GHashTable *disabled_entries;
unsigned int disabled_entries_length;
- GThreadPool *pool;
unsigned int expected_line_height;
- DRunModeEntry quit_entry;
// Theme
const gchar *icon_theme;
// DE
gchar **current_desktop_list;
-} DRunModePrivateData;
+};
struct RegexEvalArg
{
@@ -398,6 +402,7 @@ static gboolean read_desktop_file ( DRunModePrivateData *pd, const char *root, c
pd->entry_list[pd->cmd_list_length].sort_index = -pd->cmd_list_length;
}
pd->entry_list[pd->cmd_list_length].icon_size = 0;
+ pd->entry_list[pd->cmd_list_length].icon_fetch_uid = 0;
pd->entry_list[pd->cmd_list_length].root = g_strdup ( root );
pd->entry_list[pd->cmd_list_length].path = g_strdup ( path );
pd->entry_list[pd->cmd_list_length].desktop_id = g_strdup ( id );
@@ -582,59 +587,6 @@ static void get_apps ( DRunModePrivateData *pd )
TICK_N ( "Sorting done." );
}
-static void drun_icon_fetch ( gpointer data, gpointer user_data )
-{
- g_debug ( "Starting up icon fetching thread." );
- // as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
- // this should be fine running in another thread.
- DRunModePrivateData *pd = (DRunModePrivateData *) user_data;
- DRunModeEntry *dr = (DRunModeEntry *) data;
- const gchar *themes[2] = {
- config.drun_icon_theme,
- NULL
- };
-
- if ( dr->icon_name == NULL ) {
- return;
- }
- const gchar *icon_path;
- gchar *icon_path_ = NULL;
-
- if ( g_path_is_absolute ( dr->icon_name ) ) {
- icon_path = dr->icon_name;
- }
- else {
- icon_path = icon_path_ = nk_xdg_theme_get_icon ( pd->xdg_context, themes, NULL, dr->icon_name, dr->icon_size, 1, TRUE );
- if ( icon_path_ == NULL ) {
- g_debug ( "Failed to get Icon %s(%d): n/a", dr->icon_name, dr->icon_size );
- return;
- }
- else{
- g_debug ( "Found Icon %s(%d): %s", dr->icon_name, dr->icon_size, icon_path );
- }
- }
- cairo_surface_t *icon_surf = NULL;
- if ( g_str_has_suffix ( icon_path, ".png" ) ) {
- icon_surf = cairo_image_surface_create_from_png ( icon_path );
- }
- else if ( g_str_has_suffix ( icon_path, ".svg" ) ) {
- icon_surf = cairo_image_surface_create_from_svg ( icon_path, dr->icon_size );
- }
- else {
- g_debug ( "Icon type not yet supported: %s", icon_path );
- }
- if ( icon_surf ) {
- // Check if surface is valid.
- if ( cairo_surface_status ( icon_surf ) != CAIRO_STATUS_SUCCESS ) {
- g_debug ( "Icon failed to open: %s(%d): %s", dr->icon_name, dr->icon_size, icon_path );
- cairo_surface_destroy ( icon_surf );
- icon_surf = NULL;
- }
- dr->icon = icon_surf;
- }
- g_free ( icon_path_ );
- rofi_view_reload ();
-}
static void drun_mode_parse_entry_fields ()
{
@@ -677,16 +629,6 @@ static int drun_mode_init ( Mode *sw )
if ( mode_get_private_data ( sw ) != NULL ) {
return TRUE;
}
-
- static const gchar * const drun_icon_fallback_themes[] = {
- "Adwaita",
- "gnome",
- NULL
- };
- const gchar *themes[2] = {
- config.drun_icon_theme,
- 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 );
@@ -694,9 +636,6 @@ static int drun_mode_init ( Mode *sw )
const char *current_desktop = g_getenv ( "XDG_CURRENT_DESKTOP" );
pd->current_desktop_list = current_desktop ? g_strsplit ( current_desktop, ":", 0 ) : NULL;
- // Theme
- pd->xdg_context = nk_xdg_theme_context_new ( drun_icon_fallback_themes, NULL );
- nk_xdg_theme_preload_themes_icon ( pd->xdg_context, themes );
drun_mode_parse_entry_fields ();
get_apps ( pd );
return TRUE;
@@ -746,10 +685,6 @@ 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 ) {
// Possitive sort index means it is in history.
if ( rmpd->entry_list[selected_line].sort_index >= 0 ) {
- if ( rmpd->pool ) {
- g_thread_pool_free ( rmpd->pool, TRUE, TRUE );
- rmpd->pool = 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],
@@ -764,16 +699,11 @@ static void drun_mode_destroy ( Mode *sw )
{
DRunModePrivateData *rmpd = (DRunModePrivateData *) mode_get_private_data ( sw );
if ( rmpd != NULL ) {
- if ( rmpd->pool ) {
- g_thread_pool_free ( rmpd->pool, TRUE, TRUE );
- rmpd->pool = 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_strfreev ( rmpd->current_desktop_list );
g_free ( rmpd );
@@ -808,16 +738,12 @@ 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 ( pd->pool == NULL ) {
- /* TODO: 4 threads good? */
- pd->pool = g_thread_pool_new ( drun_icon_fetch, pd, 4, FALSE, NULL );
- }
- if ( dr->icon_size == 0 ) {
- dr->icon_size = height;
- //g_async_queue_push ( pd->icon_fetch_queue, dr );
- g_thread_pool_push ( pd->pool, dr, NULL );
+ if ( dr->icon_name == NULL ) return NULL;
+ if ( dr->icon_fetch_uid >0){
+ return rofi_icon_fetcher_get ( dr->icon_fetch_uid );
}
- return dr->icon;
+ dr->icon_fetch_uid = rofi_icon_fetcher_query ( dr->icon_name, height );
+ return NULL;
}
static char *drun_get_completion ( const Mode *sw, unsigned int index )
diff --git a/source/dialogs/run.c b/source/dialogs/run.c
index 0465b9f7..0e9cae9c 100644
--- a/source/dialogs/run.c
+++ b/source/dialogs/run.c
@@ -55,6 +55,7 @@
#include "mode-private.h"
#include "timings.h"
+#include "rofi-icon-fetcher.h"
/**
* Name of the history file where previously chosen commands are stored.
*/
@@ -400,6 +401,7 @@ static char *_get_display_value ( const Mode *sw, unsigned int selected_line, G_
const RunModePrivateData *rmpd = (const RunModePrivateData *) sw->private_data;
return get_entry ? g_strdup ( rmpd->cmd_list[selected_line] ) : NULL;
}
+
static int run_token_match ( const Mode *sw, rofi_int_matcher **tokens, unsigned int index )
{
const RunModePrivateData *rmpd = (const RunModePrivateData *) sw->private_data;
@@ -417,6 +419,7 @@ Mode run_mode =
._destroy = run_mode_destroy,
._token_match = run_token_match,
._get_display_value = _get_display_value,
+ ._get_icon = NULL,
._get_completion = NULL,
._preprocess_input = NULL,
.private_data = NULL,
diff --git a/source/dialogs/window.c b/source/dialogs/window.c
index e6691401..d031d5d1 100644
--- a/source/dialogs/window.c
+++ b/source/dialogs/window.c
@@ -56,6 +56,8 @@
#include "timings.h"
+#include "rofi-icon-fetcher.h"
+
#define WINLIST 32
#define CLIENTSTATE 10
@@ -108,6 +110,7 @@ typedef struct
char *wmdesktopstr;
cairo_surface_t *icon;
gboolean icon_checked;
+ uint32_t icon_fetch_uid;
} client;
// window lists
@@ -910,6 +913,13 @@ static cairo_surface_t *_get_icon ( const Mode *sw, unsigned int selected_line,
c->icon = get_net_wm_icon ( rmpd->ids->array[selected_line], size );
c->icon_checked = TRUE;
}
+ if ( c->icon == NULL && c->class ){
+ if ( c->icon_fetch_uid > 0){
+ return rofi_icon_fetcher_get ( c->icon_fetch_uid );
+ }
+ c->icon_fetch_uid = rofi_icon_fetcher_query ( c->class, size);
+
+ }
return c->icon;
}
diff --git a/source/rofi-icon-fetcher.c b/source/rofi-icon-fetcher.c
new file mode 100644
index 00000000..1c0dc6ca
--- /dev/null
+++ b/source/rofi-icon-fetcher.c
@@ -0,0 +1,219 @@
+/*
+ * rofi
+ *
+ * MIT/X11 License
+ * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define G_LOG_DOMAIN "Util.IconFetcher"
+
+#include "rofi-icon-fetcher.h"
+#include "rofi-types.h"
+#include "helper.h"
+
+
+typedef struct {
+ // Context for icon-themes.
+ NkXdgThemeContext *xdg_context;
+
+ // On name.
+ GHashTable *icon_cache;
+ // On uid.
+ GHashTable *icon_cache_uid;
+
+ uint32_t last_uid;
+
+
+} IconFetcher;
+
+
+typedef struct {
+ char *name;
+ GList *sizes;
+} IconFetcherNameEntry;
+
+typedef struct {
+ thread_state state;
+
+ GCond *cond;
+ GMutex *mutex;
+ unsigned int *acount;
+
+ uint32_t uid;
+ int size;
+ cairo_surface_t *surface;
+
+ IconFetcherNameEntry *entry;
+} IconFetcherEntry;
+
+IconFetcher *rofi_icon_fetcher_data = NULL;
+
+
+static void rofi_icon_fetch_entry_free ( gpointer data )
+{
+ IconFetcherNameEntry *entry = (IconFetcherNameEntry*) data;
+
+ // Free name/key.
+ g_free ( entry->name );
+
+
+ for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) {
+ IconFetcherEntry *sentry = (IconFetcherEntry *)(iter->data);
+
+ cairo_surface_destroy ( sentry->surface );
+ g_free ( sentry );
+ }
+
+ g_list_free ( entry->sizes );
+ g_free ( entry );
+}
+
+
+void rofi_icon_fetcher_init ( void )
+{
+ g_assert ( rofi_icon_fetcher_data == NULL );
+
+ static const gchar * const icon_fallback_themes[] = {
+ "Adwaita",
+ "gnome",
+ NULL
+ };
+ const char *themes[2] = { NULL, NULL};
+
+ rofi_icon_fetcher_data = g_malloc0(sizeof(IconFetcher));
+
+ rofi_icon_fetcher_data->xdg_context = nk_xdg_theme_context_new ( icon_fallback_themes, NULL );
+ nk_xdg_theme_preload_themes_icon ( rofi_icon_fetcher_data->xdg_context, themes );
+
+
+ rofi_icon_fetcher_data->icon_cache_uid = g_hash_table_new ( g_direct_hash, g_direct_equal );
+ rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free );
+}
+
+
+void rofi_icon_fetcher_destroy ( void )
+{
+ if ( rofi_icon_fetcher_data == NULL ) return;
+
+ nk_xdg_theme_context_free ( rofi_icon_fetcher_data->xdg_context );
+
+
+ g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache_uid );
+ g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache );
+
+ g_free ( rofi_icon_fetcher_data );
+}
+void rofi_view_reload ();
+static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data )
+{
+ g_debug ( "starting up icon fetching thread." );
+ // as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
+ // this should be fine running in another thread.
+ IconFetcherEntry *sentry = (IconFetcherEntry*) sdata;
+ const gchar *themes[1] = {
+ NULL
+ };
+
+ const gchar *icon_path;
+ gchar *icon_path_ = NULL;
+
+ if ( g_path_is_absolute ( sentry->entry->name ) ) {
+ icon_path = sentry->entry->name;
+ }
+ else {
+ icon_path = icon_path_ = nk_xdg_theme_get_icon ( rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, sentry->size, 1, TRUE );
+ if ( icon_path_ == NULL ) {
+ g_debug ( "failed to get icon %s(%d): n/a",sentry->entry->name, sentry->size );
+ return;
+ }
+ else{
+ g_debug ( "found icon %s(%d): %s", sentry->entry->name, sentry->size, icon_path );
+ }
+ }
+ cairo_surface_t *icon_surf = NULL;
+ if ( g_str_has_suffix ( icon_path, ".png" ) ) {
+ icon_surf = cairo_image_surface_create_from_png ( icon_path );
+ }
+ else if ( g_str_has_suffix ( icon_path, ".svg" ) ) {
+ icon_surf = cairo_image_surface_create_from_svg ( icon_path, sentry->size );
+ }
+ else {
+ g_debug ( "icon type not yet supported: %s", icon_path );
+ }
+ if ( icon_surf ) {
+ // check if surface is valid.
+ if ( cairo_surface_status ( icon_surf ) != CAIRO_STATUS_SUCCESS ) {
+ g_debug ( "icon failed to open: %s(%d): %s", sentry->entry->name, sentry->size, icon_path );
+ cairo_surface_destroy ( icon_surf );
+ icon_surf = NULL;
+ }
+ sentry->surface= icon_surf;
+ }
+ g_free ( icon_path_ );
+ rofi_view_reload ();
+}
+
+
+uint32_t rofi_icon_fetcher_query ( const char *name, const int size )
+{
+ g_debug ("Query: %s(%d)", name, size);
+ IconFetcherNameEntry *entry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache, name );
+ if ( entry == NULL ) {
+ entry = g_new0(IconFetcherNameEntry,1);
+ entry->name = g_strdup(name);
+ g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache, entry->name, entry );
+ }
+ IconFetcherEntry *sentry;
+ for ( GList *iter = g_list_first(entry->sizes); iter; iter = g_list_next ( iter ) ) {
+ sentry = iter->data;
+ if ( sentry->size == size ){
+ return sentry->uid;
+ }
+ }
+
+ // Not found.
+ sentry = g_new0(IconFetcherEntry, 1);
+ sentry->uid = ++(rofi_icon_fetcher_data->last_uid);
+ sentry->size = size;
+ sentry->entry = entry;
+ sentry->surface = NULL;
+
+ entry->sizes = g_list_prepend ( entry->sizes, sentry );
+ g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER(sentry->uid), sentry );
+
+ // Push into fetching queue.
+ sentry->state.callback = rofi_icon_fetcher_worker;
+ g_thread_pool_push ( tpool, sentry, NULL);
+
+ return sentry->uid;
+}
+
+
+cairo_surface_t * rofi_icon_fetcher_get ( const uint32_t uid )
+{
+ IconFetcherEntry *sentry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER(uid) );
+ if ( sentry ) {
+ return sentry->surface;
+ }
+ return NULL;
+}
diff --git a/source/rofi.c b/source/rofi.c
index 55925702..ac8695e2 100644
--- a/source/rofi.c
+++ b/source/rofi.c
@@ -68,6 +68,7 @@
#include "view-internal.h"
#include "theme.h"
+#include "rofi-icon-fetcher.h"
#include "timings.h"
@@ -442,6 +443,7 @@ static void cleanup ()
}
TIMINGS_STOP ();
rofi_collect_modi_destroy ( );
+ rofi_icon_fetcher_destroy ( );
}
/**
@@ -956,6 +958,7 @@ int main ( int argc, char *argv[] )
}
rofi_view_workers_initialize ();
+ rofi_icon_fetcher_init ( );
// Create pid file
int pfd = create_pid_file ( pidfile );
diff --git a/source/view.c b/source/view.c
index 1dba430c..721d065b 100644
--- a/source/view.c
+++ b/source/view.c
@@ -551,23 +551,24 @@ static RofiViewState * __rofi_view_state_create ( void )
{
return g_malloc0 ( sizeof ( RofiViewState ) );
}
-/**
- * Structure with data to process by each worker thread.
- */
-typedef struct _thread_state
+
+typedef struct _thread_state_view
{
+ thread_state st;
+
+ GCond *cond;
+ GMutex *mutex;
+ unsigned int *acount;
+
RofiViewState *state;
unsigned int start;
unsigned int stop;
unsigned int count;
- GCond *cond;
- GMutex *mutex;
- unsigned int *acount;
const char *pattern;
glong plen;
- void ( *callback )( struct _thread_state *t, gpointer data );
-}thread_state;
+
+} thread_state_view;
/**
* @param data A thread_state object.
* @param user_data User data to pass to thread_state callback
@@ -578,14 +579,11 @@ static void rofi_view_call_thread ( gpointer data, gpointer user_data )
{
thread_state *t = (thread_state *) data;
t->callback ( t, user_data );
- g_mutex_lock ( t->mutex );
- ( *( t->acount ) )--;
- g_cond_signal ( t->cond );
- g_mutex_unlock ( t->mutex );
}
-static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data )
+static void filter_elements ( thread_state *ts, G_GNUC_UNUSED gpointer user_data )
{
+ thread_state_view *t = (thread_state_view *)ts;
for ( unsigned int i = t->start; i < t->stop; i++ ) {
int match = mode_token_match ( t->state->sw, t->state->tokens, i );
// If each token was matched, add it to list.
@@ -606,6 +604,12 @@ static void filter_elements ( thread_state *t, G_GNUC_UNUSED gpointer user_data
t->count++;
}
}
+ if ( t->acount != NULL ) {
+ g_mutex_lock ( t->mutex );
+ ( *( t->acount ) )--;
+ g_cond_signal ( t->cond );
+ g_mutex_unlock ( t->mutex );
+ }
}
static void rofi_view_setup_fake_transparency ( const char* const fake_background )
{
@@ -931,6 +935,11 @@ static void update_callback ( textbox *t, unsigned int index, void *udata, TextB
cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[index], icon_height );
textbox_icon ( t, icon );
+ if ( state->cur_icon ) {
+ if ( index == listview_get_selected ( state->list_view ) ){
+ icon_set_surface ( state->cur_icon, icon );
+ }
+ }
if ( state->tokens && config.show_match ) {
RofiHighlightColorStyle th = { ROFI_HL_BOLD | ROFI_HL_UNDERLINE, { 0.0, 0.0, 0.0, 0.0 } };
@@ -988,6 +997,12 @@ void rofi_view_update ( RofiViewState *state, gboolean qr )
if ( state->overlay ) {
widget_draw ( WIDGET ( state->overlay ), d );
}
+
+ int selected = listview_get_selected ( state->list_view );
+ cairo_surface_t *icon = mode_get_icon ( state->sw, state->line_map[selected], 32);
+ if ( state->cur_icon ) {
+ icon_set_surface ( state->cur_icon, icon );
+ }
TICK_N ( "widgets" );
cairo_surface_flush ( CacheState.edit_surf );
if ( qr ) {
@@ -1029,7 +1044,7 @@ static void rofi_view_refilter ( RofiViewState *state )
* For large lists with 8 threads I see a factor three speedup of the whole function.
*/
unsigned int nt = MAX ( 1, state->num_lines / 500 );
- thread_state states[nt];
+ thread_state_view states[nt];
GCond cond;
GMutex mutex;
g_mutex_init ( &mutex );
@@ -1046,7 +1061,7 @@ static void rofi_view_refilter ( RofiViewState *state )
states[i].acount = &count;
states[i].plen = plen;
states[i].pattern = pattern;
- states[i].callback = filter_elements;
+ states[i].st.callback = filter_elements;
if ( i > 0 ) {
g_thread_pool_push ( tpool, &states[i], NULL );
}
@@ -1637,6 +1652,13 @@ static void rofi_view_add_widget ( RofiViewState *state, widget *parent_widget,
textbox *t = textbox_create ( parent_widget, WIDGET_TYPE_TEXTBOX_TEXT, name, TB_AUTOHEIGHT | TB_WRAP, NORMAL, "", 0, 0 );
box_add ( (box *) parent_widget, WIDGET ( t ), TRUE );
}
+ else if ( g_ascii_strncasecmp ( name, "icon", 4 ) == 0 ) {
+ icon *t = icon_create ( parent_widget, name );
+ box_add ( (box *) parent_widget, WIDGET ( t ), TRUE );
+ if ( rofi_theme_get_boolean ( WIDGET ( t ), "show-current", FALSE ) ) {
+ state->cur_icon = t;
+ }
+ }
else {
wid = (widget *) box_create ( parent_widget, name, ROFI_ORIENTATION_VERTICAL );
box_add ( (box *) parent_widget, WIDGET ( wid ), TRUE );
diff --git a/source/widgets/icon.c b/source/widgets/icon.c
new file mode 100644
index 00000000..63ab3c60
--- /dev/null
+++ b/source/widgets/icon.c
@@ -0,0 +1,156 @@
+/*
+ * rofi
+ *
+ * MIT/X11 License
+ * Copyright © 2013-2018 Qball Cow <qball@gmpclient.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define G_LOG_DOMAIN "Widgets.Icon"
+
+#include <config.h>
+#include <stdio.h>
+#include "widgets/widget.h"
+#include "widgets/widget-internal.h"
+#include "widgets/icon.h"
+#include "theme.h"
+
+#include "rofi-icon-fetcher.h"
+
+struct _icon
+{
+ widget widget;
+
+ // Size of the icon.
+ int size;
+
+ uint32_t icon_fetch_id;
+
+ // Source surface.
+ cairo_surface_t *icon;
+};
+
+
+static int icon_get_desired_height ( widget *widget )
+{
+ icon *b = (icon *) widget;
+ int height = b->size;
+ height += widget_padding_get_padding_height ( widget );
+ return height;
+}
+static int icon_get_desired_width ( widget *widget )
+{
+ icon *b = (icon *) widget;
+ int width = b->size;
+ width += widget_padding_get_padding_width ( widget );
+ return width;
+}
+
+static void icon_draw ( widget *wid, cairo_t *draw )
+{
+ icon *b = (icon *) wid;
+ // If no icon is loaded. quit.
+ if ( b->icon == NULL && b->icon_fetch_id > 0 ) {
+
+ b->icon = rofi_icon_fetcher_get ( b->icon_fetch_id );
+ if ( b->icon ) {
+ cairo_surface_reference ( b->icon );
+ }
+ }
+ if ( b->icon == NULL ) {
+ return;
+ }
+ int iconh = cairo_image_surface_get_height ( b->icon );
+ int iconw = cairo_image_surface_get_width ( b->icon );
+ int icons = MAX ( iconh, iconw );
+ double scale = (double) b->size/ icons;
+
+ cairo_save ( draw );
+
+ cairo_translate ( draw, ( b->size - iconw * scale ) / 2.0, ( b->size - iconh * scale ) / 2.0 );
+ cairo_scale ( draw, scale, scale );
+ cairo_set_source_surface ( draw, b->icon, 0, 0 );
+ cairo_paint ( draw );
+ cairo_restore ( draw );
+
+}
+
+static void icon_free ( widget *wid )
+{
+ icon *b = (icon *) wid;
+
+ if ( b->icon ) {
+ cairo_surface_destroy ( b->icon );
+ }
+
+ g_free ( b );
+}
+
+static void icon_resize ( widget *widget, short w, short h )
+{
+ icon *b = (icon *) widget;
+ if ( b->widget.w != w || b->widget.h != h ) {
+ b->widget.w = w;
+ b->widget.h = h;
+ widget_update ( widget );
+ }
+}
+
+void icon_set_surface ( icon *icon, cairo_surface_t *surf )
+{
+ icon->icon_fetch_id = 0;
+ if ( icon->icon ) {
+ cairo_surface_destroy ( icon->icon );
+ icon->icon = NULL;
+ }
+ if ( surf ) {
+ cairo_surface_reference ( surf );
+ icon->icon = surf;
+ }
+ widget_queue_redraw ( WIDGET ( icon ) );
+}
+
+icon * icon_create ( widget *parent, const char *name )
+{
+ icon *b = g_malloc0 ( sizeof ( icon ) );
+
+ b->size = 16;
+ // Initialize widget.
+ widget_init ( WIDGET ( b ), parent, WIDGET_TYPE_UNKNOWN, name );
+ b->widget.draw = icon_draw;
+ b->widget.free = icon_free;
+ b->widget.resize = icon_resize;
+ b->widget.get_desired_height = icon_get_desired_height;
+ b->widget.get_desired_width = icon_get_desired_width;
+
+
+ b->size = rofi_theme_get_integer ( WIDGET ( b ), "size", b->size );
+
+ const char * filename = rofi_theme_get_string ( WIDGET ( b ), "filename", NULL );
+ if ( filename ) {
+ b->icon_fetch_id = rofi_icon_fetcher_query ( filename, b->size );
+ }
+
+
+ return b;
+}
+
diff --git a/source/widgets/widget.c b/source/widgets/widget.c
index 1562d3d0..22869959 100644
--- a/source/widgets/widget.c
+++ b/source/widgets/widget.c
@@ -27,6 +27,7 @@
#include <glib.h>
#include <math.h>
+#include <stdatomic.h>
#include "widgets/widget.h"
#include "widgets/widget-internal.h"
#include "theme.h"
@@ -36,6 +37,8 @@
void widget_init ( widget *wid, widget *parent, WidgetType type, const char *name )
{
+ wid->ref_count = 1;
+
wid->type = type;
wid->parent = parent;
wid->name = g_strdup ( name );
@@ -359,14 +362,26 @@ void widget_draw ( widget *widget, cairo_t *d )
}
}
}
+
+void widget_ref ( widget *wid )
+{
+ g_assert ( wid != NULL );
+ g_assert ( wid->ref_count > 0 );
+
+ atomic_fetch_add( &(wid->ref_count), 1);
+}
+
void widget_free ( widget *wid )
{
if ( wid ) {
- if ( wid->name ) {
- g_free ( wid->name );
- }
- if ( wid->free ) {
- wid->free ( wid );
+ if ( atomic_fetch_sub ( &(wid->ref_count), 1) == 1 ) {
+ if ( wid->name ) {
+ g_free ( wid->name );
+ }
+ if ( wid->free ) {
+ wid->free ( wid );
+ }
+ return;
}
}
}