rofi  1.5.4
rofi-icon-fetcher.c
Go to the documentation of this file.
1 /*
2  * rofi
3  *
4  * MIT/X11 License
5  * Copyright © 2013-2017 Qball Cow <qball@gmpclient.org>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  */
27 
29 #define G_LOG_DOMAIN "Helpers.IconFetcher"
30 
31 #include "rofi-icon-fetcher.h"
32 #include "rofi-types.h"
33 #include "helper.h"
34 #include "settings.h"
35 
36 #include "xcb.h"
37 #include "keyb.h"
38 #include "view.h"
39 
40 #include "nkutils-xdg-theme.h"
41 
42 typedef struct
43 {
44  // Context for icon-themes.
45  NkXdgThemeContext *xdg_context;
46 
47  // On name.
48  GHashTable *icon_cache;
49  // On uid.
50  GHashTable *icon_cache_uid;
51 
52  uint32_t last_uid;
53 } IconFetcher;
54 
55 typedef struct
56 {
57  char *name;
58  GList *sizes;
60 
61 typedef struct
62 {
64 
65  GCond *cond;
66  GMutex *mutex;
67  unsigned int *acount;
68 
69  uint32_t uid;
70  int size;
71  cairo_surface_t *surface;
72 
75 
80 
81 static void rofi_icon_fetch_entry_free ( gpointer data )
82 {
84 
85  // Free name/key.
86  g_free ( entry->name );
87 
88  for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) {
89  IconFetcherEntry *sentry = (IconFetcherEntry *) ( iter->data );
90 
91  cairo_surface_destroy ( sentry->surface );
92  g_free ( sentry );
93  }
94 
95  g_list_free ( entry->sizes );
96  g_free ( entry );
97 }
98 
100 {
101  g_assert ( rofi_icon_fetcher_data == NULL );
102 
103  static const gchar * const icon_fallback_themes[] = {
104  "Adwaita",
105  "gnome",
106  NULL
107  };
108  const char *themes[2] = { config.icon_theme, NULL };
109 
110  rofi_icon_fetcher_data = g_malloc0 ( sizeof ( IconFetcher ) );
111 
112  rofi_icon_fetcher_data->xdg_context = nk_xdg_theme_context_new ( icon_fallback_themes, NULL );
113  nk_xdg_theme_preload_themes_icon ( rofi_icon_fetcher_data->xdg_context, themes );
114 
115  rofi_icon_fetcher_data->icon_cache_uid = g_hash_table_new ( g_direct_hash, g_direct_equal );
116  rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free );
117 }
118 
120 {
121  if ( rofi_icon_fetcher_data == NULL ) {
122  return;
123  }
124 
125  nk_xdg_theme_context_free ( rofi_icon_fetcher_data->xdg_context );
126 
127  g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache_uid );
128  g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache );
129 
130  g_free ( rofi_icon_fetcher_data );
131 }
132 static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data )
133 {
134  g_debug ( "starting up icon fetching thread." );
135  // as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
136  // this should be fine running in another thread.
137  IconFetcherEntry *sentry = (IconFetcherEntry *) sdata;
138  const gchar *themes[] = {
140  NULL
141  };
142 
143  const gchar *icon_path;
144  gchar *icon_path_ = NULL;
145 
146  if ( g_path_is_absolute ( sentry->entry->name ) ) {
147  icon_path = sentry->entry->name;
148  }
149  else {
150  icon_path = icon_path_ = nk_xdg_theme_get_icon ( rofi_icon_fetcher_data->xdg_context, themes, NULL, sentry->entry->name, sentry->size, 1, TRUE );
151  if ( icon_path_ == NULL ) {
152  g_debug ( "failed to get icon %s(%d): n/a", sentry->entry->name, sentry->size );
153  return;
154  }
155  else{
156  g_debug ( "found icon %s(%d): %s", sentry->entry->name, sentry->size, icon_path );
157  }
158  }
159  cairo_surface_t *icon_surf = NULL;
160  if ( g_str_has_suffix ( icon_path, ".png" ) ) {
161  icon_surf = cairo_image_surface_create_from_png ( icon_path );
162  }
163  else if ( g_str_has_suffix ( icon_path, ".svg" ) ) {
164  icon_surf = cairo_image_surface_create_from_svg ( icon_path, sentry->size );
165  }
166  else {
167  g_debug ( "icon type not yet supported: %s", icon_path );
168  }
169  if ( icon_surf ) {
170  // check if surface is valid.
171  if ( cairo_surface_status ( icon_surf ) != CAIRO_STATUS_SUCCESS ) {
172  g_debug ( "icon failed to open: %s(%d): %s", sentry->entry->name, sentry->size, icon_path );
173  cairo_surface_destroy ( icon_surf );
174  icon_surf = NULL;
175  }
176  sentry->surface = icon_surf;
177  }
178  g_free ( icon_path_ );
179  rofi_view_reload ();
180 }
181 
182 uint32_t rofi_icon_fetcher_query ( const char *name, const int size )
183 {
184  g_debug ( "Query: %s(%d)", name, size );
185  IconFetcherNameEntry *entry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache, name );
186  if ( entry == NULL ) {
187  entry = g_new0 ( IconFetcherNameEntry, 1 );
188  entry->name = g_strdup ( name );
189  g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache, entry->name, entry );
190  }
191  IconFetcherEntry *sentry;
192  for ( GList *iter = g_list_first ( entry->sizes ); iter; iter = g_list_next ( iter ) ) {
193  sentry = iter->data;
194  if ( sentry->size == size ) {
195  return sentry->uid;
196  }
197  }
198 
199  // Not found.
200  sentry = g_new0 ( IconFetcherEntry, 1 );
201  sentry->uid = ++( rofi_icon_fetcher_data->last_uid );
202  sentry->size = size;
203  sentry->entry = entry;
204  sentry->surface = NULL;
205 
206  entry->sizes = g_list_prepend ( entry->sizes, sentry );
207  g_hash_table_insert ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( sentry->uid ), sentry );
208 
209  // Push into fetching queue.
211  g_thread_pool_push ( tpool, sentry, NULL );
212 
213  return sentry->uid;
214 }
215 
216 cairo_surface_t * rofi_icon_fetcher_get ( const uint32_t uid )
217 {
218  IconFetcherEntry *sentry = g_hash_table_lookup ( rofi_icon_fetcher_data->icon_cache_uid, GINT_TO_POINTER ( uid ) );
219  if ( sentry ) {
220  return sentry->surface;
221  }
222  return NULL;
223 }
rofi_icon_fetcher_worker
static void rofi_icon_fetcher_worker(thread_state *sdata, G_GNUC_UNUSED gpointer user_data)
Definition: rofi-icon-fetcher.c:132
IconFetcherEntry::cond
GCond * cond
Definition: rofi-icon-fetcher.c:65
IconFetcherEntry::acount
unsigned int * acount
Definition: rofi-icon-fetcher.c:67
IconFetcherEntry::surface
cairo_surface_t * surface
Definition: rofi-icon-fetcher.c:71
IconFetcherEntry::entry
IconFetcherNameEntry * entry
Definition: rofi-icon-fetcher.c:73
IconFetcher::last_uid
uint32_t last_uid
Definition: rofi-icon-fetcher.c:52
_thread_state
Definition: rofi-types.h:245
settings.h
IconFetcherNameEntry::sizes
GList * sizes
Definition: rofi-icon-fetcher.c:58
rofi-types.h
rofi_icon_fetcher_data
IconFetcher * rofi_icon_fetcher_data
Definition: rofi-icon-fetcher.c:79
cairo_image_surface_create_from_svg
cairo_surface_t * cairo_image_surface_create_from_svg(const gchar *file, int height)
Definition: helper.c:1074
tpool
GThreadPool * tpool
Definition: view.c:83
rofi_icon_fetcher_destroy
void rofi_icon_fetcher_destroy(void)
Definition: rofi-icon-fetcher.c:119
IconFetcherEntry::mutex
GMutex * mutex
Definition: rofi-icon-fetcher.c:66
rofi_icon_fetch_entry_free
static void rofi_icon_fetch_entry_free(gpointer data)
Definition: rofi-icon-fetcher.c:81
IconFetcherEntry::state
thread_state state
Definition: rofi-icon-fetcher.c:63
IconFetcherEntry
Definition: rofi-icon-fetcher.c:62
Settings::icon_theme
char * icon_theme
Definition: settings.h:97
IconFetcherEntry::uid
uint32_t uid
Definition: rofi-icon-fetcher.c:69
keyb.h
rofi_icon_fetcher_get
cairo_surface_t * rofi_icon_fetcher_get(const uint32_t uid)
Definition: rofi-icon-fetcher.c:216
xcb.h
IconFetcher::icon_cache_uid
GHashTable * icon_cache_uid
Definition: rofi-icon-fetcher.c:50
IconFetcher::icon_cache
GHashTable * icon_cache
Definition: rofi-icon-fetcher.c:48
IconFetcherNameEntry
Definition: rofi-icon-fetcher.c:56
view.h
rofi_icon_fetcher_query
uint32_t rofi_icon_fetcher_query(const char *name, const int size)
Definition: rofi-icon-fetcher.c:182
IconFetcherEntry::size
int size
Definition: rofi-icon-fetcher.c:70
rofi-icon-fetcher.h
IconFetcherNameEntry::name
char * name
Definition: rofi-icon-fetcher.c:57
helper.h
_thread_state::callback
void(* callback)(struct _thread_state *t, gpointer data)
Definition: rofi-types.h:246
IconFetcher::xdg_context
NkXdgThemeContext * xdg_context
Definition: rofi-icon-fetcher.c:45
rofi_icon_fetcher_init
void rofi_icon_fetcher_init(void)
Definition: rofi-icon-fetcher.c:99
config
Settings config
IconFetcher
Definition: rofi-icon-fetcher.c:43
rofi_view_reload
void rofi_view_reload(void)
Definition: view.c:425