Exemple #1
0
static void
ide_run_manager_run_cb (GObject      *object,
                        GAsyncResult *result,
                        gpointer      user_data)
{
  IdeRunner *runner = (IdeRunner *)object;
  g_autoptr(GTask) task = user_data;
  IdeRunManager *self;
  GError *error = NULL;

  IDE_ENTRY;

  g_assert (IDE_IS_RUNNER (runner));
  g_assert (G_IS_TASK (task));

  self = g_task_get_source_object (task);

  if (!ide_runner_run_finish (runner, result, &error))
    {
      g_task_return_error (task, error);
      IDE_GOTO (failure);
    }

  g_task_return_boolean (task, TRUE);

failure:

  g_signal_emit (self, signals [STOPPED], 0);

  IDE_EXIT;
}
Exemple #2
0
static void
ide_editor_perspective_focus_location_cb (GObject      *object,
                                          GAsyncResult *result,
                                          gpointer      user_data)
{
  IdeBufferManager *bufmgr = (IdeBufferManager *)object;
  FocusLocation *state = user_data;
  GError *error = NULL;

  IDE_ENTRY;

  g_assert (IDE_IS_BUFFER_MANAGER (bufmgr));
  g_assert (state != NULL);
  g_assert (IDE_IS_EDITOR_PERSPECTIVE (state->self));
  g_assert (state->location != NULL);

  if (!ide_buffer_manager_load_file_finish (bufmgr, result, &error))
    {
      /* TODO: display warning breifly to the user in the frame? */
      g_warning ("%s", error->message);
      g_clear_error (&error);
      IDE_GOTO (cleanup);
    }

  /* try again now that we have loaded */
  ide_editor_perspective_focus_location_full (state->self, state->location, FALSE);

cleanup:
  g_clear_object (&state->self);
  g_clear_pointer (&state->location, ide_source_location_unref);
  g_slice_free (FocusLocation, state);

  IDE_EXIT;
}
static void
buffer_delete_range_cb (GbpGitBufferChangeMonitor *self,
                        GtkTextIter               *begin,
                        GtkTextIter               *end,
                        IdeBuffer                 *buffer)
{
  guint begin_line;

  g_assert (GBP_IS_GIT_BUFFER_CHANGE_MONITOR (self));
  g_assert (begin != NULL);
  g_assert (end != NULL);
  g_assert (IDE_IS_BUFFER (buffer));

  begin_line = gtk_text_iter_get_line (begin);

  /*
   * We need to recalculate the diff when text is deleted if:
   *
   * 1) The range includes a newline.
   * 2) The current line change is set to NONE.
   *
   * Technically we need to do it on every change to be more correct, but that
   * wastes a lot of power. So instead, we'll be a bit lazy about it here and
   * pick up the other changes on a much more conservative timeout, generated
   * by gbp_git_buffer_change_monitor__buffer_changed_cb().
   */

  if (begin_line != gtk_text_iter_get_line (end))
    IDE_GOTO (recalculate);

  if (self->cache == NULL || !line_cache_get_mark (self->cache, begin_line))
    IDE_GOTO (recalculate);

  return;

recalculate:
  /*
   * We need to wait for the delete to occur, so mark it as necessary and let
   * gbp_git_buffer_change_monitor__buffer_delete_range_after_cb perform the
   * operation.
   */
  self->delete_range_requires_recalculation = TRUE;
}
static gchar *
ide_xml_indenter_maybe_unindent (IdeXmlIndenter *xml,
                                 GtkTextIter    *begin,
                                 GtkTextIter    *end)
{
  GtkTextIter tmp;
  gunichar ch;

  g_return_val_if_fail (IDE_IS_XML_INDENTER (xml), NULL);
  g_return_val_if_fail (begin, NULL);
  g_return_val_if_fail (end, NULL);

  tmp = *begin;

  if (!gtk_text_iter_backward_char (&tmp))
    return NULL;

  if (('/' == gtk_text_iter_get_char (&tmp)) &&
      gtk_text_iter_backward_char (&tmp) &&
      ('<' == gtk_text_iter_get_char (&tmp)) &&
      (ch = text_iter_peek_prev_char (&tmp)) &&
      ((ch == ' ') || (ch == '\t')))
    {
      if (ch == '\t')
        {
          gtk_text_iter_backward_char (&tmp);
          *begin = tmp;
          return g_strdup ("</");
        }
      else
        {
          gint count = xml->indent_width;

          while (count > 0)
            {
              if (!gtk_text_iter_backward_char (&tmp) ||
                  !(ch = gtk_text_iter_get_char (&tmp)) ||
                  (ch != ' '))
                return NULL;
              count--;
              if (count == 0)
                IDE_GOTO (success);
            }
        }
    }

  return NULL;

success:
  *begin = tmp;
  return g_strdup ("</");
}
Exemple #5
0
static void
gb_terminal_view_wait_cb (GObject      *object,
                          GAsyncResult *result,
                          gpointer      user_data)
{
  IdeSubprocess *subprocess = (IdeSubprocess *)object;
  VteTerminal *terminal = user_data;
  GbTerminalView *self;
  g_autoptr(GError) error = NULL;

  IDE_ENTRY;

  g_assert (IDE_IS_SUBPROCESS (subprocess));
  g_assert (G_IS_ASYNC_RESULT (result));
  g_assert (VTE_IS_TERMINAL (terminal));

  if (!ide_subprocess_wait_finish (subprocess, result, &error))
    {
      g_warning ("%s", error->message);
      IDE_GOTO (failure);
    }

  self = (GbTerminalView *)gtk_widget_get_ancestor (GTK_WIDGET (terminal), GB_TYPE_TERMINAL_VIEW);
  if (self == NULL)
    IDE_GOTO (failure);

  if (!ide_widget_action (GTK_WIDGET (self), "view-stack", "close", NULL))
    {
      if (!gtk_widget_in_destruction (GTK_WIDGET (terminal)))
        gb_terminal_respawn (self, terminal);
    }

failure:
  g_clear_object (&terminal);

  IDE_EXIT;
}
static gchar *
ide_xml_indenter_indent (IdeXmlIndenter *xml,
                         GtkTextIter    *begin,
                         GtkTextIter    *end,
                         gint           *cursor_offset)
{
  GtkTextIter match_begin;
  GString *str;
  guint offset;

  g_return_val_if_fail (IDE_IS_XML_INDENTER (xml), NULL);
  g_return_val_if_fail (begin, NULL);
  g_return_val_if_fail (end, NULL);

  str = g_string_new (NULL);

  if (text_iter_backward_to_element_start (begin, &match_begin))
    {
      offset = gtk_text_iter_get_line_offset (&match_begin);
      build_indent (xml, offset + xml->indent_width, &match_begin, str);

      /*
       * If immediately after our cursor is a closing tag, we will move it to
       * a line after our indent line.
       */
      if ('<' == gtk_text_iter_get_char (end) &&
          '/' == text_iter_peek_next_char (end))
        {
          GString *str2;

          str2 = g_string_new (NULL);
          build_indent (xml, offset, &match_begin, str2);

          g_string_append (str, "\n");
          g_string_append (str, str2->str);

          *cursor_offset = -str2->len - 1;

          g_string_free (str2, TRUE);
        }

      IDE_GOTO (cleanup);
    }

  /* do nothing */

cleanup:
  return g_string_free (str, (str->len == 0));
}
static gboolean
text_iter_backward_to_element_start (const GtkTextIter *iter,
                                     GtkTextIter       *match_begin)
{
  GtkTextIter tmp = *iter;
  gboolean ret = FALSE;
  gint depth = 0;

  g_return_val_if_fail (iter, FALSE);
  g_return_val_if_fail (match_begin, FALSE);

  while (gtk_text_iter_backward_char (&tmp))
    {
      gunichar ch;

      ch = gtk_text_iter_get_char (&tmp);

      if ((ch == '/') && (text_iter_peek_prev_char (&tmp) == '<'))
        {
          gtk_text_iter_backward_char (&tmp);
          depth++;
        }
      else if ((ch == '/') && (text_iter_peek_next_char (&tmp) == '>'))
        {
          depth++;
        }
      else if ((ch == '<') && (text_iter_peek_next_char (&tmp) != '!'))
        {
          depth--;
          if (depth < 0)
            {
              *match_begin = tmp;
              ret = TRUE;
              IDE_GOTO (cleanup);
            }
        }
    }

cleanup:
  return ret;
}
static gboolean
text_iter_in_cdata (const GtkTextIter *location)
{
  GtkTextIter iter = *location;
  gboolean ret = FALSE;

  if (gtk_text_iter_backward_search (&iter, "<![CDATA[",
                                     GTK_TEXT_SEARCH_TEXT_ONLY,
                                     NULL, &iter, NULL))
    {
      if (!gtk_text_iter_forward_search (&iter, "]]>",
                                         GTK_TEXT_SEARCH_TEXT_ONLY,
                                         NULL, NULL, location))
        {
          ret = TRUE;
          IDE_GOTO (cleanup);
        }
    }

cleanup:
  return ret;
}
Exemple #9
0
static void
ide_langserv_completion_provider_complete_cb (GObject      *object,
                                              GAsyncResult *result,
                                              gpointer      user_data)
{
  IdeLangservClient *client = (IdeLangservClient *)object;
  g_autoptr(CompletionState) state = user_data;
  g_autoptr(GVariant) return_value = NULL;
  g_autoptr(GError) error = NULL;
  GVariant *node;
  GList *list = NULL;
  GVariantIter iter;

  IDE_ENTRY;

  g_assert (IDE_IS_LANGSERV_CLIENT (client));
  g_assert (G_IS_ASYNC_RESULT (result));
  g_assert (state != NULL);
  g_assert (IDE_IS_LANGSERV_COMPLETION_PROVIDER (state->self));
  g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (state->context));

  if (!ide_langserv_client_call_finish (client, result, &return_value, &error))
    {
      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        g_message ("%s", error->message);
      IDE_GOTO (failure);
    }

  /*
   * TODO: We will want to make a much more optimized version of this using
   *       the other completion result work we've done.
   */

  g_variant_iter_init (&iter, return_value);

  while (g_variant_iter_loop (&iter, "v", &node))
    {
      g_autoptr(GtkSourceCompletionItem) item = NULL;
      g_autofree gchar *full_label = NULL;
      const gchar *label;
      const gchar *detail;
      const gchar *icon_name = NULL;
      gboolean success;
      gint64 kind = 0;

      success = JSONRPC_MESSAGE_PARSE (node,
        "label", JSONRPC_MESSAGE_GET_STRING (&label),
        "detail", JSONRPC_MESSAGE_GET_STRING (&detail)
      );

      if (!success)
        {
          IDE_TRACE_MSG ("Failed to extract completion item from node");
          continue;
        }

      /* Optional kind field */
      JSONRPC_MESSAGE_PARSE (node, "kind", JSONRPC_MESSAGE_GET_INT64 (&kind));
      kind = ide_langserv_decode_completion_kind (kind);
      if (kind != IDE_SYMBOL_NONE)
        icon_name = ide_symbol_kind_get_icon_name (kind);

      if (label != NULL && detail != NULL)
        full_label = g_strdup_printf ("%s : %s", label, detail);
      else
        full_label = g_strdup (label);

      //item = gtk_source_completion_item_new (full_label, label, NULL, NULL);
      item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
                           "icon-name", icon_name,
                           "label", full_label,
                           "text", label,
                           NULL);

      list = g_list_prepend (list, g_steal_pointer (&item));
    }

failure:
  gtk_source_completion_context_add_proposals (state->context,
                                               GTK_SOURCE_COMPLETION_PROVIDER (state->self),
                                               list,
                                               TRUE);

  g_list_free_full (list, g_object_unref);

  IDE_EXIT;
}
static void
ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
                                        GtkSourceCompletionContext  *context)
{
  IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider;
  const gchar * const *allowed;
  g_autofree gchar *casefold = NULL;
  gint word_len;
  guint i;
  guint j;

  IDE_ENTRY;

  g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self));
  g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context));

  g_clear_pointer (&self->current_word, g_free);
  self->current_word = ide_completion_provider_context_current_word (context);

  allowed = get_allowed_suffixes (context);

  if (self->results != NULL)
    {
      if (ide_completion_results_replay (self->results, self->current_word))
        {
          ide_completion_results_present (self->results, provider, context);
          IDE_EXIT;
        }
      g_clear_pointer (&self->results, g_object_unref);
    }

  word_len = strlen (self->current_word);
  if (word_len < self->minimum_word_size)
    IDE_GOTO (word_too_small);

  casefold = g_utf8_casefold (self->current_word, -1);

  self->results = ide_completion_results_new (self->current_word);

  for (i = 0; i < self->indexes->len; i++)
    {
      g_autofree gchar *copy = g_strdup (self->current_word);
      IdeCtagsIndex *index = g_ptr_array_index (self->indexes, i);
      const IdeCtagsIndexEntry *entries = NULL;
      const gchar *last_name = NULL;
      guint tmp_len = word_len;
      gsize n_entries = 0;

      while (entries == NULL && *copy)
        {
          if (!(entries = ide_ctags_index_lookup_prefix (index, copy, &n_entries)))
            copy [--tmp_len] = '\0';
        }

      if ((entries == NULL) || (n_entries == 0))
        continue;

      for (j = 0; j < n_entries; j++)
        {
          const IdeCtagsIndexEntry *entry = &entries [j];
          IdeCtagsCompletionItem *item;

          if (ide_str_equal0 (entry->name, last_name))
            continue;

          last_name = entry->name;

          if (!ide_ctags_is_allowed (entry, allowed))
            continue;

          item = ide_ctags_completion_item_new (self, entry);

          if (!ide_completion_item_match (IDE_COMPLETION_ITEM (item), self->current_word, casefold))
            {
              g_object_unref (item);
              continue;
            }

          ide_completion_results_take_proposal (self->results, IDE_COMPLETION_ITEM (item));
        }
    }

  ide_completion_results_present (self->results, provider, context);

  IDE_EXIT;

word_too_small:
  gtk_source_completion_context_add_proposals (context, provider, NULL, TRUE);

  IDE_EXIT;
}
Exemple #11
0
static void
gb_terminal_respawn (GbTerminalView *self,
                     VteTerminal    *terminal)
{
  g_autoptr(GPtrArray) args = NULL;
  g_autoptr(IdeSubprocess) subprocess = NULL;
  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
  g_autofree gchar *workpath = NULL;
  g_autofree gchar *shell = NULL;
  GtkWidget *toplevel;
  GError *error = NULL;
  IdeContext *context;
  IdeVcs *vcs;
  VtePty *pty = NULL;
  GFile *workdir;
  gint64 now;
  int tty_fd = -1;
  gint stdout_fd = -1;
  gint stderr_fd = -1;

  IDE_ENTRY;

  g_assert (GB_IS_TERMINAL_VIEW (self));

  vte_terminal_reset (terminal, TRUE, TRUE);

  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
  if (!IDE_IS_WORKBENCH (toplevel))
    IDE_EXIT;

  /* Prevent flapping */
  now = g_get_monotonic_time ();
  if ((now - self->last_respawn) < (G_USEC_PER_SEC / 10))
    IDE_EXIT;
  self->last_respawn = now;

  context = ide_workbench_get_context (IDE_WORKBENCH (toplevel));
  vcs = ide_context_get_vcs (context);
  workdir = ide_vcs_get_working_directory (vcs);
  workpath = g_file_get_path (workdir);

  shell = gb_terminal_view_discover_shell (NULL, &error);

  if (shell == NULL)
    {
      g_warning ("Failed to discover user shell: %s", error->message);

      /* We prefer bash in flatpak over sh */
      if (ide_is_flatpak ())
        shell = g_strdup ("/bin/bash");
      else
        shell = vte_get_user_shell ();

      g_clear_error (&error);
    }

  args = g_ptr_array_new ();
  g_ptr_array_add (args, (gchar *)shell);
  g_ptr_array_add (args, NULL);

  pty = vte_terminal_pty_new_sync (terminal,
                                   VTE_PTY_DEFAULT | VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
                                   NULL,
                                   &error);
  if (pty == NULL)
    IDE_GOTO (failure);

  vte_terminal_set_pty (terminal, pty);

  if (-1 == (tty_fd = gb_vte_pty_create_slave (pty)))
    IDE_GOTO (failure);

  /* dup() is safe as it will inherit O_CLOEXEC */
  if (-1 == (stdout_fd = dup (tty_fd)) || -1 == (stderr_fd = dup (tty_fd)))
    IDE_GOTO (failure);

  /* XXX: It would be nice to allow using the runtimes launcher */
  launcher = ide_subprocess_launcher_new (0);
  ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
  ide_subprocess_launcher_set_cwd (launcher, workpath);
  ide_subprocess_launcher_push_args (launcher, (const gchar * const *)args->pdata);
  ide_subprocess_launcher_take_stdin_fd (launcher, tty_fd);
  ide_subprocess_launcher_take_stdout_fd (launcher, stdout_fd);
  ide_subprocess_launcher_take_stderr_fd (launcher, stderr_fd);
  ide_subprocess_launcher_setenv (launcher, "TERM", "xterm-256color", TRUE);
  ide_subprocess_launcher_setenv (launcher, "INSIDE_GNOME_BUILDER", PACKAGE_VERSION, TRUE);
  ide_subprocess_launcher_setenv (launcher, "SHELL", shell, TRUE);

  tty_fd = -1;
  stdout_fd = -1;
  stderr_fd = -1;

  if (NULL == (subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
    IDE_GOTO (failure);

  ide_subprocess_wait_async (subprocess,
                             NULL,
                             gb_terminal_view_wait_cb,
                             g_object_ref (terminal));

failure:
  if (tty_fd != -1)
    close (tty_fd);

  if (stdout_fd != -1)
    close (stdout_fd);

  g_clear_object (&pty);

  if (error != NULL)
    {
      g_warning ("%s", error->message);
      g_clear_error (&error);
    }

  IDE_EXIT;
}
static gboolean
ide_highlight_engine_tick (IdeHighlightEngine *self)
{
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    GtkTextIter invalid_begin;
    GtkTextIter invalid_end;
    GSList *tags_iter;

    IDE_PROBE;

    g_assert (IDE_IS_HIGHLIGHT_ENGINE (self));
    g_assert (self->buffer != NULL);
    g_assert (self->highlighter != NULL);
    g_assert (self->invalid_begin != NULL);
    g_assert (self->invalid_end != NULL);

    self->quanta_expiration = g_get_monotonic_time () + HIGHLIGHT_QUANTA_USEC;

    buffer = GTK_TEXT_BUFFER (self->buffer);

    gtk_text_buffer_get_iter_at_mark (buffer, &invalid_begin, self->invalid_begin);
    gtk_text_buffer_get_iter_at_mark (buffer, &invalid_end, self->invalid_end);

    IDE_TRACE_MSG ("Highlight Range [%u:%u,%u:%u] (%s)",
                   gtk_text_iter_get_line (&invalid_begin),
                   gtk_text_iter_get_line_offset (&invalid_begin),
                   gtk_text_iter_get_line (&invalid_end),
                   gtk_text_iter_get_line_offset (&invalid_end),
                   G_OBJECT_TYPE_NAME (self->highlighter));

    if (gtk_text_iter_compare (&invalid_begin, &invalid_end) >= 0)
        IDE_GOTO (up_to_date);

    /*Clear all our tags*/
    for (tags_iter = self->private_tags; tags_iter; tags_iter = tags_iter->next)
        gtk_text_buffer_remove_tag (buffer,
                                    GTK_TEXT_TAG (tags_iter->data),
                                    &invalid_begin,
                                    &invalid_end);

    iter = invalid_begin;

    ide_highlighter_update (self->highlighter, ide_highlight_engine_apply_style,
                            &invalid_begin, &invalid_end, &iter);

    if (gtk_text_iter_compare (&iter, &invalid_end) >= 0)
        IDE_GOTO (up_to_date);

    /* Stop processing until further instruction if no movement was made */
    if (gtk_text_iter_equal (&iter, &invalid_begin))
        return FALSE;

    gtk_text_buffer_move_mark (buffer, self->invalid_begin, &iter);

    return TRUE;

up_to_date:
    gtk_text_buffer_get_start_iter (buffer, &iter);
    gtk_text_buffer_move_mark (buffer, self->invalid_begin, &iter);
    gtk_text_buffer_move_mark (buffer, self->invalid_end, &iter);

    return FALSE;
}
static void
ide_ctags_completion_provider_populate (GtkSourceCompletionProvider *provider,
                                        GtkSourceCompletionContext  *context)
{
  IdeCtagsCompletionProvider *self = (IdeCtagsCompletionProvider *)provider;
  g_autofree gchar *word = NULL;
  const IdeCtagsIndexEntry *entries;
  const gchar * const *allowed;
  g_autoptr(GPtrArray) ar = NULL;
  IdeCtagsIndexEntry *last = NULL;
  GtkSourceBuffer *buffer;
  gsize n_entries;
  GtkTextIter iter;
  GList *list = NULL;
  gsize i;
  gsize j;

  IDE_ENTRY;

  g_assert (IDE_IS_CTAGS_COMPLETION_PROVIDER (self));
  g_assert (GTK_SOURCE_IS_COMPLETION_CONTEXT (context));

  if (self->indexes->len == 0)
    IDE_GOTO (failure);

  if (!g_settings_get_boolean (self->settings, "ctags-autocompletion"))
    IDE_GOTO (failure);

  if (!gtk_source_completion_context_get_iter (context, &iter))
    IDE_GOTO (failure);

  buffer = GTK_SOURCE_BUFFER (gtk_text_iter_get_buffer (&iter));
  allowed = get_allowed_suffixes (buffer);

  word = get_word_to_cursor (&iter);
  if (ide_str_empty0 (word) || strlen (word) < self->minimum_word_size)
    IDE_GOTO (failure);

  if (strlen (word) < 3)
    IDE_GOTO (failure);

  ar = g_ptr_array_new ();

  IDE_TRACE_MSG ("Searching for %s", word);

  for (j = 0; j < self->indexes->len; j++)
    {
      IdeCtagsIndex *index = g_ptr_array_index (self->indexes, j);

      entries = ide_ctags_index_lookup_prefix (index, word, &n_entries);
      if ((entries == NULL) || (n_entries == 0))
        continue;

      for (i = 0; i < n_entries; i++)
        {
          const IdeCtagsIndexEntry *entry = &entries [i];

          if (is_allowed (entry, allowed))
            g_ptr_array_add (ar, (gpointer)entry);
        }
    }

  g_ptr_array_sort (ar, sort_wrapper);

  for (i = ar->len; i > 0; i--)
    {
      GtkSourceCompletionProposal *item;
      IdeCtagsIndexEntry *entry = g_ptr_array_index (ar, i - 1);

      /*
       * NOTE:
       *
       * We walk backwards in this ptrarray so that we can use g_list_prepend() for O(1) access.
       * I think everyone agrees that using GList for passing completion data around was not
       * a great choice, but it is what we have to work with.
       */

      /*
       * Ignore this item if the previous one looks really similar.
       * We take the first item instead of the last since the first item (when walking backwards)
       * tends to be more likely to be the one we care about (based on lexicographical
       * ordering. For example, something in "gtk-2.0" is less useful than "gtk-3.0".
       *
       * This is done here instead of during our initial object creation so that
       * we can merge items between different indexes. It often happens that the
       * same headers are included in multiple tags files.
       */
      if ((last != NULL) && too_similar (entry, last))
        continue;

      /*
       * NOTE:
       *
       * Autocompletion is very performance sensitive code. The smallest amount of
       * extra work has a very negative impact on interactivity. We are trying to
       * avoid a couple things here based on how completion works.
       *
       * 1) Avoiding referencing or copying things.
       *    Since the provider will always outlive the completion item, we use
       *    borrowed references for as much as we can.
       * 2) We delay the work of looking up icons until they are requested.
       *    No sense in doing that work before hand.
       */
      item = ide_ctags_completion_item_new (entry, self, context);
      list = g_list_prepend (list, item);

      last = entry;
    }

failure:
  gtk_source_completion_context_add_proposals (context, provider, list, TRUE);
  g_list_free_full (list, g_object_unref);

  IDE_EXIT;
}
Exemple #14
0
static void
ide_frame_pan_end (IdeFrame         *self,
                   GdkEventSequence *sequence,
                   GtkGesturePan    *gesture)
{
  IdeFramePrivate *priv = ide_frame_get_instance_private (self);
  IdeFramePrivate *dest_priv;
  IdeFrame *dest;
  GtkAllocation alloc;
  GtkWidget *grid;
  GtkWidget *column;
  gdouble x, y;
  gint direction;
  gint index = 0;

  IDE_ENTRY;

  g_assert (IDE_IS_FRAME (self));
  g_assert (GTK_IS_GESTURE_PAN (gesture));

  if (priv->pan_theatric == NULL || priv->pan_page == NULL)
    IDE_GOTO (cleanup);

  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);

  gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (gesture), &x, &y);

  if (x > DISTANCE_THRESHOLD (&alloc))
    direction = 1;
  else if (x < -DISTANCE_THRESHOLD (&alloc))
    direction = -1;
  else
    direction = 0;

  grid = gtk_widget_get_ancestor (GTK_WIDGET (self), IDE_TYPE_GRID);
  g_assert (grid != NULL);
  g_assert (IDE_IS_GRID (grid));

  column = gtk_widget_get_ancestor (GTK_WIDGET (self), IDE_TYPE_GRID_COLUMN);
  g_assert (column != NULL);
  g_assert (IDE_IS_GRID_COLUMN (column));

  gtk_container_child_get (GTK_CONTAINER (grid), GTK_WIDGET (column),
                           "index", &index,
                           NULL);

  dest = _ide_grid_get_nth_stack (IDE_GRID (grid), index + direction);
  dest_priv = ide_frame_get_instance_private (dest);
  g_assert (dest != NULL);
  g_assert (IDE_IS_FRAME (dest));

  gtk_widget_get_allocation (GTK_WIDGET (dest), &alloc);

  if (!is_uninitialized (&alloc))
    {
      AnimationState *state;

      state = g_slice_new0 (AnimationState);
      state->source = g_object_ref (self);
      state->dest = g_object_ref (dest);
      state->page = g_object_ref (priv->pan_page);
      state->theatric = g_object_ref (priv->pan_theatric);

      gtk_widget_translate_coordinates (GTK_WIDGET (dest_priv->top_stack), grid, 0, 0,
                                        &alloc.x, &alloc.y);

      /*
       * Use EASE_OUT_CUBIC, because user initiated the beginning of the
       * acceleration curve just by swiping. No need to duplicate.
       */
      dzl_object_animate_full (state->theatric,
                               DZL_ANIMATION_EASE_OUT_CUBIC,
                               TRANSITION_DURATION,
                               gtk_widget_get_frame_clock (GTK_WIDGET (self)),
                               animation_state_complete,
                               state,
                               "x", alloc.x,
                               "width", alloc.width,
                               NULL);

      if (dest != self)
        {
          g_ptr_array_add (priv->in_transition, g_object_ref (priv->pan_page));
          gtk_container_remove (GTK_CONTAINER (priv->stack), GTK_WIDGET (priv->pan_page));
        }

      IDE_TRACE_MSG ("Animating transition to %s column",
                     dest != self ? "another" : "same");
    }
  else
    {
      g_autoptr(IdePage) page = g_object_ref (priv->pan_page);

      IDE_TRACE_MSG ("Moving page to a previously non-existant column");

      gtk_container_remove (GTK_CONTAINER (priv->stack), GTK_WIDGET (page));
      gtk_widget_show (GTK_WIDGET (page));
      gtk_container_add (GTK_CONTAINER (dest_priv->stack), GTK_WIDGET (page));
    }

cleanup:
  g_clear_object (&priv->pan_theatric);
  g_clear_object (&priv->pan_page);

  gtk_widget_queue_draw (gtk_widget_get_toplevel (GTK_WIDGET (self)));

  ide_frame_set_cursor (self, "arrow");

  IDE_EXIT;
}