static void
send_notification (IdeDebuggerEditorAddin *self,
                   const gchar            *title,
                   const gchar            *body,
                   const gchar            *icon_name,
                   gboolean                urgent)
{
  g_autoptr(IdeNotification) notif = NULL;
  g_autoptr(GIcon) icon = NULL;
  IdeContext *context;

  g_assert (IDE_IS_DEBUGGER_EDITOR_ADDIN (self));

  context = ide_workbench_get_context (self->workbench);

  if (icon_name)
    icon = g_themed_icon_new (icon_name);

  notif = g_object_new (IDE_TYPE_NOTIFICATION,
                        "has-progress", FALSE,
                        "icon", icon,
                        "title", title,
                        "body", body,
                        "urgent", TRUE,
                        NULL);
  ide_notification_attach (notif, IDE_OBJECT (context));
  ide_notification_withdraw_in_seconds (notif, 30);
}
Beispiel #2
0
static void
ide_workbench_get_property (GObject    *object,
                            guint       prop_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  IdeWorkbench *self = IDE_WORKBENCH (object);

  switch (prop_id)
    {
    case PROP_CONTEXT:
      g_value_set_object (value, ide_workbench_get_context (self));
      break;

    case PROP_DISABLE_GREETER:
      g_value_set_boolean (value, self->disable_greeter);
      break;

    case PROP_VISIBLE_PERSPECTIVE:
      g_value_set_object (value, ide_workbench_get_visible_perspective (self));
      break;

    case PROP_VISIBLE_PERSPECTIVE_NAME:
      g_value_set_string (value, ide_workbench_get_visible_perspective_name (self));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}
static void
gb_terminal_respawn (GbTerminalView *self,
                     VteTerminal    *terminal)
{
  g_autoptr(GPtrArray) args = NULL;
  g_autofree gchar *workpath = NULL;
  GtkWidget *toplevel;
  GError *error = NULL;
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;
  GPid child_pid;
  gint64 now;

  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))
    return;

  /* Prevent flapping */
  now = g_get_monotonic_time ();
  if ((now - self->last_respawn) < (G_USEC_PER_SEC / 10))
    return;
  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);

  args = g_ptr_array_new_with_free_func (g_free);
  g_ptr_array_add (args, vte_get_user_shell ());
  g_ptr_array_add (args, NULL);

  vte_terminal_spawn_sync (terminal,
                           VTE_PTY_DEFAULT | VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
                           workpath,
                           (gchar **)args->pdata,
                           NULL,
                           G_SPAWN_DEFAULT,
                           NULL,
                           NULL,
                           &child_pid,
                           NULL,
                           &error);

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

  vte_terminal_watch_child (terminal, child_pid);
}
Beispiel #4
0
static gboolean
load_split_async (GtkWidget            *active_widget,
                  const gchar          *options,
                  GAsyncReadyCallback   callback,
                  GError              **error)
{
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;
  GFile *file = NULL;
  gchar *file_path;
  SplitCallbackData *split_callback_data;

  g_assert (GTK_IS_WIDGET (active_widget));
  g_assert (options != NULL);
  g_assert (callback != NULL);

  if (!(workbench = ide_widget_get_workbench (active_widget)) ||
      !(context = ide_workbench_get_context (workbench)) ||
      !(vcs = ide_context_get_vcs (context)) ||
      !(workdir = ide_vcs_get_working_directory (vcs)))
    {
      g_set_error (error,
                   GB_VIM_ERROR,
                   GB_VIM_ERROR_NOT_SOURCE_VIEW,
                   _("Failed to locate working directory"));
      return FALSE;
    }

  if (!g_path_is_absolute (options))
    {
      g_autofree gchar *workdir_path = NULL;
      workdir_path = g_file_get_path (workdir);
      file_path = g_build_filename (workdir_path, options, NULL);
    }
  else
    file_path = g_strdup (options);

  file = g_file_new_for_path (file_path);

  split_callback_data = g_slice_new (SplitCallbackData);
  split_callback_data->active_widget = g_object_ref (active_widget);
  split_callback_data->file_path = file_path;

  ide_workbench_open_files_async (workbench,
                                  &file,
                                  1,
                                  "editor",
                                  IDE_WORKBENCH_OPEN_FLAGS_NO_VIEW,
                                  NULL,
                                  callback,
                                  split_callback_data);

  g_clear_object (&file);

  return TRUE;
}
Beispiel #5
0
static gboolean
gb_vim_command_vsplit (GtkWidget      *active_widget,
                       const gchar    *command,
                       const gchar    *options,
                       GError        **error)
{
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;
  GFile *file = NULL;
  gchar *file_path;
  SplitCallbackData *split_callback_data;
  GVariant *variant;

  g_assert (GTK_IS_WIDGET (active_widget));

  if (!IDE_IS_LAYOUT_VIEW (active_widget))
    return gb_vim_set_no_view_error (error);

  if (ide_str_empty0 (options))
    {
      variant = g_variant_new_string ("");
      ide_widget_action (GTK_WIDGET (active_widget), "view-stack", "split-left", variant);
    }
  else
    {
      if (!(workbench = ide_widget_get_workbench (active_widget)) ||
          !(context = ide_workbench_get_context (workbench)) ||
          !(vcs = ide_context_get_vcs (context)) ||
          !(workdir = ide_vcs_get_working_directory (vcs)))
        {
          g_set_error (error,
                       GB_VIM_ERROR,
                       GB_VIM_ERROR_NOT_SOURCE_VIEW,
                       _("Failed to locate working directory"));
          return FALSE;
        }

      file_path = g_strdup (options);

      if (!g_path_is_absolute (file_path))
        file_path = g_build_filename (g_file_get_path (workdir), file_path, NULL);

      file = g_file_new_for_path (file_path);

      split_callback_data = g_slice_new (SplitCallbackData);
      split_callback_data->active_widget = g_object_ref (active_widget);
      split_callback_data->file_path = file_path;

      ide_workbench_open_files_async (workbench, &file, 1, "editor", IDE_WORKBENCH_OPEN_FLAGS_BACKGROUND, NULL, gb_vim_command_vsplit_cb, split_callback_data);

      g_clear_object (&file);
    }

  return TRUE;
}
Beispiel #6
0
GArray *
gb_beautifier_config_get_entries (GbBeautifierWorkbenchAddin *self)
{
  IdeContext *context;
  IdeVcs *vcs;
  GArray *entries;
  GArray *map = NULL;
  g_autofree gchar *project_config_path = NULL;
  g_autofree gchar *user_config_path = NULL;

  g_assert (GB_IS_BEAUTIFIER_WORKBENCH_ADDIN (self));

  entries = g_array_new (TRUE, TRUE, sizeof (GbBeautifierConfigEntry));
  g_array_set_clear_func (entries, config_entry_clear_func);

  /* User wide config: ~/.config/gnome-builder/beautifier_plugin */
  user_config_path = g_build_filename (g_get_user_config_dir (),
                                       ide_get_program_name (),
                                       "beautifier_plugin",
                                       NULL);
  map = gb_beautifier_config_get_map (self, user_config_path);
  add_entries_from_base_path (self, user_config_path, entries, map);
  if (map != NULL)
    g_array_free (map, TRUE);

  /* Project wide config */
  if (NULL != (context = ide_workbench_get_context (self->workbench)) &&
      NULL != (vcs = ide_context_get_vcs (context)))
    {
      GFile *workdir;
      g_autofree gchar *workdir_path = NULL;

      workdir = ide_vcs_get_working_directory (vcs);
      workdir_path = g_file_get_path (workdir);
      project_config_path = g_build_filename (workdir_path,
                                              ".beautifier",
                                              NULL);
      map = gb_beautifier_config_get_map (self, project_config_path);
      add_entries_from_base_path (self, project_config_path, entries, map);
      if (map != NULL)
        g_array_free (map, TRUE);
    }

  /* System wide config */
  map = gb_beautifier_config_get_map (self, GB_BEAUTIFIER_PLUGIN_DATADIR);
  add_entries_from_base_path (self, GB_BEAUTIFIER_PLUGIN_DATADIR, entries, map);
  if (map != NULL)
    g_array_free (map, TRUE);

  return entries;
}
Beispiel #7
0
static GFile *
find_workdir (GtkWidget *active_widget)
{
  g_autoptr(GFile) workdir = NULL;
  IdeWorkbench *workbench;
  IdeContext *context;

  if (!(workbench = ide_widget_get_workbench (active_widget)) ||
      !(context = ide_workbench_get_context (workbench)) ||
      !(workdir = ide_context_ref_workdir (context)))
    return NULL;

  return g_steal_pointer (&workdir);
}
static void
ide_workbench_actions_save_all (GSimpleAction *action,
                                GVariant      *variant,
                                gpointer       user_data)
{
  IdeWorkbench *workbench = user_data;
  IdeContext *context;
  IdeBufferManager *bufmgr;

  g_assert (IDE_IS_WORKBENCH (workbench));

  context = ide_workbench_get_context (workbench);
  if (context == NULL)
    return;

  bufmgr = ide_context_get_buffer_manager (context);
  ide_buffer_manager_save_all_async (bufmgr, NULL, NULL, NULL);
}
static gboolean
workbench_manages_file (IdeWorkbench *workbench,
                        GFile        *file)
{
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;

  g_assert (IDE_IS_WORKBENCH (workbench));
  g_assert (G_IS_FILE (file));

  if (NULL == (context = ide_workbench_get_context (workbench)))
    return FALSE;

  vcs = ide_context_get_vcs (context);
  workdir = ide_vcs_get_working_directory (vcs);

  return g_file_has_prefix (file, workdir);
}
Beispiel #10
0
static gboolean
gb_vim_command_edit (GtkWidget      *active_widget,
                     const gchar    *command,
                     const gchar    *options,
                     GError        **error)
{
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;
  GFile *file = NULL;

  g_assert (GTK_IS_WIDGET (active_widget));

  if (ide_str_empty0 (options))
    {
      ide_widget_action (GTK_WIDGET (active_widget), "win", "open-with-dialog", NULL);
      return TRUE;
    }

  if (!(workbench = ide_widget_get_workbench (active_widget)) ||
      !(context = ide_workbench_get_context (workbench)) ||
      !(vcs = ide_context_get_vcs (context)) ||
      !(workdir = ide_vcs_get_working_directory (vcs)))
    {
      g_set_error (error,
                   GB_VIM_ERROR,
                   GB_VIM_ERROR_NOT_SOURCE_VIEW,
                   _("Failed to locate working directory"));
      return FALSE;
    }

  if (g_path_is_absolute (options))
    file = g_file_new_for_path (options);
  else
    file = g_file_get_child (workdir, options);

  ide_workbench_open_files_async (workbench, &file, 1, "editor", IDE_WORKBENCH_OPEN_FLAGS_NONE, NULL, NULL, NULL);

  g_clear_object (&file);

  return TRUE;
}
Beispiel #11
0
static void
ide_application_actions_load_workbench_view (IdeApplication *self,
                                             const char     *genesis_view,
                                             const char     *manifest)
{
  IdeWorkbench *workbench = NULL;
  IdePerspective *greeter;
  const GList *list;

  list = gtk_application_get_windows (GTK_APPLICATION (self));

  for (; list != NULL; list = list->next)
    {
      GtkWindow *window = list->data;

      if (IDE_IS_WORKBENCH (window))
        {
          if (ide_workbench_get_context (IDE_WORKBENCH (window)) == NULL)
            {
              workbench = IDE_WORKBENCH (window);
              break;
            }
        }
    }

  if (workbench == NULL)
    {
      workbench = g_object_new (IDE_TYPE_WORKBENCH,
                                "application", self,
                                NULL);
    }

  greeter = ide_workbench_get_perspective_by_name (workbench, "greeter");

  if (greeter)
    {
      ide_greeter_perspective_show_genesis_view (IDE_GREETER_PERSPECTIVE (greeter),
                                                 genesis_view, manifest);
    }

  gtk_window_present (GTK_WINDOW (workbench));
}
static void
ide_debugger_editor_addin_unload (IdeEditorAddin   *addin,
                                  IdeEditorSurface *editor)
{
  IdeDebuggerEditorAddin *self = (IdeDebuggerEditorAddin *)addin;
  IdeRunManager *run_manager;
  IdeWorkspace *workspace;
  IdeContext *context;

  IDE_ENTRY;

  g_assert (IDE_IS_DEBUGGER_EDITOR_ADDIN (self));
  g_assert (IDE_IS_EDITOR_SURFACE (editor));

  if (!ide_workbench_has_project (self->workbench))
    return;

  context = ide_workbench_get_context (self->workbench);
  run_manager = ide_run_manager_from_context (context);

  if ((workspace = ide_widget_get_workspace (GTK_WIDGET (editor))))
    gtk_widget_insert_action_group (GTK_WIDGET (workspace), "debugger", NULL);

  /* Remove the handler to initiate the debugger */
  ide_run_manager_remove_handler (run_manager, "debugger");

  g_clear_object (&self->debugger_signals);
  g_clear_object (&self->debug_manager_signals);

  if (self->panel != NULL)
    gtk_widget_destroy (GTK_WIDGET (self->panel));
  if (self->controls != NULL)
    gtk_widget_destroy (GTK_WIDGET (self->controls));
  if (self->disassembly_view != NULL)
    gtk_widget_destroy (GTK_WIDGET (self->disassembly_view));

  self->editor = NULL;
  self->workbench = NULL;

  IDE_EXIT;
}
Beispiel #13
0
static void
ide_editor_perspective_actions_new_file (GSimpleAction *action,
                                         GVariant      *variant,
                                         gpointer       user_data)
{
  IdeEditorPerspective *self = user_data;
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeBufferManager *bufmgr;
  IdeBuffer *buffer;

  g_assert (G_IS_SIMPLE_ACTION (action));
  g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));

  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
  context = ide_workbench_get_context (workbench);
  bufmgr = ide_context_get_buffer_manager (context);
  buffer = ide_buffer_manager_create_temporary_buffer (bufmgr);

  g_clear_object (&buffer);
}
Beispiel #14
0
static gboolean
gb_vim_command_bprevious (GtkWidget      *active_widget,
                          const gchar    *command,
                          const gchar    *options,
                          GError        **error)
{
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeBufferManager *bufmgr;
  guint n_buffers;

  g_assert (GTK_IS_WIDGET (active_widget));

  workbench = ide_widget_get_workbench (GTK_WIDGET (active_widget));
  context = ide_workbench_get_context (workbench);
  bufmgr = ide_context_get_buffer_manager (context);
  n_buffers = ide_buffer_manager_get_n_buffers (bufmgr);

  if (n_buffers > 0)
    ide_widget_action (GTK_WIDGET (active_widget), "view-stack", "previous-view", NULL);

  return TRUE;
}
Beispiel #15
0
static void
gb_vim_complete_edit_files (GtkWidget *active_widget,
                            const gchar   *command,
                            GPtrArray     *ar,
                            const gchar   *prefix)
{
  IdeWorkbench *workbench;
  IdeContext *context;
  IdeVcs *vcs;
  GFile *workdir;
  g_autoptr(GFile) child = NULL;
  g_autoptr(GFile) parent = NULL;

  IDE_ENTRY;

  g_assert (command);
  g_assert (ar);
  g_assert (prefix);

  if (!(workbench = ide_widget_get_workbench (GTK_WIDGET (active_widget))) ||
      !(context = ide_workbench_get_context (workbench)) ||
      !(vcs = ide_context_get_vcs (context)) ||
      !(workdir = ide_vcs_get_working_directory (vcs)))
    IDE_EXIT;

  child = g_file_get_child (workdir, prefix);

  if (g_file_query_exists (child, NULL))
    {
      if (g_file_query_file_type (child, 0, NULL) == G_FILE_TYPE_DIRECTORY)
        {
          g_autoptr(GFileEnumerator) fe = NULL;
          GFileInfo *descendent;

          if (!g_str_has_suffix (prefix, "/"))
            {
              g_ptr_array_add (ar, g_strdup_printf ("%s %s/", command, prefix));
              IDE_EXIT;
            }

          fe = g_file_enumerate_children (child,
                                          G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
                                          G_FILE_QUERY_INFO_NONE,
                                          NULL, NULL);

          if (fe == NULL)
            IDE_EXIT;

          while ((descendent = g_file_enumerator_next_file (fe, NULL, NULL)))
            {
              const gchar *name;

              name = g_file_info_get_display_name (descendent);
              g_ptr_array_add (ar, g_strdup_printf ("%s %s%s", command, prefix, name));
              g_object_unref (descendent);
            }

          IDE_EXIT;
        }
    }

  parent = g_file_get_parent (child);

  if (parent != NULL)
    {
      g_autoptr(GFileEnumerator) fe = NULL;
      GFileInfo *descendent;
      const gchar *slash;
      const gchar *partial_name;
      g_autofree gchar *prefix_dir = NULL;

#ifdef IDE_ENABLE_TRACE
      {
        g_autofree gchar *parent_path = g_file_get_path (parent);
        IDE_TRACE_MSG ("parent_path: %s", parent_path);
      }
#endif

      if ((slash = strrchr (prefix, G_DIR_SEPARATOR)))
        {
          partial_name = slash + 1;
          prefix_dir = g_strndup (prefix, slash - prefix + 1);
        }
      else
        {
          partial_name = prefix;
        }

      fe = g_file_enumerate_children (parent,
                                      G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
                                      G_FILE_QUERY_INFO_NONE,
                                      NULL, NULL);

      if (fe == NULL)
        IDE_EXIT;

      while ((descendent = g_file_enumerator_next_file (fe, NULL, NULL)))
        {
          const gchar *name;
          name = g_file_info_get_display_name (descendent);

          IDE_TRACE_MSG ("name=%s prefix=%s", name, prefix);

          if (name && g_str_has_prefix (name, partial_name))
            {
              gchar *completed_command;
              const gchar *descendent_name;
              g_autofree gchar *full_path = NULL;
              g_autofree gchar *parent_path = NULL;

              parent_path = g_file_get_path (parent);
              descendent_name = g_file_info_get_name (descendent);
              full_path = g_build_filename (parent_path, descendent_name, NULL);

              if (prefix[0] == G_DIR_SEPARATOR)
                completed_command = g_strdup_printf ("%s %s", command, full_path);
              else if (strchr (prefix, G_DIR_SEPARATOR) == NULL)
                completed_command = g_strdup_printf ("%s %s", command, descendent_name);
              else
                completed_command = g_strdup_printf ("%s %s%s", command, prefix_dir, descendent_name);

              IDE_TRACE_MSG ("edit completion: %s", completed_command);

              g_ptr_array_add (ar, completed_command);
            }
          g_object_unref (descendent);
        }

      IDE_EXIT;
    }

  IDE_EXIT;
}
Beispiel #16
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;
}
Beispiel #17
0
static void
ide_editor_perspective_focus_location_full (IdeEditorPerspective *self,
                                            IdeSourceLocation    *location,
                                            gboolean              open_if_not_found)
{
  struct {
    IdeFile *file;
    IdeEditorView *view;
  } lookup = { 0 };
  GtkWidget *stack;
  guint line;
  guint line_offset;

  IDE_ENTRY;

  g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));
  g_assert (location != NULL);

  lookup.file = ide_source_location_get_file (location);
  lookup.view = NULL;

  if (lookup.file == NULL)
    {
      g_warning ("IdeSourceLocation does not contain a file");
      IDE_EXIT;
    }

#ifdef IDE_ENABLE_TRACE
  {
    const gchar *path = ide_file_get_path (lookup.file);
    IDE_TRACE_MSG ("Locating %s, open_if_not_found=%d",
                   path, open_if_not_found);
  }
#endif

  ide_perspective_views_foreach (IDE_PERSPECTIVE (self),
                                 ide_editor_perspective_find_source_location,
                                 &lookup);

  if (!open_if_not_found && lookup.view == NULL)
    IDE_EXIT;

  if (lookup.view == NULL)
    {
      FocusLocation *state;
      IdeBufferManager *bufmgr;
      IdeWorkbench *workbench;
      IdeContext *context;

      workbench = ide_widget_get_workbench (GTK_WIDGET (self));
      context = ide_workbench_get_context (workbench);
      bufmgr = ide_context_get_buffer_manager (context);

      state = g_slice_new0 (FocusLocation);
      state->self = g_object_ref (self);
      state->location = ide_source_location_ref (location);

      ide_buffer_manager_load_file_async (bufmgr,
                                          lookup.file,
                                          FALSE,
                                          IDE_WORKBENCH_OPEN_FLAGS_NONE,
                                          NULL,
                                          NULL,
                                          ide_editor_perspective_focus_location_cb,
                                          state);
      IDE_EXIT;
    }

  line = ide_source_location_get_line (location);
  line_offset = ide_source_location_get_line_offset (location);

  stack = gtk_widget_get_ancestor (GTK_WIDGET (lookup.view), IDE_TYPE_LAYOUT_STACK);
  ide_layout_stack_set_visible_child (IDE_LAYOUT_STACK (stack), IDE_LAYOUT_VIEW (lookup.view));
  ide_editor_view_scroll_to_line_offset (lookup.view, line, line_offset);

  IDE_EXIT;
}