mirror of
https://github.com/davatorium/rofi.git
synced 2024-11-18 13:54:36 -05:00
[RofiIconFetcher] Switch to gdk-pixbuf.
This commit is contained in:
parent
4fd7128d4c
commit
deb1e6a208
7 changed files with 169 additions and 348 deletions
|
@ -31,17 +31,15 @@ You can also use [Meson](https://mesonbuild.com/) as an alternative.
|
||||||
* libglib2.0 >= 2.40
|
* libglib2.0 >= 2.40
|
||||||
* gmodule-2.0
|
* gmodule-2.0
|
||||||
* gio-unix-2.0
|
* gio-unix-2.0
|
||||||
* librsvg2.0
|
* libgdk-pixbuf-2.0
|
||||||
* libstartup-notification-1.0
|
* libstartup-notification-1.0
|
||||||
* libxkbcommon >= 0.4.1
|
* libxkbcommon >= 0.4.1
|
||||||
* libxkbcommon-x11
|
* libxkbcommon-x11
|
||||||
* libjpeg
|
|
||||||
* libxcb (sometimes split, you need libxcb, libxcb-xkb and libxcb-randr libxcb-xinerama)
|
* libxcb (sometimes split, you need libxcb, libxcb-xkb and libxcb-randr libxcb-xinerama)
|
||||||
* xcb-util
|
* xcb-util
|
||||||
* xcb-util-wm (sometimes split as libxcb-ewmh and libxcb-icccm)
|
* xcb-util-wm (sometimes split as libxcb-ewmh and libxcb-icccm)
|
||||||
* xcb-util-xrm [new module might not be available in your distribution. The source can be found
|
* xcb-util-xrm [new module might not be available in your distribution. The source can be found
|
||||||
here](https://github.com/Airblader/xcb-util-xrm/)
|
here](https://github.com/Airblader/xcb-util-xrm/)
|
||||||
* libgif (optional)
|
|
||||||
|
|
||||||
On debian based systems, the developer packages are in the form of: `<package>-dev` on rpm based
|
On debian based systems, the developer packages are in the form of: `<package>-dev` on rpm based
|
||||||
`<package>-devel`.
|
`<package>-devel`.
|
||||||
|
|
13
Makefile.am
13
Makefile.am
|
@ -145,7 +145,7 @@ rofi_CFLAGS=\
|
||||||
$(pango_CFLAGS)\
|
$(pango_CFLAGS)\
|
||||||
$(libsn_CFLAGS)\
|
$(libsn_CFLAGS)\
|
||||||
$(cairo_CFLAGS)\
|
$(cairo_CFLAGS)\
|
||||||
$(librsvg_CFLAGS)\
|
$(gdkpixbuf_CFLAGS)\
|
||||||
-DMANPAGE_PATH="\"$(mandir)/\""\
|
-DMANPAGE_PATH="\"$(mandir)/\""\
|
||||||
-I$(top_srcdir)/include/\
|
-I$(top_srcdir)/include/\
|
||||||
-I$(top_builddir)/lexer/\
|
-I$(top_builddir)/lexer/\
|
||||||
|
@ -166,9 +166,7 @@ rofi_LDADD=\
|
||||||
$(libsn_LIBS)\
|
$(libsn_LIBS)\
|
||||||
$(pango_LIBS)\
|
$(pango_LIBS)\
|
||||||
$(cairo_LIBS)\
|
$(cairo_LIBS)\
|
||||||
$(librsvg_LIBS)\
|
$(gdkpixbuf_LIBS)\
|
||||||
$(libjpeg_LIBS)\
|
|
||||||
$(libgif_LIBS)\
|
|
||||||
$(LIBS)
|
$(LIBS)
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -326,8 +324,7 @@ textbox_test_CFLAGS=\
|
||||||
$(GW_XCB_CFLAGS)\
|
$(GW_XCB_CFLAGS)\
|
||||||
$(cairo_CFLAGS)\
|
$(cairo_CFLAGS)\
|
||||||
$(libsn_CFLAGS)\
|
$(libsn_CFLAGS)\
|
||||||
$(librsvg_CFLAGS)\
|
$(gdkpixbuf_CFLAGS)\
|
||||||
$(libjpeg_CFLAGS)\
|
|
||||||
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
||||||
-DTHEME_DIR=\"$(themedir)\"\
|
-DTHEME_DIR=\"$(themedir)\"\
|
||||||
-I$(top_srcdir)/include/\
|
-I$(top_srcdir)/include/\
|
||||||
|
@ -342,7 +339,6 @@ textbox_test_LDADD=\
|
||||||
$(NKUTILS_LIBS)\
|
$(NKUTILS_LIBS)\
|
||||||
$(GW_XCB_LIBS)\
|
$(GW_XCB_LIBS)\
|
||||||
$(cairo_LIBS)\
|
$(cairo_LIBS)\
|
||||||
$(librsvg_LIBS)\
|
|
||||||
$(libsn_LIBS)
|
$(libsn_LIBS)
|
||||||
|
|
||||||
helper_pidfile_CFLAGS=$(textbox_test_CFLAGS)
|
helper_pidfile_CFLAGS=$(textbox_test_CFLAGS)
|
||||||
|
@ -479,7 +475,7 @@ helper_test_CFLAGS=\
|
||||||
$(NKUTILS_CFLAGS)\
|
$(NKUTILS_CFLAGS)\
|
||||||
$(GW_XCB_CFLAGS)\
|
$(GW_XCB_CFLAGS)\
|
||||||
$(cairo_CFLAGS)\
|
$(cairo_CFLAGS)\
|
||||||
$(librsvg_CFLAGS)\
|
$(gdkpixbuf_CFLAGS)\
|
||||||
$(libsn_CFLAGS)\
|
$(libsn_CFLAGS)\
|
||||||
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
||||||
-DTHEME_DIR=\"$(themedir)\"\
|
-DTHEME_DIR=\"$(themedir)\"\
|
||||||
|
@ -495,7 +491,6 @@ helper_test_LDADD=\
|
||||||
$(NKUTILS_LIBS)\
|
$(NKUTILS_LIBS)\
|
||||||
$(GW_XCB_LIBS)\
|
$(GW_XCB_LIBS)\
|
||||||
$(libsn_LIBS)\
|
$(libsn_LIBS)\
|
||||||
$(librsvg_LIBS)\
|
|
||||||
$(cairo_LIBS)
|
$(cairo_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
|
35
configure.ac
35
configure.ac
|
@ -148,8 +148,7 @@ GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm
|
||||||
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
||||||
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])
|
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])
|
||||||
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0 ])
|
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0 ])
|
||||||
PKG_CHECK_MODULES([librsvg], [librsvg-2.0 ])
|
PKG_CHECK_MODULES([gdkpixbuf], [gdk-pixbuf-2.0])
|
||||||
PKG_CHECK_MODULES([libjpeg], [libjpeg])
|
|
||||||
|
|
||||||
dnl ---------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------
|
||||||
dnl check - Unit testing.
|
dnl check - Unit testing.
|
||||||
|
@ -165,38 +164,6 @@ dnl Gets the resource compile tool path.
|
||||||
dnl ---------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------
|
||||||
AM_PATH_GLIB_2_0
|
AM_PATH_GLIB_2_0
|
||||||
|
|
||||||
dnl Test for libgif or libungif
|
|
||||||
AC_ARG_WITH([libgif],
|
|
||||||
AS_HELP_STRING([--with-libgif=PREFIX],
|
|
||||||
[Prefix where libgif is installed, or 'no' to disable]),
|
|
||||||
[libgif_prefix="$withval"], [libgif_prefix="${prefix}"])
|
|
||||||
|
|
||||||
if test x$with_libgif != xno && test -z "$libgif_LIBS"; then
|
|
||||||
GIF_CFLAGS="-I${libgif_prefix}/include"
|
|
||||||
GIF_LIBS="-L${libgif_prefix}/lib"
|
|
||||||
save_cflags=$CFLAGS; CFLAGS=$GIF_CFLAGS
|
|
||||||
save_libs=$LIBS; LIBS=$GIF_LIBS
|
|
||||||
AC_CHECK_LIB(gif, DGifOpenFileName,
|
|
||||||
[AC_CHECK_HEADER(gif_lib.h,
|
|
||||||
GIF='gif'; libgif_LIBS='-lgif'; gif_ok=yes,
|
|
||||||
AC_MSG_WARN(*** GIF loader will not be built (giflibrary not found) ***))],
|
|
||||||
AC_MSG_WARN(*** GIF loader will not be built (giflibrary not found) ***))
|
|
||||||
|
|
||||||
AC_CHECK_LIB(ungif, DGifOpenFileName,
|
|
||||||
[AC_CHECK_HEADER(gif_lib.h,
|
|
||||||
GIF='ungif'; libgif_LIBS='-lungif'; gif_ok=yes,
|
|
||||||
AC_MSG_WARN(*** GIF loader will not be built (ungiflibrary not found) ***))],
|
|
||||||
AC_MSG_WARN(*** GIF loader will not be built (ungiflibrary not found) ***))
|
|
||||||
CFLAGS+=$save_cflags
|
|
||||||
LIBS+=$save_libs
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test x$GIF != x; then
|
|
||||||
AC_SUBST(libgif_LIBS)
|
|
||||||
AC_DEFINE(HAVE_LIBGIF, 1, Define if gif support is available)
|
|
||||||
else
|
|
||||||
gif_ok="no (See http://sourceforge.net/projects/libgif)"
|
|
||||||
fi
|
|
||||||
dnl ---------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------
|
||||||
dnl Add extra compiler flags
|
dnl Add extra compiler flags
|
||||||
dnl ---------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------
|
||||||
|
|
|
@ -47,9 +47,7 @@ deps = [
|
||||||
dependency('pango'),
|
dependency('pango'),
|
||||||
dependency('pangocairo'),
|
dependency('pangocairo'),
|
||||||
dependency('xkbcommon'),
|
dependency('xkbcommon'),
|
||||||
dependency('librsvg-2.0'),
|
dependency('gdk-pixbuf-2.0'),
|
||||||
dependency('libjpeg'),
|
|
||||||
c_compiler.find_library('m', required: false),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include <pango/pango.h>
|
#include <pango/pango.h>
|
||||||
#include <pango/pango-fontmap.h>
|
#include <pango/pango-fontmap.h>
|
||||||
#include <pango/pangocairo.h>
|
#include <pango/pangocairo.h>
|
||||||
#include <librsvg/rsvg.h>
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "xcb.h"
|
#include "xcb.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
@ -1137,50 +1136,6 @@ char *helper_get_theme_path ( const char *file )
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
cairo_surface_t* cairo_image_surface_create_from_svg ( const gchar* file, int height )
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
cairo_surface_t *surface = NULL;
|
|
||||||
RsvgHandle * handle;
|
|
||||||
|
|
||||||
handle = rsvg_handle_new_from_file ( file, &error );
|
|
||||||
if ( G_LIKELY ( handle != NULL ) ) {
|
|
||||||
RsvgDimensionData dimensions;
|
|
||||||
// Update DPI.
|
|
||||||
rsvg_handle_set_dpi ( handle, config.dpi );
|
|
||||||
// Get size.
|
|
||||||
rsvg_handle_get_dimensions ( handle, &dimensions );
|
|
||||||
// Create cairo surface in the right size.
|
|
||||||
double scale = (double) height / dimensions.height;
|
|
||||||
surface = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32,
|
|
||||||
(double) dimensions.width * scale,
|
|
||||||
(double) dimensions.height * scale );
|
|
||||||
gboolean failed = cairo_surface_status ( surface ) != CAIRO_STATUS_SUCCESS;
|
|
||||||
if ( G_LIKELY ( failed == FALSE ) ) {
|
|
||||||
cairo_t *cr = cairo_create ( surface );
|
|
||||||
cairo_scale ( cr, scale, scale );
|
|
||||||
failed = rsvg_handle_render_cairo ( handle, cr ) == FALSE;
|
|
||||||
cairo_destroy ( cr );
|
|
||||||
}
|
|
||||||
|
|
||||||
rsvg_handle_close ( handle, &error );
|
|
||||||
g_object_unref ( handle );
|
|
||||||
|
|
||||||
/** Rendering fails */
|
|
||||||
if ( G_UNLIKELY ( failed ) ) {
|
|
||||||
g_warning ( "Failed to render file: '%s'", file );
|
|
||||||
cairo_surface_destroy ( surface );
|
|
||||||
surface = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( G_UNLIKELY ( error != NULL ) ) {
|
|
||||||
g_warning ( "Failed to render SVG file: '%s': %s", file, error->message );
|
|
||||||
g_error_free ( error );
|
|
||||||
}
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_pair ( char *input, rofi_range_pair *item )
|
static void parse_pair ( char *input, rofi_range_pair *item )
|
||||||
{
|
{
|
||||||
// Skip leading blanks.
|
// Skip leading blanks.
|
||||||
|
|
|
@ -44,9 +44,8 @@
|
||||||
#include "nkutils-enum.h"
|
#include "nkutils-enum.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <jpeglib.h>
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -58,6 +57,8 @@ typedef struct
|
||||||
// On uid.
|
// On uid.
|
||||||
GHashTable *icon_cache_uid;
|
GHashTable *icon_cache_uid;
|
||||||
|
|
||||||
|
// list extensions
|
||||||
|
GList *supported_extensions;
|
||||||
uint32_t last_uid;
|
uint32_t last_uid;
|
||||||
} IconFetcher;
|
} IconFetcher;
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
IconFetcher *rofi_icon_fetcher_data = NULL;
|
IconFetcher *rofi_icon_fetcher_data = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void rofi_icon_fetch_entry_free ( gpointer data )
|
static void rofi_icon_fetch_entry_free ( gpointer data )
|
||||||
{
|
{
|
||||||
IconFetcherNameEntry *entry = (IconFetcherNameEntry *) data;
|
IconFetcherNameEntry *entry = (IconFetcherNameEntry *) data;
|
||||||
|
@ -123,6 +125,22 @@ void rofi_icon_fetcher_init ( void )
|
||||||
|
|
||||||
rofi_icon_fetcher_data->icon_cache_uid = g_hash_table_new ( g_direct_hash, g_direct_equal );
|
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 );
|
rofi_icon_fetcher_data->icon_cache = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, rofi_icon_fetch_entry_free );
|
||||||
|
|
||||||
|
|
||||||
|
GSList *l = gdk_pixbuf_get_formats();
|
||||||
|
for ( GSList *li = l; li != NULL; li = g_slist_next(li))
|
||||||
|
{
|
||||||
|
gchar **exts = gdk_pixbuf_format_get_extensions ( (GdkPixbufFormat *)li->data );
|
||||||
|
|
||||||
|
for ( unsigned int i = 0; exts && exts[i]; i ++ ) {
|
||||||
|
rofi_icon_fetcher_data->supported_extensions = g_list_append ( rofi_icon_fetcher_data->supported_extensions, exts[i]);
|
||||||
|
exts[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free ( exts );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rofi_icon_fetcher_destroy ( void )
|
void rofi_icon_fetcher_destroy ( void )
|
||||||
|
@ -136,180 +154,106 @@ void rofi_icon_fetcher_destroy ( void )
|
||||||
g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache_uid );
|
g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache_uid );
|
||||||
g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache );
|
g_hash_table_unref ( rofi_icon_fetcher_data->icon_cache );
|
||||||
|
|
||||||
|
|
||||||
|
g_list_foreach ( rofi_icon_fetcher_data->supported_extensions, (GFunc)g_free, NULL );
|
||||||
|
g_list_free ( rofi_icon_fetcher_data->supported_extensions );
|
||||||
g_free ( rofi_icon_fetcher_data );
|
g_free ( rofi_icon_fetcher_data );
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_surface_t* cairo_image_surface_create_from_jpeg_private ( struct jpeg_decompress_struct* cinfo )
|
/*
|
||||||
{
|
* _rofi_icon_fetcher_get_icon_surface and alpha_mult
|
||||||
cairo_surface_t* surface = 0;
|
* are inspired by gdk_cairo_set_source_pixbuf
|
||||||
unsigned char * data = 0;
|
* GDK is:
|
||||||
unsigned char * rgb = 0;
|
* Copyright (C) 2011-2018 Red Hat, Inc.
|
||||||
|
*/
|
||||||
jpeg_read_header ( cinfo, TRUE );
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||||
jpeg_start_decompress ( cinfo );
|
#define RED_BYTE 2
|
||||||
|
#define GREEN_BYTE 1
|
||||||
surface = cairo_image_surface_create ( CAIRO_FORMAT_RGB24, cinfo->image_width, cinfo->image_height );
|
#define BLUE_BYTE 0
|
||||||
data = cairo_image_surface_get_data ( surface );
|
#define ALPHA_BYTE 3
|
||||||
rgb = (unsigned char *) ( malloc ( cinfo->output_width * cinfo->output_components ) );
|
#else
|
||||||
|
#define RED_BYTE 1
|
||||||
while ( cinfo->output_scanline < cinfo->output_height ) {
|
#define GREEN_BYTE 2
|
||||||
unsigned int i;
|
#define BLUE_BYTE 3
|
||||||
int scanline = cinfo->output_scanline * cairo_image_surface_get_stride ( surface );
|
#define ALPHA_BYTE 0
|
||||||
|
|
||||||
jpeg_read_scanlines ( cinfo, &rgb, 1 );
|
|
||||||
|
|
||||||
for ( i = 0; i < cinfo->output_width; i++ ) {
|
|
||||||
int offset = scanline + ( i * 4 );
|
|
||||||
|
|
||||||
data[offset + 3] = 255;
|
|
||||||
data[offset + 2] = rgb[( i * 3 )];
|
|
||||||
data[offset + 1] = rgb[( i * 3 ) + 1];
|
|
||||||
data[offset ] = rgb[( i * 3 ) + 2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free ( rgb );
|
|
||||||
|
|
||||||
jpeg_finish_decompress ( cinfo );
|
|
||||||
jpeg_destroy_decompress ( cinfo );
|
|
||||||
|
|
||||||
cairo_surface_mark_dirty ( surface );
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
struct jpegErrorManager {
|
|
||||||
/* "public" fields */
|
|
||||||
struct jpeg_error_mgr pub;
|
|
||||||
/* for return to caller */
|
|
||||||
jmp_buf setjmp_buffer;
|
|
||||||
};
|
|
||||||
char jpegLastErrorMsg[JMSG_LENGTH_MAX];
|
|
||||||
static void jpegErrorExit (j_common_ptr cinfo)
|
|
||||||
{
|
|
||||||
/* cinfo->err actually points to a jpegErrorManager struct */
|
|
||||||
struct jpegErrorManager* myerr = (struct jpegErrorManager*) cinfo->err;
|
|
||||||
|
|
||||||
/* Create the message */
|
|
||||||
( *(cinfo->err->format_message) ) (cinfo, jpegLastErrorMsg);
|
|
||||||
g_warning ( jpegLastErrorMsg, NULL );
|
|
||||||
|
|
||||||
/* Jump to the setjmp point */
|
|
||||||
longjmp(myerr->setjmp_buffer, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cairo_surface_t* cairo_image_surface_create_from_jpeg ( const char* file )
|
|
||||||
{
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
|
||||||
cairo_surface_t * surface;
|
|
||||||
FILE * infile;
|
|
||||||
|
|
||||||
if ( ( infile = fopen ( file, "rb" ) ) == NULL ) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct jpegErrorManager jerr;
|
|
||||||
cinfo.err = jpeg_std_error( &jerr.pub);
|
|
||||||
jerr.pub.error_exit = jpegErrorExit;
|
|
||||||
/* Establish the setjmp return context for my_error_exit to use. */
|
|
||||||
if (setjmp(jerr.setjmp_buffer)) {
|
|
||||||
/* If we get here, the JPEG code has signaled an error. */
|
|
||||||
jpeg_destroy_decompress(&cinfo);
|
|
||||||
fclose(infile);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jpeg_create_decompress ( &cinfo );
|
|
||||||
jpeg_stdio_src ( &cinfo, infile );
|
|
||||||
|
|
||||||
surface = cairo_image_surface_create_from_jpeg_private ( &cinfo );
|
|
||||||
|
|
||||||
fclose ( infile );
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBGIF
|
|
||||||
#include <gif_lib.h>
|
|
||||||
|
|
||||||
static cairo_surface_t* cairo_image_surface_create_from_gif(const char* file )
|
|
||||||
{
|
|
||||||
cairo_surface_t* img = NULL;
|
|
||||||
|
|
||||||
int err;
|
|
||||||
GifFileType* gif = DGifOpenFileName(file, &err);
|
|
||||||
if (!gif) {
|
|
||||||
g_warning( "[%i] %s", err, GifErrorString(err));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode with high-level API
|
|
||||||
if (DGifSlurp(gif) != GIF_OK) {
|
|
||||||
g_warning("Decoder error: %s", GifErrorString(gif->Error));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!gif->SavedImages) {
|
|
||||||
g_warning("No saved images");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create canvas
|
|
||||||
img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, gif->SWidth, gif->SHeight);
|
|
||||||
if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
|
|
||||||
g_warning("Unable to create surface: %s",
|
|
||||||
cairo_status_to_string(cairo_surface_status(img)));
|
|
||||||
cairo_surface_destroy(img);
|
|
||||||
img = NULL;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we don't support animation, show the first frame only
|
|
||||||
const GifImageDesc* frame = &gif->SavedImages->ImageDesc;
|
|
||||||
const GifColorType* colors = gif->SColorMap ? gif->SColorMap->Colors :
|
|
||||||
frame->ColorMap->Colors;
|
|
||||||
uint32_t* base = (uint32_t*)(cairo_image_surface_get_data(img) +
|
|
||||||
frame->Top * cairo_image_surface_get_stride(img));
|
|
||||||
for (int y = 0; y < frame->Height; ++y) {
|
|
||||||
uint32_t* pixel = base + y * gif->SWidth + frame->Left;
|
|
||||||
const uint8_t* raster = &gif->SavedImages->RasterBits[y * gif->SWidth];
|
|
||||||
for (int x = 0; x < frame->Width; ++x) {
|
|
||||||
const uint8_t color = raster[x];
|
|
||||||
if (color != gif->SBackGroundColor) {
|
|
||||||
const GifColorType* rgb = &colors[color];
|
|
||||||
*pixel = 0xff000000 |
|
|
||||||
rgb->Red << 16 | rgb->Green << 8 | rgb->Blue;
|
|
||||||
}
|
|
||||||
++pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_surface_mark_dirty(img);
|
|
||||||
|
|
||||||
done:
|
|
||||||
DGifCloseFile(gif, NULL);
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
static inline guchar alpha_mult(guchar c, guchar a)
|
||||||
IMAGE_PNG,
|
{
|
||||||
IMAGE_JPG,
|
guint16 t;
|
||||||
IMAGE_JPEG,
|
switch ( a )
|
||||||
IMAGE_SVG,
|
{
|
||||||
#ifdef HAVE_LIBGIF
|
case 0xff:
|
||||||
IMAGE_GIF,
|
return c;
|
||||||
#endif
|
case 0x00:
|
||||||
IMAGE_MAX_VALUES
|
return 0x00;
|
||||||
} RofiIconFetchDecoder;
|
default:
|
||||||
|
t = c * a + 0x7f;
|
||||||
|
return ((t >> 8) + t) >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const gchar * const _image_exts[IMAGE_MAX_VALUES] = {
|
static cairo_surface_t * rofi_icon_fetcher_get_surface_from_pixbuf(GdkPixbuf
|
||||||
[IMAGE_PNG] = ".png",
|
*pixbuf)
|
||||||
[IMAGE_JPG] = ".jpg",
|
{
|
||||||
[IMAGE_JPEG] = ".jpeg",
|
gint width, height;
|
||||||
[IMAGE_SVG] = ".svg",
|
const guchar *pixels;
|
||||||
#ifdef HAVE_LIBGIF
|
gint stride;
|
||||||
[IMAGE_GIF] = ".gif",
|
gboolean alpha;
|
||||||
#endif
|
|
||||||
};
|
if ( pixbuf == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
width = gdk_pixbuf_get_width(pixbuf);
|
||||||
|
height = gdk_pixbuf_get_height(pixbuf);
|
||||||
|
pixels = gdk_pixbuf_read_pixels(pixbuf);
|
||||||
|
stride = gdk_pixbuf_get_rowstride(pixbuf);
|
||||||
|
alpha = gdk_pixbuf_get_has_alpha(pixbuf);
|
||||||
|
|
||||||
|
cairo_surface_t *surface = NULL;
|
||||||
|
|
||||||
|
gint cstride;
|
||||||
|
guint lo, o;
|
||||||
|
guchar a = 0xff;
|
||||||
|
const guchar *pixels_end, *line, *line_end;
|
||||||
|
guchar *cpixels, *cline;
|
||||||
|
|
||||||
|
pixels_end = pixels + height * stride;
|
||||||
|
o = alpha ? 4 : 3;
|
||||||
|
lo = o * width;
|
||||||
|
|
||||||
|
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
||||||
|
cpixels = cairo_image_surface_get_data(surface);
|
||||||
|
cstride = cairo_image_surface_get_stride(surface);
|
||||||
|
|
||||||
|
cairo_surface_flush(surface);
|
||||||
|
while ( pixels < pixels_end )
|
||||||
|
{
|
||||||
|
line = pixels;
|
||||||
|
line_end = line + lo;
|
||||||
|
cline = cpixels;
|
||||||
|
|
||||||
|
while ( line < line_end )
|
||||||
|
{
|
||||||
|
if ( alpha )
|
||||||
|
a = line[3];
|
||||||
|
cline[RED_BYTE] = alpha_mult(line[0], a);
|
||||||
|
cline[GREEN_BYTE] = alpha_mult(line[1], a);
|
||||||
|
cline[BLUE_BYTE] = alpha_mult(line[2], a);
|
||||||
|
cline[ALPHA_BYTE] = a;
|
||||||
|
|
||||||
|
line += o;
|
||||||
|
cline += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels += stride;
|
||||||
|
cpixels += cstride;
|
||||||
|
}
|
||||||
|
cairo_surface_mark_dirty(surface);
|
||||||
|
cairo_surface_flush(surface);
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean rofi_icon_fetcher_file_is_image ( const char * const path )
|
gboolean rofi_icon_fetcher_file_is_image ( const char * const path )
|
||||||
{
|
{
|
||||||
|
@ -320,101 +264,66 @@ gboolean rofi_icon_fetcher_file_is_image ( const char * const path )
|
||||||
if ( suf == NULL ) {
|
if ( suf == NULL ) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
suf++;
|
||||||
|
|
||||||
guint64 type;
|
for ( GList *iter = rofi_icon_fetcher_data->supported_extensions; iter != NULL ; iter = g_list_next ( iter ) ) {
|
||||||
gboolean r = nk_enum_parse ( suf, _image_exts, G_N_ELEMENTS(_image_exts), TRUE, FALSE, &type );
|
if ( g_ascii_strcasecmp(iter->data, suf ) == 0 ) {
|
||||||
return r;
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data )
|
static void rofi_icon_fetcher_worker ( thread_state *sdata, G_GNUC_UNUSED gpointer user_data )
|
||||||
{
|
{
|
||||||
g_debug ( "starting up icon fetching thread." );
|
g_debug ( "starting up icon fetching thread." );
|
||||||
// as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
|
// as long as dr->icon is updated atomicly.. (is a pointer write atomic?)
|
||||||
// this should be fine running in another thread.
|
// this should be fine running in another thread.
|
||||||
IconFetcherEntry *sentry = (IconFetcherEntry *) sdata;
|
IconFetcherEntry *sentry = (IconFetcherEntry *) sdata;
|
||||||
const gchar *themes[] = {
|
const gchar *themes[] = {
|
||||||
config.icon_theme,
|
config.icon_theme,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
const gchar *icon_path;
|
const gchar *icon_path;
|
||||||
gchar *icon_path_ = NULL;
|
gchar *icon_path_ = NULL;
|
||||||
|
|
||||||
if ( g_path_is_absolute ( sentry->entry->name ) ) {
|
if ( g_path_is_absolute ( sentry->entry->name ) ) {
|
||||||
icon_path = 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 {
|
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 );
|
g_debug ( "found icon %s(%d): %s", sentry->entry->name, sentry->size, icon_path );
|
||||||
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;
|
}
|
||||||
|
cairo_surface_t *icon_surf = NULL;
|
||||||
|
|
||||||
const char *suf = strrchr(icon_path, '.');
|
const char *suf = strrchr(icon_path, '.');
|
||||||
if ( suf == NULL ) {
|
if ( suf == NULL ) {
|
||||||
return ;
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
GdkPixbuf *pb = gdk_pixbuf_new_from_file_at_scale ( icon_path, sentry->size, sentry->size, TRUE, &error );
|
||||||
|
if ( error != NULL ) {
|
||||||
|
g_warning ( "Failed to load image: %s", error->message);
|
||||||
|
g_error_free( error );
|
||||||
|
if ( pb ) {
|
||||||
|
g_object_unref ( pb );
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
icon_surf = rofi_icon_fetcher_get_surface_from_pixbuf(pb );
|
||||||
|
g_object_unref ( pb );
|
||||||
|
}
|
||||||
|
|
||||||
guint64 type;
|
sentry->surface = icon_surf;
|
||||||
gboolean is_image = nk_enum_parse ( suf, _image_exts, G_N_ELEMENTS(_image_exts), TRUE, FALSE, &type );
|
g_free ( icon_path_ );
|
||||||
if ( is_image )
|
rofi_view_reload ();
|
||||||
{
|
|
||||||
if ( type == IMAGE_PNG ) {
|
|
||||||
icon_surf = cairo_image_surface_create_from_png ( icon_path );
|
|
||||||
}
|
|
||||||
#ifdef HAVE_LIBGIF
|
|
||||||
else if ( type == IMAGE_GIF ) {
|
|
||||||
icon_surf = cairo_image_surface_create_from_gif ( icon_path );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else if ( type == IMAGE_JPG || type == IMAGE_JPEG ) {
|
|
||||||
icon_surf = cairo_image_surface_create_from_jpeg ( icon_path );
|
|
||||||
}
|
|
||||||
else if ( type == IMAGE_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 ) {
|
|
||||||
if ( cairo_surface_status ( icon_surf ) == CAIRO_STATUS_SUCCESS ) {
|
|
||||||
float sw = sentry->size / (float) cairo_image_surface_get_width ( icon_surf );
|
|
||||||
float sh = sentry->size / (float) cairo_image_surface_get_height ( icon_surf );
|
|
||||||
|
|
||||||
float scale = ( sw > sh ) ? sh : sw;
|
|
||||||
if ( scale < 0.5 ) {
|
|
||||||
cairo_surface_t * surface = cairo_image_surface_create (
|
|
||||||
cairo_image_surface_get_format ( icon_surf ),
|
|
||||||
cairo_image_surface_get_width ( icon_surf ) * scale,
|
|
||||||
cairo_image_surface_get_height ( icon_surf ) * scale );
|
|
||||||
|
|
||||||
cairo_t *d = cairo_create ( surface );
|
|
||||||
cairo_scale ( d, scale, scale );
|
|
||||||
cairo_set_source_surface ( d, icon_surf, 0.0, 0.0 );
|
|
||||||
cairo_pattern_set_filter ( cairo_get_source ( d ), CAIRO_FILTER_FAST );
|
|
||||||
cairo_paint ( d );
|
|
||||||
|
|
||||||
cairo_destroy ( d );
|
|
||||||
cairo_surface_destroy ( icon_surf );
|
|
||||||
icon_surf = surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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 )
|
uint32_t rofi_icon_fetcher_query ( const char *name, const int size )
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo-xcb.h>
|
#include <cairo-xcb.h>
|
||||||
#include <librsvg/rsvg.h>
|
|
||||||
|
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb/xcb_aux.h>
|
#include <xcb/xcb_aux.h>
|
||||||
|
|
Loading…
Reference in a new issue