1
0
Fork 0
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:
Dave Davenport 2017-05-31 11:18:30 +02:00
commit d8b0e24b09
20 changed files with 398 additions and 23 deletions

View file

@ -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)

View file

@ -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,

View file

@ -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.

View file

@ -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.

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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
*

View file

@ -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.

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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 ) {

View file

@ -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 );

View file

@ -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 } };

View file

@ -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 );
}

View file

@ -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;
}

View file

@ -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 )

View file

@ -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 },