Issue: #381: Try to handle X11 input and UTF-8 better.

In window_get_text_prop do conversion when input is of type STRING. (latin1) to utf8.
Dmenu: don't skip invalid lines, but try to display as much as possible.
Window mode: Double check all input from X.
This commit is contained in:
Dave Davenport 2016-04-10 12:05:34 +02:00
parent c3b236db28
commit e54e012500
8 changed files with 73 additions and 13 deletions

View File

@ -166,5 +166,10 @@ void cmd_set_arguments ( int argc, char **argv );
char *rofi_expand_path ( const char *input );
unsigned int levenshtein ( const char *needle, const char *haystack );
/**
* Convert string to valid utf-8, replacing invalid parts with replacement character.
*/
char * rofi_force_utf8 ( gchar *data );
char * rofi_latin_to_utf8_strdup ( const char *input, gssize length );
/*@}*/
#endif // ROFI_HELPER_H

View File

@ -7,7 +7,7 @@
* The 'object' that makes a mode in rofi.
* @{
*/
typedef struct rofi_mode Mode;
typedef struct rofi_mode Mode;
/**
* Enum used to sum the possible states of ROFI.

View File

@ -36,6 +36,8 @@ void window_set_atom_prop ( xcb_window_t w, xcb_atom_t prop, xcb_atom_t *atoms,
#define EWMH_ATOMS( X ) \
X ( _NET_WM_WINDOW_OPACITY ), \
X ( I3_SOCKET_PATH ), \
X ( UTF8_STRING ), \
X ( STRING ), \
X ( WM_WINDOW_ROLE )
enum { EWMH_ATOMS ( ATOM_ENUM ), NUM_NETATOMS };

View File

@ -92,10 +92,8 @@ static char **get_dmenu ( DmenuModePrivateData *pd, FILE *fd, unsigned int *leng
data[l - 1] = '\0';
l--;
}
if ( !g_utf8_validate ( data, l, NULL ) ) {
fprintf ( stderr, "String: '%s' is not valid utf-8\n", data );
continue;
}
data = rofi_force_utf8 ( data );
printf ( "data: %s\n", data );
retv[( *length )] = data;
data = NULL;

View File

@ -53,8 +53,6 @@
#define WINLIST 32
#define CLIENTTITLE 100
#define CLIENTCLASS 50
#define CLIENTSTATE 10
#define CLIENTWINDOWTYPE 10
#define CLIENTROLE 50
@ -285,7 +283,8 @@ static client* window_client ( xcb_window_t win )
cky = xcb_icccm_get_wm_class ( xcb->connection, c->window );
xcb_icccm_get_wm_class_reply_t wcr;
if ( xcb_icccm_get_wm_class_reply ( xcb->connection, cky, &wcr, NULL ) ) {
c->class = g_strdup ( wcr.class_name );
c->class = rofi_latin_to_utf8_strdup ( wcr.class_name, -1 );
c->name = rofi_latin_to_utf8_strdup ( wcr.instance_name, -1 );
xcb_icccm_get_wm_class_reply_wipe ( &wcr );
}
@ -295,6 +294,14 @@ static client* window_client ( xcb_window_t win )
c->hint_flags = r.flags;
}
/** Do UTF-8 Check, should not be needed, does not hurt here to be paranoid. */
{
c->title = rofi_force_utf8 ( c->title );
c->class = rofi_force_utf8 ( c->class );
c->name = rofi_force_utf8 ( c->name );
c->role = rofi_force_utf8 ( c->role );
}
winlist_append ( cache_client, c->window, c );
g_free ( attr );
return c;

View File

@ -659,3 +659,42 @@ unsigned int levenshtein ( const char *needle, const char *haystack )
}
return column[needlelen];
}
char * rofi_latin_to_utf8_strdup ( const char *input, gssize length )
{
gsize slength = 0;
return g_convert_with_fallback ( input, length, "UTF-8", "latin1", "\uFFFD", NULL, &slength, NULL );
}
char * rofi_force_utf8 ( gchar *start )
{
if ( start == NULL ) {
return NULL;
}
const char *data = start;
const char *end;
gsize length = strlen ( data );
GString *string;
if ( g_utf8_validate ( data, length, &end ) ) {
return start;
}
string = g_string_sized_new ( length + 16 );
do {
/* Valid part of the string */
g_string_append_len ( string, data, end - data );
/* Replacement character */
g_string_append ( string, "\uFFFD" );
length -= ( end - data ) + 1;
data = end + 1;
} while ( !g_utf8_validate ( data, length, &end ) );
if ( length ) {
g_string_append_len ( string, data, length );
}
// Free input string.
g_free ( start );
return g_string_free ( string, FALSE );
}

View File

@ -626,8 +626,8 @@ int main ( int argc, char *argv[] )
// 2 the binary that executed is called dmenu (e.g. symlink to rofi)
else{
// Get the base name of the executable called.
char *base_name = g_path_get_basename ( argv[0] );
const char * const dmenu_str = "dmenu";
char *base_name = g_path_get_basename ( argv[0] );
const char * const dmenu_str = "dmenu";
dmenu_mode = ( strcmp ( base_name, dmenu_str ) == 0 );
// Free the basename for dmenu detection.
g_free ( base_name );

View File

@ -39,6 +39,7 @@
#include "xcb-internal.h"
#include "xcb.h"
#include "settings.h"
#include "helper.h"
#include <rofi.h>
#define OVERLAP( a, b, c, \
@ -90,9 +91,17 @@ char* window_get_text_prop ( xcb_window_t w, xcb_atom_t atom )
xcb_get_property_reply_t *r = xcb_get_property_reply ( xcb->connection, c, NULL );
if ( r ) {
if ( xcb_get_property_value_length ( r ) > 0 ) {
char *str = g_malloc ( xcb_get_property_value_length ( r ) + 1 );
memcpy ( str, xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) );
str[xcb_get_property_value_length ( r )] = '\0';
char *str = NULL;
if ( r->type == netatoms[UTF8_STRING] ) {
str = g_strndup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) );
}
else if ( r->type == netatoms[STRING] ) {
str = rofi_latin_to_utf8_strdup ( xcb_get_property_value ( r ), xcb_get_property_value_length ( r ) );
}
else {
str = g_strdup ( "Invalid encoding." );
}
free ( r );
return str;
}