summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Davenport <qball@gmpclient.org>2016-04-10 12:05:34 +0200
committerDave Davenport <qball@gmpclient.org>2016-04-10 12:05:34 +0200
commite54e012500ecf2ebd35bbfef669f3971fb199bad (patch)
treeb6dea9aecbe38249641042f9f1906533d7918018
parentc3b236db28538d5f53dd085c3d52092f3d3e7fcf (diff)
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.
-rw-r--r--include/helper.h5
-rw-r--r--include/mode.h2
-rw-r--r--include/x11-helper.h2
-rw-r--r--source/dialogs/dmenu.c6
-rw-r--r--source/dialogs/window.c13
-rw-r--r--source/helper.c39
-rw-r--r--source/rofi.c4
-rw-r--r--source/x11-helper.c15
8 files changed, 73 insertions, 13 deletions
diff --git a/include/helper.h b/include/helper.h
index eae59ce1..de6f1097 100644
--- a/include/helper.h
+++ b/include/helper.h
@@ -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
diff --git a/include/mode.h b/include/mode.h
index 90bae0f3..aaf38566 100644
--- a/include/mode.h
+++ b/include/mode.h
@@ -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.
diff --git a/include/x11-helper.h b/include/x11-helper.h
index a1435c3f..730724bc 100644
--- a/include/x11-helper.h
+++ b/include/x11-helper.h
@@ -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 };
diff --git a/source/dialogs/dmenu.c b/source/dialogs/dmenu.c
index 02594572..2ca1540e 100644
--- a/source/dialogs/dmenu.c
+++ b/source/dialogs/dmenu.c
@@ -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;
diff --git a/source/dialogs/window.c b/source/dialogs/window.c
index 5c2bdc11..57684151 100644
--- a/source/dialogs/window.c
+++ b/source/dialogs/window.c
@@ -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;
diff --git a/source/helper.c b/source/helper.c
index 2485e802..955939e6 100644
--- a/source/helper.c
+++ b/source/helper.c
@@ -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 );
+}
diff --git a/source/rofi.c b/source/rofi.c
index eba030ba..7f708f3b 100644
--- a/source/rofi.c
+++ b/source/rofi.c
@@ -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 );
diff --git a/source/x11-helper.c b/source/x11-helper.c
index 9a98d507..f56122ab 100644
--- a/source/x11-helper.c
+++ b/source/x11-helper.c
@@ -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;
}