summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--.travis.yml4
-rw-r--r--Makefile.am4
-rw-r--r--include/rofi-icon-fetcher.h21
-rw-r--r--include/rofi-types.h11
-rw-r--r--include/view-internal.h4
-rw-r--r--include/widgets/icon.h63
-rw-r--r--include/widgets/widget-internal.h3
-rw-r--r--include/widgets/widget.h7
-rw-r--r--lexer/theme-lexer.l1
-rw-r--r--meson.build4
-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
18 files changed, 585 insertions, 113 deletions
diff --git a/.travis.yml b/.travis.yml
index 0f04e028..d4bb3ab9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -50,8 +50,8 @@ compiler:
- gcc
before_install:
- - sudo add-apt-repository -y 'deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse'
- - sudo add-apt-repository -y 'deb http://debian.jpleau.ca/ jessie-backports main contrib non-free'
+ - sudo add-apt-repository -y 'deb https://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse'
+ - sudo add-apt-repository -y 'deb https://debian.jpleau.ca/ jessie-backports main contrib non-free'
- sudo apt-get update -qq
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
diff --git a/Makefile.am b/Makefile.am
index d2d0db4e..e8d99e1e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,8 +69,10 @@ SOURCES=\
source/history.c\
source/theme.c\
source/rofi-types.c\
+ source/rofi-icon-fetcher.c\
source/widgets/box.c\
source/widgets/container.c\
+ source/widgets/icon.c\
source/widgets/widget.c\
source/widgets/textbox.c\
source/widgets/listview.c\
@@ -91,6 +93,7 @@ SOURCES=\
include/xcb-internal.h\
include/rofi.h\
include/rofi-types.h\
+ include/rofi-icon-fetcher.h\
include/mode.h\
include/mode-private.h\
include/settings.h\
@@ -105,6 +108,7 @@ SOURCES=\
include/css-colors.h\
include/widgets/box.h\
include/widgets/container.h\
+ include/widgets/icon.h\
include/widgets/widget.h\
include/widgets/widget-internal.h\
include/widgets/textbox.h\
diff --git a/include/rofi-icon-fetcher.h b/include/rofi-icon-fetcher.h
new file mode 100644
index 00000000..3198658e
--- /dev/null
+++ b/include/rofi-icon-fetcher.h
@@ -0,0 +1,21 @@
+#ifndef ROFI_ICON_FETCHER_H
+#define ROFI_ICON_FETCHER_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <cairo.h>
+#include "nkutils-xdg-theme.h"
+
+void rofi_icon_fetcher_init ( void );
+
+
+void rofi_icon_fetcher_destroy ( void );
+
+
+uint32_t rofi_icon_fetcher_query ( const char *name, const int size );
+
+
+cairo_surface_t * rofi_icon_fetcher_get ( const uint32_t uid );
+
+
+#endif // ROFI_ICON_FETCHER_H
diff --git a/include/rofi-types.h b/include/rofi-types.h
index 93fc683c..46b01f1b 100644
--- a/include/rofi-types.h
+++ b/include/rofi-types.h
@@ -235,5 +235,16 @@ typedef struct rofi_int_matcher_t
gboolean invert;
} rofi_int_matcher;
+/**
+ * Structure with data to process by each worker thread.
+ * TODO: Make this more generic wrapper.
+ */
+typedef struct _thread_state
+{
+ void ( *callback )( struct _thread_state *t, gpointer data );
+} thread_state;
+
+extern GThreadPool *tpool;
+
G_END_DECLS
#endif // INCLUDE_ROFI_TYPES_H
diff --git a/include/view-internal.h b/include/view-internal.h
index efbf7987..cb160293 100644
--- a/include/view-internal.h
+++ b/include/view-internal.h
@@ -32,6 +32,7 @@
#include "widgets/textbox.h"
#include "widgets/listview.h"
#include "widgets/box.h"
+#include "widgets/icon.h"
#include "keyb.h"
#include "xcb.h"
#include "theme.h"
@@ -68,6 +69,9 @@ struct RofiViewState
/** #textbox containing the message entry */
textbox *mesg_tb;
+
+ icon *cur_icon;
+
/** Array with the levenshtein distance for each eleemnt. */
int *distance;
/** Array with the translation between the filtered and unfiltered list. */
diff --git a/include/widgets/icon.h b/include/widgets/icon.h
new file mode 100644
index 00000000..c7bf556f
--- /dev/null
+++ b/include/widgets/icon.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef ROFI_ICON_H
+#define ROFI_ICON_H
+
+#include "widget.h"
+
+/**
+ * @defgroup icon icon
+ * @ingroup widget
+ *
+ *
+ * @{
+ */
+
+/**
+ * Abstract handle to the icon widget internal state.
+ */
+typedef struct _icon icon;
+
+/**
+ * @param parent The widget's parent
+ * @param name The name of the widget.
+ *
+ * @returns a newly created icon, free with #widget_free
+ */
+icon * icon_create ( widget *parent, const char *name );
+
+/**
+ * @param widget The icon widget handle.
+ * @param size The size of the icon.
+ *
+ */
+void icon_set_size ( widget *icon, const int size );
+
+void icon_set_surface ( icon *icon, cairo_surface_t *surf );
+/*@}*/
+#endif // ROFI_ICON_H
diff --git a/include/widgets/widget-internal.h b/include/widgets/widget-internal.h
index e32c8766..762f5723 100644
--- a/include/widgets/widget-internal.h
+++ b/include/widgets/widget-internal.h
@@ -94,6 +94,9 @@ struct _widget
/** Name of widget (used for theming) */
char *name;
const char *state;
+
+ /** Used for reference counting */
+ int ref_count;
};
/**
diff --git a/include/widgets/widget.h b/include/widgets/widget.h
index 2c72f2e8..28fd94c3 100644
--- a/include/widgets/widget.h
+++ b/include/widgets/widget.h
@@ -322,5 +322,12 @@ int widget_get_absolute_xpos ( widget *wid );
* @returns the absolute y-position of widget of the widget in pixels.
*/
int widget_get_absolute_ypos ( widget *wid );
+
+/**
+ * @param wid The widget handle
+ *
+ * Increment the reference count on the widget.
+ */
+void widget_ref ( widget *wid );
/*@}*/
#endif // ROFI_WIDGET_H
diff --git a/lexer/theme-lexer.l b/lexer/theme-lexer.l
index da7c184f..bc1516f2 100644
--- a/lexer/theme-lexer.l
+++ b/lexer/theme-lexer.l
@@ -30,6 +30,7 @@
%option nounput
%option never-interactive
%option bison-locations
+%option bison-bridge
%{
#include <stdio.h>
diff --git a/meson.build b/meson.build
index e9c93c44..8b48e294 100644
--- a/meson.build
+++ b/meson.build
@@ -137,8 +137,10 @@ rofi_sources = files(
'source/timings.c',
'source/history.c',
'source/theme.c',
+ 'source/rofi-icon-fetcher.c',
'source/css-colors.c',
'source/widgets/box.c',
+ 'source/widgets/icon.c',
'source/widgets/container.c',
'source/widgets/widget.c',
'source/widgets/textbox.c',
@@ -165,6 +167,7 @@ rofi_sources = files(
'include/keyb.h',
'include/view.h',
'include/view-internal.h',
+ 'include/rofi-icon-fetcher.h',
'include/helper.h',
'include/helper-theme.h',
'include/timings.h',
@@ -173,6 +176,7 @@ rofi_sources = files(
'include/rofi-types.h',
'include/css-colors.h',
'include/widgets/box.h',
+ 'include/widgets/icon.h',
'include/widgets/container.h',
'include/widgets/widget.h',
'include/widgets/widget-internal.h',
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_backg