mirror of
https://github.com/davatorium/rofi.git
synced 2025-04-14 17:43:01 -04:00
Merge remote-tracking branch 'origin/master' into barview
This commit is contained in:
commit
d8b0e24b09
20 changed files with 398 additions and 23 deletions
|
@ -123,6 +123,7 @@ rofi_CFLAGS=\
|
|||
$(pango_CFLAGS)\
|
||||
$(libsn_CFLAGS)\
|
||||
$(cairo_CFLAGS)\
|
||||
$(librsvg_CFLAGS)\
|
||||
-DMANPAGE_PATH="\"$(mandir)/\""\
|
||||
-I$(top_srcdir)/include/\
|
||||
-I$(top_builddir)/lexer/\
|
||||
|
@ -142,6 +143,7 @@ rofi_LDADD=\
|
|||
$(libsn_LIBS)\
|
||||
$(pango_LIBS)\
|
||||
$(cairo_LIBS)\
|
||||
$(librsvg_LIBS)\
|
||||
$(LIBS)
|
||||
|
||||
##
|
||||
|
@ -247,6 +249,7 @@ history_test_CFLAGS=\
|
|||
$(AM_CFLAGS)\
|
||||
$(glib_CFLAGS)\
|
||||
$(libsn_CFLAGS)\
|
||||
$(cairo_CFLAGS)\
|
||||
-DTHEME_DIR=\"$(themedir)\"\
|
||||
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
||||
-I$(top_srcdir)/include/\
|
||||
|
@ -274,6 +277,7 @@ textbox_test_CFLAGS=\
|
|||
$(GW_XCB_CFLAGS)\
|
||||
$(cairo_CFLAGS)\
|
||||
$(libsn_CFLAGS)\
|
||||
$(librsvg_CFLAGS)\
|
||||
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
||||
-DTHEME_DIR=\"$(themedir)\"\
|
||||
-I$(top_srcdir)/include/\
|
||||
|
@ -287,6 +291,7 @@ textbox_test_LDADD=\
|
|||
$(pango_LIBS)\
|
||||
$(GW_XCB_LIBS)\
|
||||
$(cairo_LIBS)\
|
||||
$(librsvg_LIBS)\
|
||||
$(libsn_LIBS)
|
||||
|
||||
helper_pidfile_CFLAGS=$(textbox_test_CFLAGS)
|
||||
|
@ -428,6 +433,7 @@ helper_test_CFLAGS=\
|
|||
$(pango_CFLAGS)\
|
||||
$(GW_XCB_CFLAGS)\
|
||||
$(cairo_CFLAGS)\
|
||||
$(librsvg_CFLAGS)\
|
||||
$(libsn_CFLAGS)\
|
||||
-DPLUGIN_PATH=\"${libdir}/rofi\"\
|
||||
-DTHEME_DIR=\"$(themedir)\"\
|
||||
|
@ -442,6 +448,7 @@ helper_test_LDADD=\
|
|||
$(pango_LIBS)\
|
||||
$(GW_XCB_LIBS)\
|
||||
$(libsn_LIBS)\
|
||||
$(librsvg_LIBS)\
|
||||
$(cairo_LIBS)
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ Settings config = {
|
|||
/** Font */
|
||||
.menu_font = "mono 12",
|
||||
|
||||
/** Row colors */
|
||||
/** Whether to load and show icons */
|
||||
.show_icons = FALSE,
|
||||
|
||||
/** Terminal to use. (for ssh and open in terminal) */
|
||||
.terminal_emulator = "rofi-sensible-terminal",
|
||||
.ssh_client = "ssh",
|
||||
|
@ -58,6 +60,8 @@ Settings config = {
|
|||
.run_shell_command = "{terminal} -e {cmd}",
|
||||
/** Command executed on accep-entry-custom for window modus */
|
||||
.window_command = "xkill -id {window}",
|
||||
/** Sane default for an icon theme */
|
||||
.drun_icon_theme = "gnome",
|
||||
/**
|
||||
* Location of the window.
|
||||
* Enumeration indicating location or gravity of window.
|
||||
|
@ -109,7 +113,7 @@ Settings config = {
|
|||
.dpi = -1,
|
||||
.threads = 0,
|
||||
.scroll_method = 0,
|
||||
.window_format = "{w} {c} {t}",
|
||||
.window_format = "{w} {i}{c} {t}",
|
||||
.click_to_exit = TRUE,
|
||||
.show_match = TRUE,
|
||||
.theme = NULL,
|
||||
|
|
|
@ -116,12 +116,13 @@ PKG_PROG_PKG_CONFIG
|
|||
dnl ---------------------------------------------------------------------
|
||||
dnl PKG_CONFIG based dependencies
|
||||
dnl ---------------------------------------------------------------------
|
||||
NK_INIT([bindings])
|
||||
NK_INIT([bindings xdg-theme])
|
||||
PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40 gio-unix-2.0 gmodule-2.0])
|
||||
GW_CHECK_XCB([xcb-aux xcb-xkb xkbcommon xkbcommon-x11 xcb-ewmh xcb-icccm xcb-xrm xcb-randr xcb-xinerama])
|
||||
PKG_CHECK_MODULES([pango], [pango pangocairo])
|
||||
PKG_CHECK_MODULES([cairo], [cairo cairo-xcb])
|
||||
PKG_CHECK_MODULES([libsn], [libstartup-notification-1.0 ])
|
||||
PKG_CHECK_MODULES([librsvg], [librsvg-2.0 ])
|
||||
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl check - Unit testing.
|
||||
|
|
|
@ -220,6 +220,15 @@ char * rofi_force_utf8 ( const gchar *data, ssize_t length );
|
|||
*/
|
||||
char * rofi_latin_to_utf8_strdup ( const char *input, gssize length );
|
||||
|
||||
/**
|
||||
* @param input the string to escape
|
||||
*
|
||||
* Escape XML markup from the string. @param input is freed.
|
||||
*
|
||||
* @return the escaped string
|
||||
*/
|
||||
gchar *rofi_escape_markup ( gchar *input );
|
||||
|
||||
/**
|
||||
* @param pattern The user input to match against.
|
||||
* @param plen Pattern length.
|
||||
|
|
|
@ -53,6 +53,16 @@ typedef void ( *_mode_free )( Mode *data );
|
|||
*/
|
||||
typedef char * ( *_mode_get_display_value )( const Mode *sw, unsigned int selected_line, int *state, GList **attribute_list, int get_entry );
|
||||
|
||||
/**
|
||||
* @param sw The #Mode pointer
|
||||
* @param selected_line The selected line
|
||||
*
|
||||
* Obtains the icon if available
|
||||
*
|
||||
* @return Get the icon
|
||||
*/
|
||||
typedef cairo_surface_t * ( *_mode_get_icon )( const Mode *sw, unsigned int selected_line, int height );
|
||||
|
||||
/**
|
||||
* @param sw The #Mode pointer
|
||||
* @param selected_line The selected line
|
||||
|
@ -162,6 +172,8 @@ struct rofi_mode
|
|||
_mode_token_match _token_match;
|
||||
/** Get the string to display for the entry. */
|
||||
_mode_get_display_value _get_display_value;
|
||||
/** Get the icon for the entry. */
|
||||
_mode_get_icon _get_icon;
|
||||
/** Get the 'completed' entry. */
|
||||
_mode_get_completion _get_completion;
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#ifndef ROFI_MODE_H
|
||||
#define ROFI_MODE_H
|
||||
|
||||
#include <cairo.h>
|
||||
/**
|
||||
* @defgroup MODE Mode
|
||||
*
|
||||
|
@ -120,6 +122,16 @@ unsigned int mode_get_num_entries ( const Mode *mode );
|
|||
*/
|
||||
char * mode_get_display_value ( const Mode *mode, unsigned int selected_line, int *state, GList **attribute_list, int get_entry );
|
||||
|
||||
/**
|
||||
* @param mode The mode to query
|
||||
* @param selected_line The entry to query
|
||||
*
|
||||
* Returns the icon for the selected_line
|
||||
*
|
||||
* @returns allocated new cairo_surface_t if applicable
|
||||
*/
|
||||
cairo_surface_t * mode_get_icon ( const Mode *mode, unsigned int selected_line, int height );
|
||||
|
||||
/**
|
||||
* @param mode The mode to query
|
||||
* @param selected_line The entry to query
|
||||
|
|
|
@ -97,6 +97,9 @@ typedef struct
|
|||
char * color_urgent;
|
||||
char * color_window;
|
||||
|
||||
/** Whether to load and show icons */
|
||||
gboolean show_icons;
|
||||
|
||||
/** Terminal to use */
|
||||
char * terminal_emulator;
|
||||
/** SSH client to use */
|
||||
|
@ -111,6 +114,8 @@ typedef struct
|
|||
char * run_list_command;
|
||||
/** Command for window */
|
||||
char * window_command;
|
||||
/** Theme for icons */
|
||||
char * drun_icon_theme;
|
||||
|
||||
/** Windows location/gravity */
|
||||
WindowLocation location;
|
||||
|
|
|
@ -59,12 +59,16 @@ typedef struct
|
|||
int markup;
|
||||
int changed;
|
||||
|
||||
cairo_surface_t *icon; // AA TODO - pass in icons for a textbox line if needed
|
||||
int icon_index;
|
||||
|
||||
int blink;
|
||||
guint blink_timeout;
|
||||
|
||||
double yalign ;
|
||||
|
||||
PangoFontMetrics *metrics;
|
||||
int left_offset;
|
||||
//
|
||||
const char *theme_name;
|
||||
} textbox;
|
||||
|
@ -84,6 +88,7 @@ typedef enum
|
|||
TB_WRAP = 1 << 21,
|
||||
TB_PASSWORD = 1 << 22,
|
||||
TB_INDICATOR = 1 << 23,
|
||||
TB_ICON = 1<<24,
|
||||
} TextboxFlags;
|
||||
/**
|
||||
* Flags indicating current state of the textbox.
|
||||
|
@ -143,6 +148,14 @@ void textbox_font ( textbox *tb, TextBoxFontType tbft );
|
|||
*/
|
||||
void textbox_text ( textbox *tb, const char *text );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
* @param text The icon to show on the textbox
|
||||
*
|
||||
* Set the text to show. Cursor is moved to end (if visible)
|
||||
*/
|
||||
void textbox_icon ( textbox *tb, cairo_surface_t *icon );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
* @param action the #KeyBindingAction to execute on textbox
|
||||
|
@ -279,6 +292,14 @@ void textbox_set_pango_context ( const char *font, PangoContext *p );
|
|||
*/
|
||||
void textbox_set_pango_attributes ( textbox *tb, PangoAttrList *list );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
* @param index character index to draw the icon at. -1 for no icon
|
||||
*
|
||||
* Sets the character index where the icon should be drawn
|
||||
*/
|
||||
void textbox_set_icon_index ( textbox *tb, int index );
|
||||
|
||||
/**
|
||||
* @param tb Handle to the textbox
|
||||
*
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define X11_ROFI_HELPER_H
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
#include <librsvg/rsvg.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
|
@ -212,6 +213,13 @@ cairo_surface_t * x11_helper_get_bg_surface ( void );
|
|||
*/
|
||||
cairo_surface_t *x11_helper_get_screenshot_surface ( void );
|
||||
|
||||
/**
|
||||
* Gets a surface from an svg path
|
||||
*
|
||||
* @returns a cairo surface from an svg path
|
||||
*/
|
||||
cairo_surface_t *cairo_image_surface_create_from_svg ( const gchar* file, int height );
|
||||
|
||||
/**
|
||||
* Creates an internal represenation of the available monitors.
|
||||
* Used for positioning rofi.
|
||||
|
|
|
@ -46,6 +46,7 @@ deps = [
|
|||
dependency('pango'),
|
||||
dependency('pangocairo'),
|
||||
dependency('xkbcommon'),
|
||||
dependency('librsvg-2.0'),
|
||||
c_compiler.find_library('m', required: false),
|
||||
]
|
||||
|
||||
|
@ -103,6 +104,7 @@ config_h = configure_file(output: 'config.h', configuration: header_conf)
|
|||
|
||||
nk_modules = [
|
||||
'bindings=true',
|
||||
'xdg-theme=true',
|
||||
]
|
||||
nk = subproject('libnkutils', default_options: nk_modules)
|
||||
nk_options = nk.get_variable('nk_options')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 } };
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Add table
Reference in a new issue