4 #include <glib/gi18n-lib.h>
17 #if GTK_MAJOR_VERSION == 2
21 #if defined(__GNUC__) || defined(__clang__)
22 #define DO_PRAGMA(x) _Pragma(#x)
27 #define IGNORE_DEPRECATED \
28 DO_PRAGMA(GCC diagnostic push) \
29 DO_PRAGMA(GCC diagnostic ignored "-Wdeprecated-declarations")
31 DO_PRAGMA(GCC diagnostic pop)
34 cb_sort_settings(girara_setting_t* lhs, girara_setting_t* rhs)
40 ensure_gettext_initialized(
void)
42 static gsize initialized = 0;
43 if (g_once_init_enter(&initialized) == TRUE) {
44 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
45 bind_textdomain_codeset(GETTEXT_PACKAGE,
"UTF-8");
46 g_once_init_leave(&initialized, 1);
53 ensure_gettext_initialized();
55 girara_session_t* session = g_slice_alloc0(
sizeof(girara_session_t));
56 session->private_data = g_slice_alloc0(
sizeof(girara_session_private_t));
83 session->modes.normal = normal_mode;
84 session->modes.current_mode = normal_mode;
85 session->modes.inputbar = inputbar_mode;
102 #if GTK_MAJOR_VERSION == 2
103 session->gtk.box = GTK_BOX(gtk_vbox_new(FALSE, 0));
104 session->private_data->gtk.bottom_box = GTK_BOX(gtk_vbox_new(FALSE, 0));
105 session->gtk.statusbar_entries = GTK_BOX(gtk_hbox_new(FALSE, 0));
106 session->gtk.tabbar = gtk_hbox_new(TRUE, 0);
107 session->gtk.inputbar_box = GTK_BOX(gtk_hbox_new(TRUE, 0));
109 session->gtk.box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
110 session->private_data->gtk.overlay = gtk_overlay_new();
111 session->private_data->gtk.bottom_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
112 session->gtk.statusbar_entries = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
113 session->gtk.tabbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
114 session->gtk.inputbar_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
115 gtk_box_set_homogeneous(GTK_BOX(session->gtk.tabbar), TRUE);
116 gtk_box_set_homogeneous(session->gtk.inputbar_box, TRUE);
118 session->gtk.view = gtk_scrolled_window_new(NULL, NULL);
119 session->gtk.viewport = gtk_viewport_new(NULL, NULL);
120 session->gtk.statusbar = gtk_event_box_new();
121 session->gtk.notification_area = gtk_event_box_new();
122 session->gtk.notification_text = gtk_label_new(NULL);
123 session->gtk.inputbar_dialog = GTK_LABEL(gtk_label_new(NULL));
124 session->gtk.inputbar_entry = GTK_ENTRY(gtk_entry_new());
125 session->gtk.inputbar = gtk_event_box_new();
126 session->gtk.tabs = GTK_NOTEBOOK(gtk_notebook_new());
130 session->settings = session->private_data->settings;
140 if (session == NULL) {
145 if (session->gtk.embed){
146 session->gtk.window = gtk_plug_new(session->gtk.embed);
148 session->gtk.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
151 if (sessionname != NULL) {
152 gtk_widget_set_name(GTK_WIDGET(session->gtk.window), sessionname);
155 GdkGeometry hints = {
168 gtk_window_set_geometry_hints(GTK_WINDOW(session->gtk.window), NULL, &hints, GDK_HINT_MIN_SIZE);
170 #if (GTK_MAJOR_VERSION == 3)
171 gtk_window_set_has_resize_grip(GTK_WINDOW(session->gtk.window), FALSE);
174 #if (GTK_MAJOR_VERSION == 3)
175 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.window), GTK_STATE_NORMAL, &(session->style.default_background));
177 gtk_widget_modify_bg(GTK_WIDGET(session->gtk.window), GTK_STATE_NORMAL, &(session->style.default_background));
181 session->signals.view_key_pressed = g_signal_connect(G_OBJECT(session->gtk.view),
"key-press-event",
184 session->signals.view_button_press_event = g_signal_connect(G_OBJECT(session->gtk.view),
"button-press-event",
187 session->signals.view_button_release_event = g_signal_connect(G_OBJECT(session->gtk.view),
"button-release-event",
190 session->signals.view_motion_notify_event = g_signal_connect(G_OBJECT(session->gtk.view),
"motion-notify-event",
193 session->signals.view_scroll_event = g_signal_connect(G_OBJECT(session->gtk.view),
"scroll-event",
196 bool show_hscrollbar =
false;
197 bool show_vscrollbar =
false;
202 #if (GTK_MAJOR_VERSION == 3)
203 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(session->gtk.view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
205 GtkWidget *vscrollbar = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
206 GtkWidget *hscrollbar = gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
208 if (vscrollbar != NULL) {
209 gtk_widget_set_visible(GTK_WIDGET(vscrollbar), show_vscrollbar);
212 if (hscrollbar != NULL) {
213 gtk_widget_set_visible(GTK_WIDGET(hscrollbar), show_hscrollbar);
216 GtkPolicyType h_policy, v_policy;
217 h_policy = show_hscrollbar ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER;
218 v_policy = show_vscrollbar ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER;
219 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(session->gtk.view), h_policy, v_policy);
223 gtk_container_add(GTK_CONTAINER(session->gtk.view), session->gtk.viewport);
224 gtk_viewport_set_shadow_type(GTK_VIEWPORT(session->gtk.viewport), GTK_SHADOW_NONE);
226 #if (GTK_MAJOR_VERSION == 3)
227 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.viewport), GTK_STATE_NORMAL, &(session->style.default_background));
229 gtk_widget_modify_bg(GTK_WIDGET(session->gtk.viewport), GTK_STATE_NORMAL, &(session->style.default_background));
233 gtk_container_add(GTK_CONTAINER(session->gtk.statusbar), GTK_WIDGET(session->gtk.statusbar_entries));
236 gtk_container_add(GTK_CONTAINER(session->gtk.notification_area), GTK_WIDGET(session->gtk.notification_text));
237 gtk_misc_set_alignment(GTK_MISC(session->gtk.notification_text), 0.0, 0.5);
238 gtk_label_set_use_markup(GTK_LABEL(session->gtk.notification_text), TRUE);
241 gtk_entry_set_has_frame(session->gtk.inputbar_entry, FALSE);
242 gtk_editable_set_editable(GTK_EDITABLE(session->gtk.inputbar_entry), TRUE);
250 guint leftpadding = 4;
253 #if (GTK_MAJOR_VERSION == 3)
255 GtkCssProvider* provider = gtk_css_provider_new();
257 static const char CSS_PATTERN[] =
"#bottom_box { border-style: none; margin: 0px 0px 0px 0px; padding:%dpx 0px %dpx %dpx; }";
258 char* css = g_strdup_printf(CSS_PATTERN, ypadding - ypadding/2, ypadding/2, leftpadding);
259 gtk_css_provider_load_from_data(provider, css, strlen(css), NULL);
262 GdkDisplay* display = gdk_display_get_default();
263 GdkScreen* screen = gdk_display_get_default_screen(display);
264 gtk_style_context_add_provider_for_screen(screen,
265 GTK_STYLE_PROVIDER(provider),
266 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
267 g_object_unref(provider);
269 gtk_widget_set_name(GTK_WIDGET(session->gtk.inputbar_entry),
"bottom_box");
270 gtk_widget_set_name(GTK_WIDGET(session->gtk.notification_text),
"bottom_box");
272 GtkBorder inner_border = {
275 .top = ypadding - ypadding/2,
279 gtk_entry_set_inner_border(session->gtk.inputbar_entry, &inner_border);
284 gtk_widget_size_request(GTK_WIDGET(session->gtk.inputbar_entry), &req);
287 guint statusbar_height = req.height - 5;
290 gtk_widget_set_size_request(GTK_WIDGET(session->gtk.inputbar_entry), -1, statusbar_height);
291 gtk_widget_set_size_request(GTK_WIDGET(session->gtk.statusbar_entries), -1, statusbar_height);
292 gtk_widget_set_size_request(GTK_WIDGET(session->gtk.notification_text), -1, statusbar_height);
295 gtk_misc_set_padding(GTK_MISC(session->gtk.notification_text), leftpadding, 0);
298 session->signals.inputbar_key_pressed = g_signal_connect(
299 G_OBJECT(session->gtk.inputbar_entry),
305 session->signals.inputbar_changed = g_signal_connect(
306 G_OBJECT(session->gtk.inputbar_entry),
312 session->signals.inputbar_activate = g_signal_connect(
313 G_OBJECT(session->gtk.inputbar_entry),
319 gtk_box_set_homogeneous(session->gtk.inputbar_box, FALSE);
320 gtk_box_set_spacing(session->gtk.inputbar_box, 5);
323 gtk_box_pack_start(GTK_BOX(session->gtk.inputbar_box), GTK_WIDGET(session->gtk.inputbar_dialog), FALSE, FALSE, 0);
324 gtk_box_pack_start(GTK_BOX(session->gtk.inputbar_box), GTK_WIDGET(session->gtk.inputbar_entry), TRUE, TRUE, 0);
325 gtk_container_add(GTK_CONTAINER(session->gtk.inputbar), GTK_WIDGET(session->gtk.inputbar_box));
328 gtk_box_set_spacing(session->private_data->gtk.bottom_box, 0);
330 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.inputbar), TRUE, TRUE, 0);
331 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.notification_area), TRUE, TRUE, 0);
332 gtk_box_pack_end(GTK_BOX(session->private_data->gtk.bottom_box), GTK_WIDGET(session->gtk.statusbar), TRUE, TRUE, 0);
335 gtk_notebook_set_show_border(session->gtk.tabs, FALSE);
336 gtk_notebook_set_show_tabs(session->gtk.tabs, FALSE);
338 #if (GTK_MAJOR_VERSION == 3)
340 gtk_box_set_spacing(session->gtk.box, 0);
341 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.tabbar), FALSE, FALSE, 0);
342 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.view), TRUE, TRUE, 0);
345 gtk_container_add(GTK_CONTAINER(session->private_data->gtk.overlay), GTK_WIDGET(session->gtk.box));
347 g_object_set(session->private_data->gtk.bottom_box,
"halign", GTK_ALIGN_FILL, NULL);
348 g_object_set(session->private_data->gtk.bottom_box,
"valign", GTK_ALIGN_END, NULL);
350 gtk_overlay_add_overlay(GTK_OVERLAY(session->private_data->gtk.overlay), GTK_WIDGET(session->private_data->gtk.bottom_box));
351 gtk_container_add(GTK_CONTAINER(session->gtk.window), GTK_WIDGET(session->private_data->gtk.overlay));
355 gtk_box_set_spacing(session->gtk.box, 0);
356 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.tabbar), FALSE, FALSE, 0);
357 gtk_box_pack_start(session->gtk.box, GTK_WIDGET(session->gtk.view), TRUE, TRUE, 0);
358 gtk_box_pack_end(session->gtk.box, GTK_WIDGET(session->private_data->gtk.bottom_box), FALSE, FALSE, 0);
361 gtk_container_add(GTK_CONTAINER(session->gtk.window), GTK_WIDGET(session->gtk.box));
365 typedef struct color_setting_mapping_s
369 } color_setting_mapping_t;
371 const color_setting_mapping_t color_setting_mappings[] = {
372 {
"default-fg", &(session->style.default_foreground)},
373 {
"default-bg", &(session->style.default_background)},
374 {
"inputbar-fg", &(session->style.inputbar_foreground)},
375 {
"inputbar-bg", &(session->style.inputbar_background)},
376 {
"statusbar-fg", &(session->style.statusbar_foreground)},
377 {
"statusbar-bg", &(session->style.statusbar_background)},
378 {
"completion-fg", &(session->style.completion_foreground)},
379 {
"completion-bg", &(session->style.completion_background)},
380 {
"completion-group-fg", &(session->style.completion_group_foreground)},
381 {
"completion-group-bg", &(session->style.completion_group_background)},
382 {
"completion-highlight-fg", &(session->style.completion_highlight_foreground)},
383 {
"completion-highlight-bg", &(session->style.completion_highlight_background)},
384 {
"notification-error-fg", &(session->style.notification_error_foreground)},
385 {
"notification-error-bg", &(session->style.notification_error_background)},
386 {
"notification-warning-fg", &(session->style.notification_warning_foreground)},
387 {
"notification-warning-bg", &(session->style.notification_warning_background)},
388 {
"notification-fg", &(session->style.notification_default_foreground)},
389 {
"notification-bg", &(session->style.notification_default_background)},
390 {
"tabbar-fg", &(session->style.tabbar_foreground)},
391 {
"tabbar-bg", &(session->style.tabbar_background)},
392 {
"tabbar-focus-fg", &(session->style.tabbar_focus_foreground)},
393 {
"tabbar-focus-bg", &(session->style.tabbar_focus_background)},
396 for (
size_t i = 0; i <
LENGTH(color_setting_mappings); i++) {
397 char* tmp_value = NULL;
399 if (tmp_value != NULL) {
400 gdk_rgba_parse(color_setting_mappings[i].color, tmp_value);
406 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.viewport),
407 GTK_STATE_NORMAL, &(session->style.default_background));
410 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.statusbar),
411 GTK_STATE_NORMAL, &(session->style.statusbar_background));
414 #if (GTK_MAJOR_VERSION == 3)
415 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.inputbar_entry),
416 GTK_STATE_NORMAL, &(session->style.inputbar_background));
417 gtk_widget_override_color(GTK_WIDGET(session->gtk.inputbar_entry),
418 GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
420 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.inputbar),
421 GTK_STATE_NORMAL, &(session->style.inputbar_background));
422 gtk_widget_override_color(GTK_WIDGET(session->gtk.inputbar_dialog),
423 GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
426 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
427 GTK_STATE_NORMAL, &(session->style.notification_default_background));
428 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
429 GTK_STATE_NORMAL, &(session->style.notification_default_foreground));
432 gtk_widget_modify_base(GTK_WIDGET(session->gtk.inputbar_entry), GTK_STATE_NORMAL, &(session->style.inputbar_background));
433 gtk_widget_modify_text(GTK_WIDGET(session->gtk.inputbar_entry), GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
435 gtk_widget_modify_bg(GTK_WIDGET(session->gtk.inputbar), GTK_STATE_NORMAL, &(session->style.inputbar_background));
436 gtk_widget_modify_fg(GTK_WIDGET(session->gtk.inputbar_dialog), GTK_STATE_NORMAL, &(session->style.inputbar_foreground));
439 gtk_widget_modify_bg(GTK_WIDGET(session->gtk.notification_area),
440 GTK_STATE_NORMAL, &(session->style.notification_default_background));
441 gtk_widget_modify_text(GTK_WIDGET(session->gtk.notification_text),
442 GTK_STATE_NORMAL, &(session->style.notification_default_foreground));
445 if (session->style.font == NULL) {
449 gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_entry), session->style.font);
450 gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_dialog), session->style.font);
451 gtk_widget_override_font(GTK_WIDGET(session->gtk.notification_text), session->style.font);
455 int window_width = 0;
456 int window_height = 0;
460 if (window_width > 0 && window_height > 0) {
461 gtk_window_set_default_size(GTK_WINDOW(session->gtk.window), window_width, window_height);
464 gtk_widget_show_all(GTK_WIDGET(session->gtk.window));
465 gtk_widget_hide(GTK_WIDGET(session->gtk.notification_area));
466 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar_dialog));
468 if (session->global.autohide_inputbar ==
true) {
469 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
472 if (session->global.hide_statusbar ==
true) {
473 gtk_widget_hide(GTK_WIDGET(session->gtk.statusbar));
476 char* window_icon = NULL;
478 if (window_icon != NULL) {
479 if (strlen(window_icon) != 0) {
485 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
491 girara_session_private_free(girara_session_private_t* session)
493 g_return_if_fail(session != NULL);
497 session->settings = NULL;
499 g_slice_free(girara_session_private_t, session);
505 g_return_val_if_fail(session != NULL, FALSE);
508 if (session->style.font) {
509 pango_font_description_free(session->style.font);
514 session->bindings.shortcuts = NULL;
518 session->bindings.inputbar_shortcuts = NULL;
522 session->bindings.commands = NULL;
526 session->bindings.special_commands = NULL;
530 session->bindings.mouse_events = NULL;
533 g_object_unref(session->command_history);
534 session->command_history = NULL;
538 session->elements.statusbar_items = NULL;
542 session->config.handles = NULL;
546 session->config.shortcut_mappings = NULL;
550 session->config.argument_mappings = NULL;
554 session->modes.identifiers = NULL;
557 if (session->buffer.command) {
558 g_string_free(session->buffer.command, TRUE);
561 if (session->global.buffer) {
562 g_string_free(session->global.buffer, TRUE);
565 session->buffer.command = NULL;
566 session->global.buffer = NULL;
569 girara_session_private_free(session->private_data);
570 session->private_data = NULL;
572 session->settings = NULL;
576 g_slice_free(girara_session_t, session);
584 g_return_val_if_fail(session != NULL, NULL);
586 return (session->global.buffer) ? g_strdup(session->global.buffer->str) : NULL;
590 girara_notify(girara_session_t* session,
int level,
const char* format, ...)
593 || session->gtk.notification_text == NULL
594 || session->gtk.notification_area == NULL
595 || session->gtk.inputbar == NULL
596 || session->gtk.view == NULL) {
602 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
603 GTK_STATE_NORMAL, &(session->style.notification_error_background));
604 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
605 GTK_STATE_NORMAL, &(session->style.notification_error_foreground));
608 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
609 GTK_STATE_NORMAL, &(session->style.notification_warning_background));
610 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
611 GTK_STATE_NORMAL, &(session->style.notification_warning_foreground));
614 gtk_widget_override_background_color(GTK_WIDGET(session->gtk.notification_area),
615 GTK_STATE_NORMAL, &(session->style.notification_default_background));
616 gtk_widget_override_color(GTK_WIDGET(session->gtk.notification_text),
617 GTK_STATE_NORMAL, &(session->style.notification_default_foreground));
625 va_start(ap, format);
626 char* message = g_strdup_vprintf(format, ap);
629 gtk_label_set_markup(GTK_LABEL(session->gtk.notification_text), message);
633 gtk_widget_show(GTK_WIDGET(session->gtk.notification_area));
634 gtk_widget_hide(GTK_WIDGET(session->gtk.inputbar));
636 gtk_widget_grab_focus(GTK_WIDGET(session->gtk.view));
643 if (session == NULL || session->gtk.inputbar == NULL
644 || session->gtk.inputbar_dialog == NULL
645 || session->gtk.inputbar_entry == NULL) {
649 gtk_widget_show(GTK_WIDGET(session->gtk.inputbar_dialog));
652 if (dialog != NULL) {
653 gtk_label_set_markup(session->gtk.inputbar_dialog, dialog);
657 if (invisible ==
true) {
658 gtk_entry_set_visibility(session->gtk.inputbar_entry, FALSE);
660 gtk_entry_set_visibility(session->gtk.inputbar_entry, TRUE);
664 session->signals.inputbar_custom_activate = activate_event;
665 session->signals.inputbar_custom_key_press_event = key_press_event;
666 session->signals.inputbar_custom_data = data;
675 g_return_val_if_fail(session != NULL,
false);
677 GtkWidget* child = gtk_bin_get_child(GTK_BIN(session->gtk.viewport));
681 gtk_container_remove(GTK_CONTAINER(session->gtk.viewport), child);
684 gtk_container_add(GTK_CONTAINER(session->gtk.viewport), widget);
685 gtk_widget_show_all(widget);
693 g_return_if_fail(session != NULL);
695 session->modes.current_mode = mode;
701 g_return_val_if_fail(session != NULL, FALSE);
702 g_return_val_if_fail(name != NULL && name[0] != 0x0, FALSE);
706 if (mode->index > last_index) {
707 last_index = mode->index;
712 girara_mode_string_t* mode = g_slice_new(girara_mode_string_t);
713 mode->index = last_index + 1;
714 mode->name = g_strdup(name);
728 g_slice_free(girara_mode_string_t, mode);
734 g_return_val_if_fail(session != NULL, 0);
736 return session->modes.current_mode;
742 if (session == NULL || session->gtk.window == NULL || name == NULL) {
746 gtk_window_set_title(GTK_WINDOW(session->gtk.window), name);
754 g_return_val_if_fail(session != NULL, NULL);