Blame src/terminal-search-popover.c

Packit d370c2
/*
Packit d370c2
 * Copyright © 2015 Christian Persch
Packit d370c2
 * Copyright © 2005 Paolo Maggi
Packit d370c2
 * Copyright © 2010 Red Hat (Red Hat author: Behdad Esfahbod)
Packit d370c2
 *
Packit d370c2
 * This program is free software: you can redistribute it and/or modify
Packit d370c2
 * it under the terms of the GNU General Public License as published by
Packit d370c2
 * the Free Software Foundation, either version 3 of the License, or
Packit d370c2
 * (at your option) any later version.
Packit d370c2
 *
Packit d370c2
 * This program is distributed in the hope that it will be useful,
Packit d370c2
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d370c2
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit d370c2
 * GNU General Public License for more details.
Packit d370c2
 *
Packit d370c2
 * You should have received a copy of the GNU General Public License
Packit d370c2
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit d370c2
 */
Packit d370c2
Packit d370c2
#include "config.h"
Packit d370c2
Packit d370c2
#include <glib.h>
Packit d370c2
#include <glib/gi18n.h>
Packit d370c2
#include <gtk/gtk.h>
Packit d370c2
Packit d370c2
#include "terminal-pcre2.h"
Packit d370c2
#include "terminal-search-popover.h"
Packit d370c2
#include "terminal-intl.h"
Packit d370c2
#include "terminal-window.h"
Packit d370c2
#include "terminal-app.h"
Packit d370c2
#include "terminal-libgsystem.h"
Packit d370c2
Packit d370c2
typedef struct _TerminalSearchPopoverPrivate TerminalSearchPopoverPrivate;
Packit d370c2
Packit d370c2
struct _TerminalSearchPopover
Packit d370c2
{
Packit d370c2
  GtkWindow parent_instance;
Packit d370c2
};
Packit d370c2
Packit d370c2
struct _TerminalSearchPopoverClass
Packit d370c2
{
Packit d370c2
  GtkWindowClass parent_class;
Packit d370c2
Packit d370c2
  /* Signals */
Packit d370c2
  void (* search) (TerminalSearchPopover *popover,
Packit d370c2
                   gboolean backward);
Packit d370c2
};
Packit d370c2
Packit d370c2
struct _TerminalSearchPopoverPrivate
Packit d370c2
{
Packit d370c2
  GtkWidget *search_entry;
Packit d370c2
  GtkWidget *search_prev_button;
Packit d370c2
  GtkWidget *search_next_button;
Packit d370c2
  GtkWidget *reveal_button;
Packit d370c2
  GtkWidget *close_button;
Packit d370c2
  GtkWidget *revealer;
Packit d370c2
  GtkWidget *match_case_checkbutton;
Packit d370c2
  GtkWidget *entire_word_checkbutton;
Packit d370c2
  GtkWidget *regex_checkbutton;
Packit d370c2
  GtkWidget *wrap_around_checkbutton;
Packit d370c2
Packit d370c2
  gboolean search_text_changed;
Packit d370c2
Packit d370c2
  /* Cached regex */
Packit d370c2
  gboolean regex_caseless;
Packit d370c2
  char *regex_pattern;
Packit d370c2
  VteRegex *regex;
Packit d370c2
};
Packit d370c2
Packit d370c2
enum {
Packit d370c2
  PROP_0,
Packit d370c2
  PROP_REGEX,
Packit d370c2
  PROP_WRAP_AROUND,
Packit d370c2
  LAST_PROP
Packit d370c2
};
Packit d370c2
Packit d370c2
enum {
Packit d370c2
  SEARCH,
Packit d370c2
  LAST_SIGNAL
Packit d370c2
};
Packit d370c2
Packit d370c2
static guint signals[LAST_SIGNAL];
Packit d370c2
static GParamSpec *pspecs[LAST_PROP];
Packit d370c2
static GtkListStore *history_store;
Packit d370c2
Packit d370c2
G_DEFINE_TYPE_WITH_PRIVATE (TerminalSearchPopover, terminal_search_popover, GTK_TYPE_WINDOW)
Packit d370c2
Packit d370c2
#define PRIV(obj) ((TerminalSearchPopoverPrivate *) terminal_search_popover_get_instance_private ((TerminalSearchPopover *)(obj)))
Packit d370c2
Packit d370c2
/* history */
Packit d370c2
Packit d370c2
#define HISTORY_MIN_ITEM_LEN (3)
Packit d370c2
#define HISTORY_LENGTH (10)
Packit d370c2
Packit d370c2
static gboolean
Packit d370c2
history_enabled (void)
Packit d370c2
{
Packit d370c2
  gboolean enabled;
Packit d370c2
Packit d370c2
  /* not quite an exact setting for this, but close enough… */
Packit d370c2
  g_object_get (gtk_settings_get_default (), "gtk-recent-files-enabled", &enabled, NULL);
Packit d370c2
  if (!enabled)
Packit d370c2
    return FALSE;
Packit d370c2
Packit d370c2
  if (history_store == NULL) {
Packit d370c2
    history_store = gtk_list_store_new (1, G_TYPE_STRING);
Packit d370c2
    g_object_set_data_full (G_OBJECT (terminal_app_get ()), "search-history-store",
Packit d370c2
                            history_store, (GDestroyNotify) g_object_unref);
Packit d370c2
  }
Packit d370c2
Packit d370c2
  return TRUE;
Packit d370c2
}
Packit d370c2
Packit d370c2
static gboolean
Packit d370c2
history_remove_item (const char  *text)
Packit d370c2
{
Packit d370c2
  GtkTreeModel *model = GTK_TREE_MODEL (history_store);
Packit d370c2
  GtkTreeIter iter;
Packit d370c2
Packit d370c2
  if (!gtk_tree_model_get_iter_first (model, &iter))
Packit d370c2
    return FALSE;
Packit d370c2
Packit d370c2
  do {
Packit d370c2
    gs_free gchar *item_text;
Packit d370c2
Packit d370c2
    gtk_tree_model_get (model, &iter, 0, &item_text, -1);
Packit d370c2
Packit d370c2
    if (item_text != NULL && strcmp (item_text, text) == 0) {
Packit d370c2
      gtk_list_store_remove (history_store, &iter);
Packit d370c2
      return TRUE;
Packit d370c2
    }
Packit d370c2
  } while (gtk_tree_model_iter_next (model, &iter));
Packit d370c2
Packit d370c2
  return FALSE;
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
history_clamp (int max)
Packit d370c2
{
Packit d370c2
  GtkTreePath *path;
Packit d370c2
  GtkTreeIter iter;
Packit d370c2
Packit d370c2
  /* -1 because TreePath counts from 0 */
Packit d370c2
  path = gtk_tree_path_new_from_indices (max - 1, -1);
Packit d370c2
Packit d370c2
  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (history_store), &iter, path))
Packit d370c2
    while (1)
Packit d370c2
      if (!gtk_list_store_remove (history_store, &iter))
Packit d370c2
	break;
Packit d370c2
Packit d370c2
  gtk_tree_path_free (path);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
history_insert_item (const char *text)
Packit d370c2
{
Packit d370c2
  GtkTreeIter iter;
Packit d370c2
Packit d370c2
  if (!history_enabled () || text == NULL)
Packit d370c2
    return;
Packit d370c2
Packit d370c2
  if (g_utf8_strlen (text, -1) <= HISTORY_MIN_ITEM_LEN)
Packit d370c2
    return;
Packit d370c2
Packit d370c2
  /* remove the text from the store if it was already
Packit d370c2
   * present. If it wasn't, clamp to max history - 1
Packit d370c2
   * before inserting the new row, otherwise appending
Packit d370c2
   * would not work */
Packit d370c2
  if (!history_remove_item (text))
Packit d370c2
    history_clamp (HISTORY_LENGTH - 1);
Packit d370c2
Packit d370c2
  gtk_list_store_insert_with_values (history_store, &iter, 0,
Packit d370c2
                                     0, text,
Packit d370c2
                                     -1);
Packit d370c2
}
Packit d370c2
Packit d370c2
/* helper functions */
Packit d370c2
Packit d370c2
static void
Packit d370c2
update_sensitivity (TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
  gboolean can_search;
Packit d370c2
Packit d370c2
  can_search = priv->regex != NULL;
Packit d370c2
Packit d370c2
  gtk_widget_set_sensitive (priv->search_prev_button, can_search);
Packit d370c2
  gtk_widget_set_sensitive (priv->search_next_button, can_search);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
perform_search (TerminalSearchPopover *popover,
Packit d370c2
                gboolean backward)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
Packit d370c2
  if (priv->regex == NULL)
Packit d370c2
    return;
Packit d370c2
Packit d370c2
  /* Add to search history */
Packit d370c2
  if (priv->search_text_changed) {
Packit d370c2
    const char *search_text;
Packit d370c2
Packit d370c2
    search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
Packit d370c2
    history_insert_item (search_text);
Packit d370c2
Packit d370c2
    priv->search_text_changed = FALSE;
Packit d370c2
  }
Packit d370c2
Packit d370c2
  g_signal_emit (popover, signals[SEARCH], 0, backward);
Packit d370c2
}
Packit d370c2
Packit d370c2
#if GTK_CHECK_VERSION (3, 16, 0)
Packit d370c2
static void
Packit d370c2
previous_match_cb (GtkWidget *widget,
Packit d370c2
                  TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  perform_search (popover, TRUE);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
next_match_cb (GtkWidget *widget,
Packit d370c2
               TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  perform_search (popover, FALSE);
Packit d370c2
}
Packit d370c2
#endif /* GTK+ 3.16 */
Packit d370c2
Packit d370c2
static void
Packit d370c2
close_clicked_cb (GtkWidget *widget,
Packit d370c2
                  GtkWidget *popover)
Packit d370c2
{
Packit d370c2
  gtk_widget_hide (popover);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
search_button_clicked_cb (GtkWidget *button,
Packit d370c2
                          TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
Packit d370c2
  perform_search (popover, button == priv->search_prev_button);
Packit d370c2
}
Packit d370c2
Packit d370c2
static gboolean
Packit d370c2
key_press_cb (GtkWidget *popover,
Packit d370c2
              GdkEventKey *event,
Packit d370c2
              gpointer user_data G_GNUC_UNUSED)
Packit d370c2
{
Packit d370c2
  if (event->keyval == GDK_KEY_Escape) {
Packit d370c2
    gtk_widget_hide (popover);
Packit d370c2
    return TRUE;
Packit d370c2
  }
Packit d370c2
  return FALSE;
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
update_regex (TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
  const char *search_text;
Packit d370c2
  gboolean caseless;
Packit d370c2
  gs_free char *pattern;
Packit d370c2
  gs_free_error GError *error = NULL;
Packit d370c2
Packit d370c2
  search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
Packit d370c2
Packit d370c2
  caseless = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->match_case_checkbutton));
Packit d370c2
Packit d370c2
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->regex_checkbutton))) {
Packit d370c2
    pattern = g_strdup (search_text);
Packit d370c2
  } else {
Packit d370c2
    pattern = g_regex_escape_string (search_text, -1);
Packit d370c2
  }
Packit d370c2
Packit d370c2
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->entire_word_checkbutton))) {
Packit d370c2
    char *new_pattern;
Packit d370c2
    new_pattern = g_strdup_printf ("\\b%s\\b", pattern);
Packit d370c2
    g_free (pattern);
Packit d370c2
    pattern = new_pattern;
Packit d370c2
  }
Packit d370c2
Packit d370c2
  if (priv->regex_caseless == caseless &&
Packit d370c2
      g_strcmp0 (priv->regex_pattern, pattern) == 0)
Packit d370c2
    return;
Packit d370c2
Packit d370c2
  if (priv->regex) {
Packit d370c2
    vte_regex_unref (priv->regex);
Packit d370c2
  }
Packit d370c2
Packit d370c2
  g_clear_pointer (&priv->regex_pattern, g_free);
Packit d370c2
Packit d370c2
  /* FIXME: if comping the regex fails, show the error message somewhere */
Packit d370c2
  if (search_text[0] != '\0') {
Packit d370c2
    guint32 compile_flags;
Packit d370c2
Packit d370c2
    compile_flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_MULTILINE;
Packit d370c2
    if (caseless)
Packit d370c2
      compile_flags |= PCRE2_CASELESS;
Packit d370c2
Packit d370c2
    priv->regex = vte_regex_new_for_search (pattern, -1, compile_flags, &error);
Packit d370c2
    if (priv->regex != NULL &&
Packit d370c2
        (!vte_regex_jit (priv->regex, PCRE2_JIT_COMPLETE, NULL) ||
Packit d370c2
         !vte_regex_jit (priv->regex, PCRE2_JIT_PARTIAL_SOFT, NULL))) {
Packit d370c2
    }
Packit d370c2
Packit d370c2
    if (priv->regex != NULL)
Packit d370c2
      gs_transfer_out_value (&priv->regex_pattern, &pattern);
Packit d370c2
  } else {
Packit d370c2
    priv->regex = NULL;
Packit d370c2
  }
Packit d370c2
Packit d370c2
  priv->regex_caseless = caseless;
Packit d370c2
Packit d370c2
  update_sensitivity (popover);
Packit d370c2
Packit d370c2
  g_object_notify_by_pspec (G_OBJECT (popover), pspecs[PROP_REGEX]);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
search_text_changed_cb (GtkToggleButton *button,
Packit d370c2
                        TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
Packit d370c2
  update_regex (popover);
Packit d370c2
  priv->search_text_changed = TRUE;
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
search_parameters_changed_cb (GtkToggleButton *button,
Packit d370c2
                              TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  update_regex (popover);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
wrap_around_toggled_cb (GtkToggleButton *button,
Packit d370c2
                        TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  g_object_notify_by_pspec (G_OBJECT (popover), pspecs[PROP_WRAP_AROUND]);
Packit d370c2
}
Packit d370c2
Packit d370c2
/* public functions */
Packit d370c2
Packit d370c2
/* Class implementation */
Packit d370c2
Packit d370c2
static void
Packit d370c2
terminal_search_popover_init (TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
  GtkWidget *widget = GTK_WIDGET (popover);
Packit d370c2
Packit d370c2
  priv->regex_pattern = 0;
Packit d370c2
  priv->regex_caseless = TRUE;
Packit d370c2
Packit d370c2
  gtk_widget_init_template (widget);
Packit d370c2
Packit d370c2
  /* Make the search entry reasonably wide */
Packit d370c2
  gtk_widget_set_size_request (priv->search_entry, 300, -1);
Packit d370c2
Packit d370c2
  /* Add entry completion with history */
Packit d370c2
#if 0
Packit d370c2
  g_object_set (G_OBJECT (priv->search_entry),
Packit d370c2
		"model", history_store,
Packit d370c2
		"entry-text-column", 0,
Packit d370c2
		NULL);
Packit d370c2
#endif
Packit d370c2
Packit d370c2
  if (history_enabled ()) {
Packit d370c2
    gs_unref_object GtkEntryCompletion *completion;
Packit d370c2
Packit d370c2
    completion = gtk_entry_completion_new ();
Packit d370c2
    gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (history_store));
Packit d370c2
    gtk_entry_completion_set_text_column (completion, 0);
Packit d370c2
    gtk_entry_completion_set_minimum_key_length (completion, HISTORY_MIN_ITEM_LEN);
Packit d370c2
    gtk_entry_completion_set_popup_completion (completion, FALSE);
Packit d370c2
    gtk_entry_completion_set_inline_completion (completion, TRUE);
Packit d370c2
    gtk_entry_set_completion (GTK_ENTRY (priv->search_entry), completion);
Packit d370c2
  }
Packit d370c2
Packit d370c2
#if 0 // GTK_CHECK_VERSION (3, 17, 2)
Packit d370c2
  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
Packit d370c2
  gtk_popover_set_default_widget (GTK_POPOVER (popover), priv->search_prev_button);
Packit d370c2
  G_GNUC_END_IGNORE_DEPRECATIONS
Packit d370c2
#else
Packit d370c2
  gtk_window_set_default (GTK_WINDOW (popover), priv->search_prev_button);
Packit d370c2
#endif
Packit d370c2
Packit d370c2
#if GTK_CHECK_VERSION (3, 16, 0)
Packit d370c2
  g_signal_connect (priv->search_entry, "previous-match", G_CALLBACK (previous_match_cb), popover);
Packit d370c2
  g_signal_connect (priv->search_entry, "next-match", G_CALLBACK (next_match_cb), popover);
Packit d370c2
#endif
Packit d370c2
Packit d370c2
  g_signal_connect (priv->search_prev_button, "clicked", G_CALLBACK (search_button_clicked_cb), popover);
Packit d370c2
  g_signal_connect (priv->search_next_button, "clicked", G_CALLBACK (search_button_clicked_cb), popover);
Packit d370c2
Packit d370c2
  g_signal_connect (priv->close_button, "clicked", G_CALLBACK (close_clicked_cb), popover);
Packit d370c2
Packit d370c2
  g_object_bind_property (priv->reveal_button, "active",
Packit d370c2
                          priv->revealer, "reveal-child",
Packit d370c2
                          G_BINDING_DEFAULT);
Packit d370c2
Packit d370c2
  update_sensitivity (popover);
Packit d370c2
Packit d370c2
  g_signal_connect (priv->search_entry, "search-changed", G_CALLBACK (search_text_changed_cb), popover);
Packit d370c2
  g_signal_connect (priv->match_case_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover);
Packit d370c2
  g_signal_connect (priv->entire_word_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover);
Packit d370c2
  g_signal_connect (priv->regex_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover);
Packit d370c2
Packit d370c2
  g_signal_connect (priv->wrap_around_checkbutton, "toggled", G_CALLBACK (wrap_around_toggled_cb), popover);
Packit d370c2
Packit d370c2
  g_signal_connect (popover, "key-press-event", G_CALLBACK (key_press_cb), NULL);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
terminal_search_popover_finalize (GObject *object)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopover *popover = TERMINAL_SEARCH_POPOVER (object);
Packit d370c2
  TerminalSearchPopoverPrivate *priv = PRIV (popover);
Packit d370c2
Packit d370c2
  if (priv->regex) {
Packit d370c2
    vte_regex_unref (priv->regex);
Packit d370c2
  }
Packit d370c2
Packit d370c2
  g_free (priv->regex_pattern);
Packit d370c2
Packit d370c2
  G_OBJECT_CLASS (terminal_search_popover_parent_class)->finalize (object);
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
terminal_search_popover_get_property (GObject *object,
Packit d370c2
                                      guint prop_id,
Packit d370c2
                                      GValue *value,
Packit d370c2
                                      GParamSpec *pspec)
Packit d370c2
{
Packit d370c2
  TerminalSearchPopover *popover = TERMINAL_SEARCH_POPOVER (object);
Packit d370c2
Packit d370c2
  switch (prop_id) {
Packit d370c2
  case PROP_REGEX:
Packit d370c2
    g_value_set_boxed (value, terminal_search_popover_get_regex (popover));
Packit d370c2
    break;
Packit d370c2
  case PROP_WRAP_AROUND:
Packit d370c2
    g_value_set_boolean (value, terminal_search_popover_get_wrap_around (popover));
Packit d370c2
    break;
Packit d370c2
  default:
Packit d370c2
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit d370c2
    break;
Packit d370c2
  }
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
terminal_search_popover_set_property (GObject *object,
Packit d370c2
                                      guint prop_id,
Packit d370c2
                                      const GValue *value,
Packit d370c2
                                      GParamSpec *pspec)
Packit d370c2
{
Packit d370c2
  switch (prop_id) {
Packit d370c2
  case PROP_REGEX:
Packit d370c2
  case PROP_WRAP_AROUND:
Packit d370c2
    /* not writable */
Packit d370c2
    break;
Packit d370c2
  default:
Packit d370c2
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit d370c2
      break;
Packit d370c2
  }
Packit d370c2
}
Packit d370c2
Packit d370c2
static void
Packit d370c2
terminal_search_popover_class_init (TerminalSearchPopoverClass *klass)
Packit d370c2
{
Packit d370c2
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit d370c2
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit d370c2
Packit d370c2
  gobject_class->finalize = terminal_search_popover_finalize;
Packit d370c2
  gobject_class->get_property = terminal_search_popover_get_property;
Packit d370c2
  gobject_class->set_property = terminal_search_popover_set_property;
Packit d370c2
Packit d370c2
  signals[SEARCH] =
Packit d370c2
    g_signal_new (I_("search"),
Packit d370c2
                  G_OBJECT_CLASS_TYPE (gobject_class),
Packit d370c2
                  G_SIGNAL_RUN_LAST,
Packit d370c2
                  G_STRUCT_OFFSET (TerminalSearchPopoverClass, search),
Packit d370c2
                  NULL, NULL,
Packit d370c2
                  g_cclosure_marshal_VOID__BOOLEAN,
Packit d370c2
                  G_TYPE_NONE,
Packit d370c2
                  1,
Packit d370c2
                  G_TYPE_BOOLEAN);
Packit d370c2
Packit d370c2
  pspecs[PROP_REGEX] =
Packit d370c2
    g_param_spec_boxed ("regex", NULL, NULL,
Packit d370c2
                        VTE_TYPE_REGEX,
Packit d370c2
                        G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
Packit d370c2
Packit d370c2
  pspecs[PROP_WRAP_AROUND] =
Packit d370c2
    g_param_spec_boolean ("wrap-around", NULL, NULL,
Packit d370c2
                          FALSE,
Packit d370c2
                          G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
Packit d370c2
Packit d370c2
  g_object_class_install_properties (gobject_class, G_N_ELEMENTS (pspecs), pspecs);
Packit d370c2
Packit d370c2
  gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/terminal/ui/search-popover.ui");
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_entry);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_prev_button);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_next_button);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, reveal_button);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, close_button);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, revealer);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, match_case_checkbutton);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, entire_word_checkbutton);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, regex_checkbutton);
Packit d370c2
  gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, wrap_around_checkbutton);
Packit d370c2
}
Packit d370c2
Packit d370c2
/* public API */
Packit d370c2
Packit d370c2
/**
Packit d370c2
 * terminal_search_popover_new:
Packit d370c2
 *
Packit d370c2
 * Returns: a new #TerminalSearchPopover
Packit d370c2
 */
Packit d370c2
TerminalSearchPopover *
Packit d370c2
terminal_search_popover_new (GtkWidget *relative_to_widget)
Packit d370c2
{
Packit d370c2
  return g_object_new (TERMINAL_TYPE_SEARCH_POPOVER,
Packit d370c2
#if 0
Packit d370c2
                       "relative-to", relative_to_widget,
Packit d370c2
#else
Packit d370c2
                       "transient-for", gtk_widget_get_toplevel (relative_to_widget),
Packit d370c2
#endif
Packit d370c2
                       NULL);
Packit d370c2
}
Packit d370c2
Packit d370c2
/**
Packit d370c2
 * terminal_search_popover_get_regex:
Packit d370c2
 * @popover: a #TerminalSearchPopover
Packit d370c2
 *
Packit d370c2
 * Returns: (transfer none): the search regex, or %NULL
Packit d370c2
 */
Packit d370c2
VteRegex *
Packit d370c2
terminal_search_popover_get_regex (TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  g_return_val_if_fail (TERMINAL_IS_SEARCH_POPOVER (popover), NULL);
Packit d370c2
Packit d370c2
  return PRIV (popover)->regex;
Packit d370c2
}
Packit d370c2
Packit d370c2
/**
Packit d370c2
 * terminal_search_popover_get_wrap_around:
Packit d370c2
 * @popover: a #TerminalSearchPopover
Packit d370c2
 *
Packit d370c2
 * Returns: (transfer none): whether search should wrap around
Packit d370c2
 */
Packit d370c2
gboolean
Packit d370c2
terminal_search_popover_get_wrap_around (TerminalSearchPopover *popover)
Packit d370c2
{
Packit d370c2
  g_return_val_if_fail (TERMINAL_IS_SEARCH_POPOVER (popover), FALSE);
Packit d370c2
Packit d370c2
  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (PRIV (popover)->wrap_around_checkbutton));
Packit d370c2
}