4 #include <glib/gi18n-lib.h>
17 #if defined(__GNUC__) || defined(__clang__)
18 #define DO_PRAGMA(x) _Pragma(#x)
23 #define IGNORE_DEPRECATED \
24 DO_PRAGMA(GCC diagnostic push) \
25 DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations")
27 DO_PRAGMA(GCC diagnostic pop)
30 cb_sort_settings(girara_setting_t* lhs, girara_setting_t* rhs)
36 ensure_gettext_initialized(
void)
38 static gsize initialized = 0;
39 if (g_once_init_enter(&initialized) == TRUE) {
40 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
41 bind_textdomain_codeset(GETTEXT_PACKAGE,
"UTF-8");
42 g_once_init_leave(&initialized, 1);
49 ensure_gettext_initialized();
51 girara_session_t* session = g_slice_alloc0(
sizeof(girara_session_t));
52 session->private_data = g_slice_alloc0(
sizeof(girara_session_private_t));
79 session->modes.normal = normal_mode;
80 session->modes.current_mode = normal_mode;
81 session->modes.inputbar = inputbar_mode;
98 session->gtk.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
99 session->private_data->gtk.overlay = gtk_overlay_new();
100 session->private_data->gtk.bottom_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
101 session->gtk.statusbar_entries = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
102 session->gtk.tabbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
103 session->gtk.inputbar_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
104 gtk_box_set_homogeneous(GTK_BOX(session->gtk.tabbar), TRUE);
105 gtk_box_set_homogeneous(session->gtk.inputbar_box, TRUE);
106 session->gtk.view = gtk_scrolled_window_new(NULL, NULL);
107 session->gtk.viewport = gtk_viewport_new(NULL, NULL);
108 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4
109 gtk_widget_add_events(session->gtk.viewport, GDK_SCROLL_MASK);
111 session->gtk.statusbar = gtk_event_box_new();
112 session->gtk.notification_area = gtk_event_box_new();
113 session->gtk.notification_text = gtk_label_new(NULL);
114 session->gtk.inputbar_dialog = GTK_LABEL(gtk_label_new(NULL));
115 session->gtk.inputbar_entry = GTK_ENTRY(gtk_entry_new());
116 session->gtk.inputbar = gtk_event_box_new();
117 session->gtk.tabs = GTK_NOTEBOOK(gtk_notebook_new());
121 session->settings = session->private_data->settings;
131 if (session == NULL) {
136 if (session->gtk.embed){
137 session->gtk.window = gtk_plug_new(session->gtk.embed);
139 session->gtk.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
142 if (sessionname != NULL) {
143 gtk_widget_set_name(GTK_WIDGET(session->gtk.window), sessionname);
146 GdkGeometry hints = {
159 gtk_window_set_geometry_hints(GTK_WINDOW(session->gtk.window), NULL, &hints, GDK_HINT_MIN_SIZE);
161 gtk_window_set_has_resize_grip(GTK_WINDOW(session->gtk.window), FALSE);
163 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.window), GTK_STATE_NORMAL, &(session->style.default_background));
166 session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view),
"key-press-event",
169 session->signals.view_button_press_event = g_signal_connect(G_OBJECT(session->gtk.view),
"button-press-event",
172 session->signals.view_button_release_event = g_signal_connect(G_OBJECT(session->gtk.view),
"button-release-event",
175 session->signals.view_motion_notify_event = g_signal_connect(G_OBJECT(session->gtk.view),
"motion-notify-event",
178 session->signals.view_scroll_event = g_signal_connect(G_OBJECT(session->gtk.view),
"scroll-event",
181 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(session->gtk.view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
183 char* guioptions = NULL;
186 GtkWidget *vscrollbar = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
187 GtkWidget *hscrollbar = gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
189 if (vscrollbar != NULL) {
190 gtk_widget_set_visible(GTK_WIDGET(vscrollbar), strchr(guioptions,
'v') != NULL);
193 if (hscrollbar != NULL) {
194 gtk_widget_set_visible(GTK_WIDGET(hscrollbar), strchr(guioptions,
'h') != NULL);
199 gtk_container_add(GTK_CONTAINER(session->gtk.view), session->gtk.viewport);
200 gtk_viewport_set_shadow_type(GTK_VIEWPORT(session->gtk.viewport), GTK_SHADOW_NONE);
202 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.viewport), GTK_STATE_NORMAL, &(session->style.default_background));
205 gtk_container_add(GTK_CONTAINER(session->gtk.statusbar), GTK_WIDGET(session->gtk.statusbar_entries));
208 gtk_container_add(GTK_CONTAINER(session->gtk.notification_area), GTK_WIDGET(session->gtk.notification_text));
209 gtk_misc_set_alignment(GTK_MISC(session->gtk.notification_text), 0.0, 0.5);
210 gtk_label_set_use_markup(GTK_LABEL(session->gtk.notification_text), TRUE);
213 gtk_entry_set_has_frame(session->gtk.inputbar_entry, FALSE);
214 gtk_editable_set_editable(GTK_EDITABLE(session->gtk.inputbar_entry), TRUE);
227 GtkCssProvider* provider = gtk_css_provider_new();
229 static const char CSS_PATTERN[] =
"#bottom_box { border-style: none; margin: 0px 0px 0px 0px; padding:%dpx %dpx %dpx %dpx; }";
230 char* css = g_strdup_printf(CSS_PATTERN, ypadding - ypadding/2, xpadding/2, ypadding/2, xpadding - xpadding/2);
231 gtk_css_provider_load_from_data(provider, css, strlen(css), NULL);
234 GdkDisplay* display = gdk_display_get_default();
235 GdkScreen* screen = gdk_display_get_default_screen(display);
236 gtk_style_context_add_provider_for_screen(screen,
237 GTK_STYLE_PROVIDER(provider),
238 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
239 g_object_unref(provider);
241 gtk_widget_set_name(GTK_WIDGET(session->gtk.inputbar_entry),
"bottom_box");
242 gtk_widget_set_name(GTK_WIDGET(session->gtk.notification_text),
"bottom_box");
244 session->signals.inputbar_key_pressed = g_signal_connect(
245 G_OBJECT(session->gtk.inputbar_entry),
251 session->signals.inputbar_changed = g_signal_connect(
252 G_OBJECT(session->gtk.inputbar_entry),
258 session->signals.inputbar_activate = g_signal_connect(
259 G_OBJECT(session->gtk.inputbar_entry),
265 gtk_box_set_homogeneous(session->gtk.inputbar_box, FALSE);
266 gtk_box_set_spacing(session->gtk.inputbar_box, 5);
269 gtk_box_pack_start(GTK_BOX(session->gtk.inputbar_box), GTK_WIDGET(session->gtk.inputbar_dialog), FALSE, FALSE, 0);
270 gtk_box_pack_start(GTK_BOX(session->gtk.inputbar_box), GTK_WIDGET(session->gtk.inputbar_entry), TRUE, TRUE, 0);
271 gtk_container_add(GTK_CONTAINER(session->gtk.inputbar), GTK_WIDGET(session->gtk.inputbar_box));
274 gtk_box_set_spacing(session->private_data->gtk.bottom_box, 0);
276 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.inputbar), TRUE, TRUE, 0);
277 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.notification_area), TRUE, TRUE, 0);
278 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.statusbar), TRUE, TRUE, 0);
281 gtk_notebook_set_show_border(session->gtk.tabs, FALSE);
282 gtk_notebook_set_show_tabs(session->gtk.tabs, FALSE);
285 gtk_box_set_spacing(session->gtk.box, 0);
286 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.tabbar), FALSE, FALSE, 0);
287 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.view), TRUE, TRUE, 0);
290 gtk_container_add(GTK_CONTAINER(session->private_data->gtk.overlay), GTK_WIDGET(session->gtk.box));
292 g_object_set(session->private_data->gtk.bottom_box,
"halign", GTK_ALIGN_FILL, NULL);
293 g_object_set(session->private_data->gtk.bottom_box,
"valign", GTK_ALIGN_END, NULL);
295 gtk_overlay_add_overlay(GTK_OVERLAY(session->private_data->gtk.overlay), GTK_WIDGET(session->private_data->gtk.bottom_box));
296 gtk_container_add(GTK_CONTAINER(session->gtk.window), GTK_WIDGET(session->private_data->gtk.overlay));
299 typedef struct color_setting_mapping_s
303 } color_setting_mapping_t;
305 const color_setting_mapping_t color_setting_mappings[] = {
306 {
"default-fg", &(session->style.default_foreground)},
307 {
"default-bg", &(session->style.default_background)},
308 {
"inputbar-fg", &(session->style.inputbar_foreground)},
309 {
"inputbar-bg", &(session->style.inputbar_background)},
310 {
"statusbar-fg", &(session->style.statusbar_foreground)},
311 {
"statusbar-bg", &(session->style.statusbar_background)},
312 {
"completion-fg", &(session->style.completion_foreground)},
313 {
"completion-bg", &(session->style.completion_background)},
314 {
"completion-group-fg", &(session->style.completion_group_foreground)},
315 {
"completion-group-bg", &(session->style.completion_group_background)},
316 {
"completion-highlight-fg", &(session->style.completion_highlight_foreground)},
317 {
"completion-highlight-bg", &(session->style.completion_highlight_background)},
318 {
"notification-error-fg", &(session->style.notification_error_foreground)},
319 {
"notification-error-bg", &(session->style.notification_error_background)},
320 {
"notification-warning-fg", &(session->style.notification_warning_foreground)},
321 {
"notification-warning-bg", &(session->style.notification_warning_background)},
322 {
"notification-fg", &(session->style.notification_default_foreground)},
323 {
"notification-bg", &(session->style.notification_default_background)},
324 {
"tabbar-fg", &(session->style.tabbar_foreground)},
325 {
"tabbar-bg", &(session->style.tabbar_background)},
326 {
"tabbar-focus-fg", &(session->style.tabbar_focus_foreground)},
327 {
"tabbar-focus-bg", &(session->style.tabbar_focus_background)},
330 for (
size_t i = 0; i <
LENGTH(color_setting_mappings); i++) {
331 char* tmp_value = NULL;
333 if (tmp_value != NULL) {
334 gdk_rgba_parse(color_setting_mappings[i].color, tmp_value);
340 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.viewport),
341 GTK_STATE_NORMAL, &(session->style.default_background));
344 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.statusbar),
345 GTK_STATE_NORMAL, &(session->style.statusbar_background));
348 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.inputbar_entry),
349 GTK_STATE_NORMAL, &(session->style.inputbar_background));
350 gtk_widget_override_color(GTK_WIDGET(session->gtk.inputbar_entry),
351 GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
353 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.inputbar),
354 GTK_STATE_NORMAL, &(session->style.inputbar_background));
355 gtk_widget_override_color(GTK_WIDGET(session->gtk.inputbar_dialog),
356 GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
359 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
360 GTK_STATE_NORMAL, &(session->style.notification_default_background));
361 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
362 GTK_STATE_NORMAL, &(session->style.notification_default_foreground));
364 if (session->style.font == NULL) {
368 gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_entry), session->style.font);
369 gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_dialog), session->style.font);
370 gtk_widget_override_font(GTK_WIDGET(session->gtk.notification_text), session->style.font);
374 int window_width = 0;
375 int window_height = 0;
379 if (window_width > 0 && window_height > 0) {
380 gtk_window_set_default_size(GTK_WINDOW(session->gtk.window), window_width, window_height);
383 gtk_widget_show_all(GTK_WIDGET(session->gtk.window));
384 gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
385 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
387 if (session->global.autohide_inputbar ==
true) {
388 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
391 if (session->global.hide_statusbar ==
true) {
392 gtk_widget_hide(GTK_WIDGET(session->gtk.statusbar));
395 char* window_icon = NULL;
397 if (window_icon != NULL) {
398 if (strlen(window_icon) != 0) {
404 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
410 girara_session_private_free(girara_session_private_t* session)
412 g_return_if_fail(session != NULL);
416 session->settings = NULL;
418 g_slice_free(girara_session_private_t, session);
424 g_return_val_if_fail(session != NULL, FALSE);
427 if (session->style.font) {
428 pango_font_description_free(session->style.font);
433 session->bindings.shortcuts = NULL;
437 session->bindings.inputbar_shortcuts = NULL;
441 session->bindings.commands = NULL;
445 session->bindings.special_commands = NULL;
449 session->bindings.mouse_events = NULL;
452 g_object_unref(session->command_history);
453 session->command_history = NULL;
457 session->elements.statusbar_items = NULL;
461 session->config.handles = NULL;
465 session->config.shortcut_mappings = NULL;
469 session->config.argument_mappings = NULL;
473 session->modes.identifiers = NULL;
476 if (session->buffer.command) {
477 g_string_free(session->buffer.command, TRUE);
480 if (session->global.buffer) {
481 g_string_free(session->global.buffer, TRUE);
484 session->buffer.command = NULL;
485 session->global.buffer = NULL;
488 girara_session_private_free(session->private_data);
489 session->private_data = NULL;
491 session->settings = NULL;
495 g_slice_free(girara_session_t, session);
503 g_return_val_if_fail(session != NULL, NULL);
505 return (session->global.buffer) ? g_strdup(session->global.buffer->str) : NULL;
509 girara_notify(girara_session_t* session,
int level,
const char* format, ...)
512 || session->gtk.notification_text == NULL
513 || session->gtk.notification_area == NULL
514 || session->gtk.inputbar == NULL
515 || session->gtk.view == NULL) {
519 const GdkRGBA* foreground = NULL;
520 const GdkRGBA* background = NULL;
523 foreground = &session->style.notification_error_foreground;
524 background = &session->style.notification_error_background;
527 foreground = &session->style.notification_warning_foreground;
528 background = &session->style.notification_warning_background;
531 foreground = &session->style.notification_default_foreground;
532 background = &session->style.notification_default_background;
538 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
539 GTK_STATE_NORMAL, background);
540 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_text),
541 GTK_STATE_NORMAL, background);
542 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_area),
543 GTK_STATE_NORMAL, foreground);
544 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
545 GTK_STATE_NORMAL, foreground);
549 va_start(ap, format);
550 char* message = g_strdup_vprintf(format, ap);
553 gtk_label_set_markup(GTK_LABEL(session->gtk.notification_text), message);
557 gtk_widget_show(GTK_WIDGET(session->gtk.notification_area));
558 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
560 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
567 if (session == NULL || session->gtk.inputbar == NULL
568 || session->gtk.inputbar_dialog == NULL
569 || session->gtk.inputbar_entry == NULL) {
573 gtk_widget_show(GTK_WIDGET(session->gtk.inputbar_dialog));
576 if (dialog != NULL) {
577 gtk_label_set_markup(session->gtk.inputbar_dialog, dialog);
581 if (invisible ==
true) {
582 gtk_entry_set_visibility(session->gtk.inputbar_entry, FALSE);
584 gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
588 session->signals.inputbar_custom_activate = activate_event;
589 session->signals.inputbar_custom_key_press_event = key_press_event;
590 session->signals.inputbar_custom_data = data;
599 g_return_val_if_fail(session != NULL,
false);
601 GtkWidget* child = gtk_bin_get_child(GTK_BIN(session->gtk.viewport));
605 gtk_container_remove(GTK_CONTAINER(session->gtk.viewport), child);
608 gtk_container_add(GTK_CONTAINER(session->gtk.viewport), widget);
609 gtk_widget_show_all(widget);
610 gtk_widget_grab_focus(session->gtk.view);
618 g_return_if_fail(session != NULL);
620 session->modes.current_mode = mode;
626 g_return_val_if_fail(session != NULL, FALSE);
627 g_return_val_if_fail(name != NULL && name[0] != 0x0, FALSE);
631 if (mode->index > last_index) {
632 last_index = mode->index;
637 girara_mode_string_t* mode = g_slice_new(girara_mode_string_t);
638 mode->index = last_index + 1;
639 mode->name = g_strdup(name);
653 g_slice_free(girara_mode_string_t, mode);
659 g_return_val_if_fail(session != NULL, 0);
661 return session->modes.current_mode;
667 if (session == NULL || session->gtk.window == NULL || name == NULL) {
671 gtk_window_set_title(GTK_WINDOW(session->gtk.window), name);
679 g_return_val_if_fail(session != NULL, NULL);
void girara_config_handle_free(girara_config_handle_t *handle)
void girara_special_command_free(girara_special_command_t *special_command)
HIDDEN void girara_setting_free(girara_setting_t *setting)
bool girara_session_init(girara_session_t *session, const char *sessionname)
bool girara_set_window_title(girara_session_t *session, const char *name)
void girara_list_append(girara_list_t *list, void *data)
HIDDEN void girara_argument_mapping_free(girara_argument_mapping_t *argument_mapping)
void(* girara_free_function_t)(void *data)
bool girara_session_destroy(girara_session_t *session)
bool girara_callback_view_button_release_event(GtkWidget *UNUSED(widget), GdkEventButton *button, girara_session_t *session)
girara_list_t * girara_list_new2(girara_free_function_t gfree)
bool girara_callback_inputbar_changed_event(GtkEditable *entry, girara_session_t *session)
bool girara_sc_focus_inputbar(girara_session_t *session, girara_argument_t *argument, girara_event_t *UNUSED(event), unsigned int UNUSED(t))
HIDDEN void girara_statusbar_item_free(girara_statusbar_item_t *statusbaritem)
bool girara_callback_view_key_press_event(GtkWidget *UNUSED(widget), GdkEventKey *event, girara_session_t *session)
void girara_list_free(girara_list_t *list)
void girara_dialog(girara_session_t *session, const char *dialog, bool invisible, girara_callback_inputbar_key_press_event_t key_press_event, girara_callback_inputbar_activate_t activate_event, void *data)
bool girara_callback_inputbar_key_press_event(GtkWidget *entry, GdkEventKey *event, girara_session_t *session)
girara_mode_t girara_mode_add(girara_session_t *session, const char *name)
HIDDEN void girara_inputbar_shortcut_free(girara_inputbar_shortcut_t *shortcut)
int(* girara_compare_function_t)(const void *data1, const void *data2)
void girara_config_load_default(girara_session_t *session)
bool(* girara_callback_inputbar_key_press_event_t)(GtkWidget *widget, GdkEventKey *event, void *data)
bool girara_set_view(girara_session_t *session, GtkWidget *widget)
bool(* girara_callback_inputbar_activate_t)(GtkEntry *entry, void *data)
HIDDEN void girara_mouse_event_free(girara_mouse_event_t *mouse_event)
HIDDEN void girara_shortcut_mapping_free(girara_shortcut_mapping_t *mapping)
bool girara_setting_get(girara_session_t *session, const char *name, void *dest)
girara_list_t * girara_sorted_list_new2(girara_compare_function_t cmp, girara_free_function_t gfree)
girara_list_t * girara_input_history_list(GiraraInputHistory *history)
bool girara_callback_view_button_motion_notify_event(GtkWidget *UNUSED(widget), GdkEventMotion *button, girara_session_t *session)
void girara_mode_string_free(girara_mode_string_t *mode)
void girara_notify(girara_session_t *session, int level, const char *format,...)
void girara_command_free(girara_command_t *command)
bool girara_callback_inputbar_activate(GtkEntry *entry, girara_session_t *session)
#define IGNORE_DEPRECATED
bool girara_setting_set(girara_session_t *session, const char *name, void *value)
GiraraInputHistory * girara_input_history_new(GiraraInputHistoryIO *io)
const char * girara_setting_get_name(girara_setting_t *setting)
void girara_mode_set(girara_session_t *session, girara_mode_t mode)
bool girara_callback_view_scroll_event(GtkWidget *UNUSED(widget), GdkEventScroll *scroll, girara_session_t *session)
girara_session_t * girara_session_create()
bool girara_callback_view_button_press_event(GtkWidget *UNUSED(widget), GdkEventButton *button, girara_session_t *session)
#define GIRARA_LIST_FOREACH_END(list, type, iter, data)
#define GIRARA_LIST_FOREACH(list, type, iter, data)
girara_list_t * girara_get_command_history(girara_session_t *session)
char * girara_buffer_get(girara_session_t *session)
girara_mode_t girara_mode_get(girara_session_t *session)
HIDDEN void girara_shortcut_free(girara_shortcut_t *shortcut)