Commit c18a70d7 authored by Sebastian Ramacher's avatar Sebastian Ramacher

Merge branch 'release/0.3.3'

parents 07e88ec5 d11e5e10
...@@ -11,12 +11,25 @@ enhance the user interface that is used by zathura. ...@@ -11,12 +11,25 @@ enhance the user interface that is used by zathura.
Requirements Requirements
------------ ------------
meson (>= 0.47) The following dependencies are required:
glib (>= 2.50)
gtk3 (>= 3.20) * gtk3 (>= 3.20)
intltool * glib (>= 2.50)
libnotify (optional, for notification support)
json-c (optional, for configuration dumping support) The following dependencies are optional:
* libnotify: notification support
* json-c: configuration dumping support
For building girara, the following dependencies are also required:
* meson (>= 0.48)
* gettext
The following dependencies are optional build-time only dependencies:
* check: for tests
* doxygen: HTML documentation
To disable the optional support for libnotify and json-c, configure the build To disable the optional support for libnotify and json-c, configure the build
system with -Dnotify=disabled or -Djson=disabled. system with -Dnotify=disabled or -Djson=disabled.
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
static void static void
cb_window_icon(girara_session_t* session, const char* UNUSED(name), cb_window_icon(girara_session_t* session, const char* UNUSED(name),
girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
{ {
g_return_if_fail(session != NULL && value != NULL); g_return_if_fail(session != NULL && value != NULL);
...@@ -32,7 +32,7 @@ cb_window_icon(girara_session_t* session, const char* UNUSED(name), ...@@ -32,7 +32,7 @@ cb_window_icon(girara_session_t* session, const char* UNUSED(name),
static void static void
cb_font(girara_session_t* session, const char* UNUSED(name), cb_font(girara_session_t* session, const char* UNUSED(name),
girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
{ {
g_return_if_fail(session != NULL && value != NULL); g_return_if_fail(session != NULL && value != NULL);
...@@ -41,7 +41,7 @@ cb_font(girara_session_t* session, const char* UNUSED(name), ...@@ -41,7 +41,7 @@ cb_font(girara_session_t* session, const char* UNUSED(name),
static void static void
cb_color(girara_session_t* session, const char* name, cb_color(girara_session_t* session, const char* name,
girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
{ {
g_return_if_fail(session != NULL && value != NULL); g_return_if_fail(session != NULL && value != NULL);
...@@ -57,7 +57,7 @@ cb_color(girara_session_t* session, const char* name, ...@@ -57,7 +57,7 @@ cb_color(girara_session_t* session, const char* name,
static void static void
cb_guioptions(girara_session_t* session, const char* UNUSED(name), cb_guioptions(girara_session_t* session, const char* UNUSED(name),
girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
{ {
g_return_if_fail(session != NULL && value != NULL); g_return_if_fail(session != NULL && value != NULL);
...@@ -68,7 +68,7 @@ cb_guioptions(girara_session_t* session, const char* UNUSED(name), ...@@ -68,7 +68,7 @@ cb_guioptions(girara_session_t* session, const char* UNUSED(name),
bool show_vscrollbar = false; bool show_vscrollbar = false;
/* evaluate input */ /* evaluate input */
char* input = (char*) value; const char* input = value;
const size_t input_length = strlen(input); const size_t input_length = strlen(input);
for (size_t i = 0; i < input_length; i++) { for (size_t i = 0; i < input_length; i++) {
...@@ -113,11 +113,11 @@ cb_guioptions(girara_session_t* session, const char* UNUSED(name), ...@@ -113,11 +113,11 @@ cb_guioptions(girara_session_t* session, const char* UNUSED(name),
static void static void
cb_scrollbars(girara_session_t* session, const char* name, cb_scrollbars(girara_session_t* session, const char* name,
girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) girara_setting_type_t UNUSED(type), const void* value, void* UNUSED(data))
{ {
g_return_if_fail(session != NULL && value != NULL); g_return_if_fail(session != NULL && value != NULL);
const bool val = *(bool*) value; const bool val = *(const bool*) value;
char* guioptions = NULL; char* guioptions = NULL;
girara_setting_get(session, "guioptions", &guioptions); girara_setting_get(session, "guioptions", &guioptions);
...@@ -172,14 +172,13 @@ girara_config_load_default(girara_session_t* session) ...@@ -172,14 +172,13 @@ girara_config_load_default(girara_session_t* session)
} }
/* values */ /* values */
int statusbar_h_padding = 8; const int statusbar_h_padding = 8;
int statusbar_v_padding = 2; const int statusbar_v_padding = 2;
int window_width = 800; const int window_width = 800;
int window_height = 600; const int window_height = 600;
int n_completion_items = 15; const int n_completion_items = 15;
bool show_scrollbars = false; const bool show_scrollbars = false;
girara_mode_t normal_mode = session->modes.normal; girara_mode_t normal_mode = session->modes.normal;
bool use_smooth_scroll = false;
/* other values */ /* other values */
session->global.autohide_inputbar = true; session->global.autohide_inputbar = true;
...@@ -218,7 +217,6 @@ girara_config_load_default(girara_session_t* session) ...@@ -218,7 +217,6 @@ girara_config_load_default(girara_session_t* session)
girara_setting_add(session, "window-icon", "", STRING, FALSE, _("Window icon"), cb_window_icon, NULL); girara_setting_add(session, "window-icon", "", STRING, FALSE, _("Window icon"), cb_window_icon, NULL);
girara_setting_add(session, "exec-command", "", STRING, FALSE, _("Command to execute in :exec"), NULL, NULL); girara_setting_add(session, "exec-command", "", STRING, FALSE, _("Command to execute in :exec"), NULL, NULL);
girara_setting_add(session, "guioptions", "s", STRING, FALSE, _("Show or hide certain GUI elements"), cb_guioptions, NULL); girara_setting_add(session, "guioptions", "s", STRING, FALSE, _("Show or hide certain GUI elements"), cb_guioptions, NULL);
girara_setting_add(session, "smooth-scroll", &use_smooth_scroll, BOOLEAN, TRUE, _("Enable smooth scrolling and zooming"), NULL, NULL);
/* shortcuts */ /* shortcuts */
girara_shortcut_add(session, 0, GDK_KEY_Escape, NULL, girara_sc_abort, normal_mode, 0, NULL); girara_shortcut_add(session, 0, GDK_KEY_Escape, NULL, girara_sc_abort, normal_mode, 0, NULL);
...@@ -326,6 +324,7 @@ config_parse(girara_session_t* session, const char* path) ...@@ -326,6 +324,7 @@ config_parse(girara_session_t* session, const char* path)
FILE* file = girara_file_open(path, "r"); FILE* file = girara_file_open(path, "r");
if (file == NULL) { if (file == NULL) {
girara_debug("failed to open config file '%s'", path);
return false; return false;
} }
...@@ -339,22 +338,21 @@ config_parse(girara_session_t* session, const char* path) ...@@ -339,22 +338,21 @@ config_parse(girara_session_t* session, const char* path)
continue; continue;
} }
girara_list_t* argument_list = girara_list_new(); girara_list_t* argument_list = girara_list_new2(g_free);
if (argument_list == NULL) { if (argument_list == NULL) {
g_free(line); g_free(line);
fclose(file); fclose(file);
return false; return false;
} }
girara_list_set_free_function(argument_list, g_free);
gchar** argv = NULL; gchar** argv = NULL;
gint argc = 0; gint argc = 0;
/* parse current line */
if (g_shell_parse_argv(line, &argc, &argv, NULL) != FALSE) { if (g_shell_parse_argv(line, &argc, &argv, NULL) != FALSE) {
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
char* argument = g_strdup(argv[i]); char* argument = g_strdup(argv[i]);
girara_list_append(argument_list, (void*) argument); girara_list_append(argument_list, argument);
} }
} else { } else {
girara_list_free(argument_list); girara_list_free(argument_list);
...@@ -392,18 +390,16 @@ config_parse(girara_session_t* session, const char* path) ...@@ -392,18 +390,16 @@ config_parse(girara_session_t* session, const char* path)
} else { } else {
/* search for config handle */ /* search for config handle */
girara_session_private_t* session_private = session->private_data; girara_session_private_t* session_private = session->private_data;
girara_config_handle_t* handle = NULL; bool found = false;
GIRARA_LIST_FOREACH_BODY(session_private->config.handles, girara_config_handle_t*, tmp, GIRARA_LIST_FOREACH_BODY(session_private->config.handles, girara_config_handle_t*, handle,
handle = tmp;
if (g_strcmp0(handle->identifier, argv[0]) == 0) { if (g_strcmp0(handle->identifier, argv[0]) == 0) {
found = true;
handle->handle(session, argument_list); handle->handle(session, argument_list);
break; break;
} else {
handle = NULL;
} }
); );
if (handle == NULL) { if (found == false) {
girara_warning("Could not process line %d in '%s': Unknown handle '%s'", line_number, path, argv[0]); girara_warning("Could not process line %d in '%s': Unknown handle '%s'", line_number, path, argv[0]);
} }
} }
...@@ -421,5 +417,6 @@ config_parse(girara_session_t* session, const char* path) ...@@ -421,5 +417,6 @@ config_parse(girara_session_t* session, const char* path)
void void
girara_config_parse(girara_session_t* session, const char* path) girara_config_parse(girara_session_t* session, const char* path)
{ {
girara_debug("reading configuration file '%s'", path);
config_parse(session, path); config_parse(session, path);
} }
...@@ -48,8 +48,6 @@ HIDDEN void girara_mouse_event_free(girara_mouse_event_t* mouse_event); ...@@ -48,8 +48,6 @@ HIDDEN void girara_mouse_event_free(girara_mouse_event_t* mouse_event);
HIDDEN void girara_config_load_default(girara_session_t* session); HIDDEN void girara_config_load_default(girara_session_t* session);
HIDDEN void update_state_by_keyval(int *state, int keyval);
HIDDEN void widget_add_class(GtkWidget* widget, const char* styleclass); HIDDEN void widget_add_class(GtkWidget* widget, const char* styleclass);
HIDDEN void widget_remove_class(GtkWidget* widget, const char* styleclass); HIDDEN void widget_remove_class(GtkWidget* widget, const char* styleclass);
...@@ -298,6 +296,8 @@ struct girara_session_private_s ...@@ -298,6 +296,8 @@ struct girara_session_private_s
girara_list_t* shortcut_mappings; girara_list_t* shortcut_mappings;
girara_list_t* argument_mappings; girara_list_t* argument_mappings;
} config; } config;
GMutex feedkeys_mutex;
}; };
#endif #endif
...@@ -11,8 +11,15 @@ ...@@ -11,8 +11,15 @@
#define __has_builtin(x) 0 #define __has_builtin(x) 0
#endif #endif
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
# define GIRARA_GNUC_CHECK(maj, min) \
(((__GNUC__ << 20) + (__GNUC_MINOR__ << 10)) >= (((maj) << 20) + ((min) << 10)))
#else
# define GIRARA_GNUC_CHECK(maj, min) 0
#endif
#ifndef GIRARA_PRINTF #ifndef GIRARA_PRINTF
# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) || defined(__clang__) # if GIRARA_GNUC_CHECK(2, 5) || defined(__clang__)
# define GIRARA_PRINTF(format_idx, arg_idx) \ # define GIRARA_PRINTF(format_idx, arg_idx) \
__attribute__((__format__ (__printf__, format_idx, arg_idx))) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
# else # else
...@@ -31,7 +38,7 @@ ...@@ -31,7 +38,7 @@
#endif #endif
#ifndef GIRARA_HIDDEN #ifndef GIRARA_HIDDEN
# if (defined(__GNUC__) && (__GNUC__ >= 4)) || __has_attribute(visibility) # if GIRARA_GNUC_CHECK(4, 0) || __has_attribute(visibility)
# define GIRARA_HIDDEN __attribute__((visibility("hidden"))) # define GIRARA_HIDDEN __attribute__((visibility("hidden")))
# elif defined(__SUNPRO_C) # elif defined(__SUNPRO_C)
# define GIRARA_HIDDEN __hidden # define GIRARA_HIDDEN __hidden
...@@ -41,7 +48,7 @@ ...@@ -41,7 +48,7 @@
#endif #endif
#ifndef GIRARA_VISIBLE #ifndef GIRARA_VISIBLE
# if (defined(__GNUC__) && (__GNUC__ >= 4)) || __has_attribute(visibility) # if GIRARA_GNUC_CHECK(4, 0) || __has_attribute(visibility)
# define GIRARA_VISIBLE __attribute__((visibility("default"))) # define GIRARA_VISIBLE __attribute__((visibility("default")))
# else # else
# define GIRARA_VISIBLE # define GIRARA_VISIBLE
...@@ -49,7 +56,7 @@ ...@@ -49,7 +56,7 @@
#endif #endif
#ifndef GIRARA_DEPRECATED #ifndef GIRARA_DEPRECATED
# if defined(__GNUC__) # if defined(__GNUC__) || __has_attribute(deprecated)
# define GIRARA_DEPRECATED(x) x __attribute__((deprecated)) # define GIRARA_DEPRECATED(x) x __attribute__((deprecated))
# define GIRARA_DEPRECATED_ __attribute__((deprecated)) # define GIRARA_DEPRECATED_ __attribute__((deprecated))
# else # else
...@@ -59,7 +66,7 @@ ...@@ -59,7 +66,7 @@
#endif #endif
#ifndef GIRARA_ALLOC_SIZE #ifndef GIRARA_ALLOC_SIZE
# if (!defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) || \ # if (!defined(__clang__) && GIRARA_GNUC_CHECK(4, 3)) || \
(defined(__clang__) && __has_attribute(__alloc_size__)) (defined(__clang__) && __has_attribute(__alloc_size__))
# define GIRARA_ALLOC_SIZE(...) __attribute__((alloc_size(__VA_ARGS__))) # define GIRARA_ALLOC_SIZE(...) __attribute__((alloc_size(__VA_ARGS__)))
# else # else
......
...@@ -172,7 +172,7 @@ fill_template_with_values(girara_session_t* session) ...@@ -172,7 +172,7 @@ fill_template_with_values(girara_session_t* session)
}; };
/* parse color values */ /* parse color values */
const char* color_settings[] = { static const char* const color_settings[] = {
"default-fg", "default-fg",
"default-bg", "default-bg",
"inputbar-fg", "inputbar-fg",
...@@ -314,6 +314,7 @@ girara_session_create(void) ...@@ -314,6 +314,7 @@ girara_session_create(void)
session_private->elements.statusbar_items = girara_list_new2( session_private->elements.statusbar_items = girara_list_new2(
(girara_free_function_t) girara_statusbar_item_free); (girara_free_function_t) girara_statusbar_item_free);
g_mutex_init(&session_private->feedkeys_mutex);
/* settings */ /* settings */
session_private->settings = girara_sorted_list_new2( session_private->settings = girara_sorted_list_new2(
...@@ -355,11 +356,11 @@ girara_session_create(void) ...@@ -355,11 +356,11 @@ girara_session_create(void)
girara_config_load_default(session); girara_config_load_default(session);
/* create widgets */ /* create widgets */
session->gtk.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); session->gtk.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
session_private->gtk.overlay = gtk_overlay_new(); session_private->gtk.overlay = gtk_overlay_new();
session_private->gtk.bottom_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); session_private->gtk.bottom_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
session->gtk.statusbar_entries = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); session->gtk.statusbar_entries = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
session->gtk.inputbar_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); session->gtk.inputbar_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
gtk_box_set_homogeneous(session->gtk.inputbar_box, TRUE); gtk_box_set_homogeneous(session->gtk.inputbar_box, TRUE);
session->gtk.view = gtk_scrolled_window_new(NULL, NULL); session->gtk.view = gtk_scrolled_window_new(NULL, NULL);
session->gtk.viewport = gtk_viewport_new(NULL, NULL); session->gtk.viewport = gtk_viewport_new(NULL, NULL);
...@@ -388,11 +389,8 @@ girara_session_init(girara_session_t* session, const char* sessionname) ...@@ -388,11 +389,8 @@ girara_session_init(girara_session_t* session, const char* sessionname)
session->private_data->session_name = g_strdup( session->private_data->session_name = g_strdup(
(sessionname == NULL) ? "girara" : sessionname); (sessionname == NULL) ? "girara" : sessionname);
bool smooth_scroll = false; /* enable smooth scroll events */
girara_setting_get(session, "smooth-scroll", &smooth_scroll); gtk_widget_add_events(session->gtk.viewport, GDK_SMOOTH_SCROLL_MASK);
if (smooth_scroll == true) {
gtk_widget_add_events(session->gtk.viewport, GDK_SMOOTH_SCROLL_MASK);
}
/* load CSS style */ /* load CSS style */
fill_template_with_values(session); fill_template_with_values(session);
...@@ -615,6 +613,9 @@ girara_session_private_free(girara_session_private_t* session) ...@@ -615,6 +613,9 @@ girara_session_private_free(girara_session_private_t* session)
girara_list_free(session->settings); girara_list_free(session->settings);
session->settings = NULL; session->settings = NULL;
/* clean up mutex */
g_mutex_clear(&session->feedkeys_mutex);
g_slice_free(girara_session_private_t, session); g_slice_free(girara_session_private_t, session);
} }
......
...@@ -36,19 +36,19 @@ struct girara_setting_s ...@@ -36,19 +36,19 @@ struct girara_setting_s
}; };
void void
girara_setting_set_value(girara_session_t* session, girara_setting_t* setting, void* value) girara_setting_set_value(girara_session_t* session, girara_setting_t* setting, const void* value)
{ {
g_return_if_fail(setting && (value || setting->type == STRING)); g_return_if_fail(setting && (value || setting->type == STRING));
switch(setting->type) { switch(setting->type) {
case BOOLEAN: case BOOLEAN:
setting->value.b = *((bool *) value); setting->value.b = *((const bool *) value);
break; break;
case FLOAT: case FLOAT:
setting->value.f = *((float *) value); setting->value.f = *((const float *) value);
break; break;
case INT: case INT:
setting->value.i = *((int *) value); setting->value.i = *((const int *) value);
break; break;
case STRING: case STRING:
if (setting->value.s != NULL) { if (setting->value.s != NULL) {
...@@ -66,7 +66,7 @@ girara_setting_set_value(girara_session_t* session, girara_setting_t* setting, v ...@@ -66,7 +66,7 @@ girara_setting_set_value(girara_session_t* session, girara_setting_t* setting, v
} }
bool bool
girara_setting_add(girara_session_t* session, const char* name, void* value, girara_setting_type_t type, bool init_only, const char* description, girara_setting_callback_t callback, void* data) girara_setting_add(girara_session_t* session, const char* name, const void* value, girara_setting_type_t type, bool init_only, const char* description, girara_setting_callback_t callback, void* data)
{ {
g_return_val_if_fail(session != NULL, false); g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(name != NULL, false); g_return_val_if_fail(name != NULL, false);
...@@ -97,7 +97,7 @@ girara_setting_add(girara_session_t* session, const char* name, void* value, gir ...@@ -97,7 +97,7 @@ girara_setting_add(girara_session_t* session, const char* name, void* value, gir
} }
bool bool
girara_setting_set(girara_session_t* session, const char* name, void* value) girara_setting_set(girara_session_t* session, const char* name, const void* value)
{ {
g_return_val_if_fail(session != NULL, false); g_return_val_if_fail(session != NULL, false);
g_return_val_if_fail(name != NULL, false); g_return_val_if_fail(name != NULL, false);
...@@ -116,24 +116,31 @@ girara_setting_get_value(girara_setting_t* setting, void* dest) ...@@ -116,24 +116,31 @@ girara_setting_get_value(girara_setting_t* setting, void* dest)
{ {
g_return_val_if_fail(setting != NULL && dest != NULL, false); g_return_val_if_fail(setting != NULL && dest != NULL, false);
bool *bvalue = (bool*) dest;
float *fvalue = (float*) dest;
int *ivalue = (int*) dest;
char **svalue = (char**) dest;
switch(setting->type) { switch(setting->type) {
case BOOLEAN: case BOOLEAN:
{
bool *bvalue = (bool *)dest;
*bvalue = setting->value.b; *bvalue = setting->value.b;
break; break;
}
case FLOAT: case FLOAT:
{
float *fvalue = (float *)dest;
*fvalue = setting->value.f; *fvalue = setting->value.f;
break; break;
}
case INT: case INT:
{
int *ivalue = (int*) dest;
*ivalue = setting->value.i; *ivalue = setting->value.i;
break; break;
}
case STRING: case STRING:
{
char **svalue = (char**) dest;
*svalue = setting->value.s ? g_strdup(setting->value.s) : NULL; *svalue = setting->value.s ? g_strdup(setting->value.s) : NULL;
break; break;
}
default: default:
g_assert(false); g_assert(false);
} }
...@@ -244,8 +251,6 @@ girara_cmd_dump_config(girara_session_t* session, girara_list_t* argument_list) ...@@ -244,8 +251,6 @@ girara_cmd_dump_config(girara_session_t* session, girara_list_t* argument_list)
_("Invalid number of arguments passed: %zu instead of 1"), _("Invalid number of arguments passed: %zu instead of 1"),
number_of_arguments); number_of_arguments);
return false; return false;
return false;
} }
json_object* json_config = json_object_new_object(); json_object* json_config = json_object_new_object();
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* @return FALSE An error occurred * @return FALSE An error occurred
*/ */
bool girara_setting_add(girara_session_t* session, const char* name, bool girara_setting_add(girara_session_t* session, const char* name,
void* value, girara_setting_type_t type, bool init_only, const void* value, girara_setting_type_t type, bool init_only,
const char* description, girara_setting_callback_t callback, void* data) GIRARA_VISIBLE; const char* description, girara_setting_callback_t callback, void* data) GIRARA_VISIBLE;
/** /**
...@@ -33,7 +33,7 @@ bool girara_setting_add(girara_session_t* session, const char* name, ...@@ -33,7 +33,7 @@ bool girara_setting_add(girara_session_t* session, const char* name,
* @return TRUE No error occurred * @return TRUE No error occurred
* @return FALSE An error occurred * @return FALSE An error occurred
*/ */
bool girara_setting_set(girara_session_t* session, const char* name, void* value) GIRARA_VISIBLE; bool girara_setting_set(girara_session_t* session, const char* name, const void* value) GIRARA_VISIBLE;
/** /**
* Retrieve the value of a setting. If the setting is a string, the value stored * Retrieve the value of a setting. If the setting is a string, the value stored
...@@ -89,6 +89,6 @@ girara_setting_type_t girara_setting_get_type(girara_setting_t* setting) GIRARA_ ...@@ -89,6 +89,6 @@ girara_setting_type_t girara_setting_get_type(girara_setting_t* setting) GIRARA_
* @param value The new value * @param value The new value
*/ */
void girara_setting_set_value(girara_session_t* session, void girara_setting_set_value(girara_session_t* session,
girara_setting_t* setting, void* value) GIRARA_VISIBLE; girara_setting_t* setting, const void* value) GIRARA_VISIBLE;
#endif #endif
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "datastructures.h" #include "datastructures.h"
#include "input-history.h" #include "input-history.h"
#include "internal.h" #include "internal.h"
#include "log.h"
#include "session.h" #include "session.h"
#include "settings.h" #include "settings.h"
...@@ -12,7 +13,6 @@ ...@@ -12,7 +13,6 @@
#include <string.h> #include <string.h>
static void girara_toggle_widget_visibility(GtkWidget* widget); static void girara_toggle_widget_visibility(GtkWidget* widget);
static bool simulate_key_press(girara_session_t* session, int state, int key);
bool bool
girara_shortcut_add(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_shortcut_function_t function, girara_mode_t mode, int argument_n, void* argument_data) girara_shortcut_add(girara_session_t* session, guint modifier, guint key, const char* buffer, girara_shortcut_function_t function, girara_mode_t mode, int argument_n, void* argument_data)
...@@ -460,6 +460,60 @@ girara_sc_exec(girara_session_t* session, girara_argument_t* argument, girara_ev ...@@ -460,6 +460,60 @@ girara_sc_exec(girara_session_t* session, girara_argument_t* argument, girara_ev
return false; return false;
} }
static bool
simulate_key_press(girara_session_t* session, int state, int key)
{
if (session == NULL || session->gtk.box == NULL) {
return false;
}
GdkEvent* event = gdk_event_new(GDK_KEY_PRESS);
event->any.type = GDK_KEY_PRESS;
event->key.window = g_object_ref(gtk_widget_get_parent_window(GTK_WIDGET(session->gtk.box)));
event->key.send_event = false;
event->key.time = GDK_CURRENT_TIME;
event->key.state = state;
event->key.keyval = key;
GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(session->gtk.box));
GdkKeymapKey* keys = NULL;
gint number_of_keys = 0;
if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_for_display(display),
event->key.keyval, &keys, &number_of_keys) == FALSE) {
gdk_event_free(event);
return false;
}
event->key.hardware_keycode = keys[0].keycode;
event->key.group = keys[0].group;
g_free(keys);
gdk_event_put(event);
gdk_event_free(event);
gtk_main_iteration_do(FALSE);
return true;
}
static int
update_state_by_keyval(int state, int keyval)
{
/* The following is probably not true for some keyboard layouts. */
if ((keyval >= '!' && keyval <= '/')
|| (keyval >= ':' && keyval <= '@')
|| (keyval >= '[' && keyval <= '`')
|| (keyval >= '{' && keyval <= '~')
) {
state |= GDK_SHIFT_MASK;
}
return state;
}
bool bool
girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument, girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,
girara_event_t* UNUSED(event), unsigned int t) girara_event_t* UNUSED(event), unsigned int t)
...@@ -468,6 +522,11 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument, ...@@ -468,6 +522,11 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,
return false; return false;
} }
if (g_mutex_trylock(&session->private_data->feedkeys_mutex) == FALSE) {
girara_error("Recursive use of feedkeys detected. Aborting evaluation.");
return false;
}
typedef struct gdk_keyboard_button_s { typedef struct gdk_keyboard_button_s {
char* identifier; char* identifier;
int keyval; int keyval;
...@@ -507,7 +566,7 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument, ...@@ -507,7 +566,7 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,
char* input = (char*) argument->data; char* input = (char*) argument->data;
unsigned int input_length = strlen(input); unsigned int input_length = strlen(input);
t = (t == 0) ? 1 : t; t = MAX(1, t);
for (unsigned int c = 0; c < t; c++) { for (unsigned int c = 0; c < t; c++) {
for (unsigned i = 0; i < input_length; i++) { for (unsigned i = 0; i < input_length; i++) {
int state = 0; int state = 0;
...@@ -520,7 +579,7 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument, ...@@ -520,7 +579,7 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,
goto single_key; goto single_key;
} }
int length = end - (input + i) - 1; const int length = end - (input + i) - 1;
char* tmp = g_strndup(input + i + 1, length); char* tmp = g_strndup(input + i + 1, length);
bool found = false; bool found = false;
...@@ -572,12 +631,12 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument, ...@@ -572,12 +631,12 @@ girara_sc_feedkeys(girara_session_t* session, girara_argument_t* argument,