896 lines
24 KiB
C
896 lines
24 KiB
C
/* ide-page.c
|
|
*
|
|
* Copyright 2017-2019 Christian Hergert <chergert@redhat.com>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#define G_LOG_DOMAIN "ide-page"
|
|
|
|
#include "config.h"
|
|
|
|
#include <libide-threading.h>
|
|
#include <string.h>
|
|
|
|
#include "ide-gui-global.h"
|
|
#include "ide-gui-private.h"
|
|
#include "ide-page.h"
|
|
#include "ide-workspace.h"
|
|
|
|
typedef struct
|
|
{
|
|
GList mru_link;
|
|
|
|
const gchar *menu_id;
|
|
const gchar *icon_name;
|
|
gchar *title;
|
|
GIcon *icon;
|
|
|
|
GdkRGBA primary_color_bg;
|
|
GdkRGBA primary_color_fg;
|
|
|
|
guint failed : 1;
|
|
guint modified : 1;
|
|
guint can_split : 1;
|
|
guint primary_color_bg_set : 1;
|
|
guint primary_color_fg_set : 1;
|
|
} IdePagePrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_CAN_SPLIT,
|
|
PROP_FAILED,
|
|
PROP_ICON,
|
|
PROP_ICON_NAME,
|
|
PROP_MENU_ID,
|
|
PROP_MODIFIED,
|
|
PROP_PRIMARY_COLOR_BG,
|
|
PROP_PRIMARY_COLOR_FG,
|
|
PROP_TITLE,
|
|
N_PROPS
|
|
};
|
|
|
|
enum {
|
|
CREATE_SPLIT,
|
|
N_SIGNALS
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (IdePage, ide_page, GTK_TYPE_BOX)
|
|
|
|
static GParamSpec *properties [N_PROPS];
|
|
static guint signals [N_SIGNALS];
|
|
|
|
static void
|
|
ide_page_real_agree_to_close_async (IdePage *self,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(IdeTask) task = NULL;
|
|
|
|
g_assert (IDE_IS_PAGE (self));
|
|
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
|
|
|
task = ide_task_new (self, cancellable, callback, user_data);
|
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
|
ide_task_set_source_tag (task, ide_page_agree_to_close_async);
|
|
ide_task_return_boolean (task, TRUE);
|
|
}
|
|
|
|
static gboolean
|
|
ide_page_real_agree_to_close_finish (IdePage *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
g_assert (IDE_IS_PAGE (self));
|
|
g_assert (IDE_IS_TASK (result));
|
|
|
|
return ide_task_propagate_boolean (IDE_TASK (result), error);
|
|
}
|
|
|
|
static void
|
|
find_focus_child (GtkWidget *widget,
|
|
gboolean *handled)
|
|
{
|
|
if (!*handled)
|
|
*handled = gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
|
|
}
|
|
|
|
static void
|
|
ide_page_grab_focus (GtkWidget *widget)
|
|
{
|
|
gboolean handled = FALSE;
|
|
|
|
g_assert (IDE_IS_PAGE (widget));
|
|
|
|
/*
|
|
* This default grab_focus override just looks for the first child (generally
|
|
* something like a scrolled window) and tries to move forward on focusing
|
|
* the child widget. In most cases, this should work without intervention
|
|
* from the child subclass.
|
|
*/
|
|
|
|
gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) find_focus_child, &handled);
|
|
}
|
|
|
|
static void
|
|
ide_page_hierarchy_changed (GtkWidget *widget,
|
|
GtkWidget *previous_toplevel)
|
|
{
|
|
IdePage *self = (IdePage *)widget;
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
GtkWidget *toplevel;
|
|
|
|
g_assert (IDE_IS_PAGE (self));
|
|
g_assert (!previous_toplevel || GTK_IS_WIDGET (previous_toplevel));
|
|
|
|
if (IDE_IS_WORKSPACE (previous_toplevel))
|
|
_ide_workspace_remove_page_mru (IDE_WORKSPACE (previous_toplevel), &priv->mru_link);
|
|
|
|
if (GTK_WIDGET_CLASS (ide_page_parent_class)->hierarchy_changed)
|
|
GTK_WIDGET_CLASS (ide_page_parent_class)->hierarchy_changed (widget, previous_toplevel);
|
|
|
|
toplevel = gtk_widget_get_toplevel (widget);
|
|
|
|
if (IDE_IS_WORKSPACE (toplevel))
|
|
_ide_workspace_add_page_mru (IDE_WORKSPACE (toplevel), &priv->mru_link);
|
|
}
|
|
|
|
/**
|
|
* ide_page_mark_used:
|
|
* @self: a #IdePage
|
|
*
|
|
* This function marks the page as used by updating it's position in the
|
|
* workspaces MRU (most-recently-used) queue.
|
|
*
|
|
* Pages should call this when their contents have been focused.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_page_mark_used (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
IdeWorkspace *workspace;
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
if ((workspace = ide_widget_get_workspace (GTK_WIDGET (self))))
|
|
_ide_workspace_move_front_page_mru (workspace, &priv->mru_link);
|
|
}
|
|
|
|
static void
|
|
ide_page_finalize (GObject *object)
|
|
{
|
|
IdePage *self = (IdePage *)object;
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_clear_pointer (&priv->title, g_free);
|
|
g_clear_object (&priv->icon);
|
|
|
|
G_OBJECT_CLASS (ide_page_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
ide_page_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
IdePage *self = IDE_PAGE (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_CAN_SPLIT:
|
|
g_value_set_boolean (value, ide_page_get_can_split (self));
|
|
break;
|
|
|
|
case PROP_FAILED:
|
|
g_value_set_boolean (value, ide_page_get_failed (self));
|
|
break;
|
|
|
|
case PROP_ICON_NAME:
|
|
g_value_set_static_string (value, ide_page_get_icon_name (self));
|
|
break;
|
|
|
|
case PROP_ICON:
|
|
g_value_set_object (value, ide_page_get_icon (self));
|
|
break;
|
|
|
|
case PROP_MENU_ID:
|
|
g_value_set_static_string (value, ide_page_get_menu_id (self));
|
|
break;
|
|
|
|
case PROP_MODIFIED:
|
|
g_value_set_boolean (value, ide_page_get_modified (self));
|
|
break;
|
|
|
|
case PROP_PRIMARY_COLOR_BG:
|
|
g_value_set_boxed (value, ide_page_get_primary_color_bg (self));
|
|
break;
|
|
|
|
case PROP_PRIMARY_COLOR_FG:
|
|
g_value_set_boxed (value, ide_page_get_primary_color_fg (self));
|
|
break;
|
|
|
|
case PROP_TITLE:
|
|
g_value_set_string (value, ide_page_get_title (self));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ide_page_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
IdePage *self = IDE_PAGE (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_CAN_SPLIT:
|
|
ide_page_set_can_split (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_FAILED:
|
|
ide_page_set_failed (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_ICON_NAME:
|
|
ide_page_set_icon_name (self, g_value_get_string (value));
|
|
break;
|
|
|
|
case PROP_ICON:
|
|
ide_page_set_icon (self, g_value_get_object (value));
|
|
break;
|
|
|
|
case PROP_MENU_ID:
|
|
ide_page_set_menu_id (self, g_value_get_string (value));
|
|
break;
|
|
|
|
case PROP_MODIFIED:
|
|
ide_page_set_modified (self, g_value_get_boolean (value));
|
|
break;
|
|
|
|
case PROP_PRIMARY_COLOR_BG:
|
|
ide_page_set_primary_color_bg (self, g_value_get_boxed (value));
|
|
break;
|
|
|
|
case PROP_PRIMARY_COLOR_FG:
|
|
ide_page_set_primary_color_fg (self, g_value_get_boxed (value));
|
|
break;
|
|
|
|
case PROP_TITLE:
|
|
ide_page_set_title (self, g_value_get_string (value));
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ide_page_class_init (IdePageClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->finalize = ide_page_finalize;
|
|
object_class->get_property = ide_page_get_property;
|
|
object_class->set_property = ide_page_set_property;
|
|
|
|
widget_class->grab_focus = ide_page_grab_focus;
|
|
widget_class->hierarchy_changed = ide_page_hierarchy_changed;
|
|
|
|
klass->agree_to_close_async = ide_page_real_agree_to_close_async;
|
|
klass->agree_to_close_finish = ide_page_real_agree_to_close_finish;
|
|
|
|
properties [PROP_CAN_SPLIT] =
|
|
g_param_spec_boolean ("can-split",
|
|
"Can Split",
|
|
"If the view can be split into a second view",
|
|
FALSE,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_FAILED] =
|
|
g_param_spec_boolean ("failed",
|
|
"Failed",
|
|
"If the view has failed or crashed",
|
|
FALSE,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_ICON] =
|
|
g_param_spec_object ("icon",
|
|
"Icon",
|
|
"A GIcon for the view",
|
|
G_TYPE_ICON,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_ICON_NAME] =
|
|
g_param_spec_string ("icon-name",
|
|
"Icon Name",
|
|
"The icon-name describing the view content",
|
|
"text-x-generic-symbolic",
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_MENU_ID] =
|
|
g_param_spec_string ("menu-id",
|
|
"Menu ID",
|
|
"The identifier of the GMenu to use in the document popover",
|
|
NULL,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_MODIFIED] =
|
|
g_param_spec_boolean ("modified",
|
|
"Modified",
|
|
"If the view has been modified from the saved content",
|
|
FALSE,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
/**
|
|
* IdePage:primary-color-bg:
|
|
*
|
|
* The "primary-color-bg" property should describe the primary color
|
|
* of the content of the view (if any).
|
|
*
|
|
* This can be used by the layout stack to alter the color of the
|
|
* header to match that of the content.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
properties [PROP_PRIMARY_COLOR_BG] =
|
|
g_param_spec_boxed ("primary-color-bg",
|
|
"Primary Color Background",
|
|
"The primary foreground color of the content",
|
|
GDK_TYPE_RGBA,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
/**
|
|
* IdePage:primary-color-fg:
|
|
*
|
|
* The "primary-color-fg" property should describe the foreground
|
|
* to use for content above primary-color-bg.
|
|
*
|
|
* This can be used by the layout stack to alter the color of the
|
|
* foreground to match that of the content.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
properties [PROP_PRIMARY_COLOR_FG] =
|
|
g_param_spec_boxed ("primary-color-fg",
|
|
"Primary Color Foreground",
|
|
"The primary foreground color of the content",
|
|
GDK_TYPE_RGBA,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
properties [PROP_TITLE] =
|
|
g_param_spec_string ("title",
|
|
"Title",
|
|
"The title of the document or view",
|
|
NULL,
|
|
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
|
|
|
/**
|
|
* IdePage::create-split:
|
|
* @self: an #IdePage
|
|
*
|
|
* This signal is emitted when the view is requested to make a split
|
|
* version of itself. This happens when the user requests that a second
|
|
* version of the file to be displayed, often side-by-side.
|
|
*
|
|
* This signal will only be emitted when #IdePage:can-split is
|
|
* set to %TRUE. The default is %FALSE.
|
|
*
|
|
* Returns: (transfer full): A newly created #IdePage
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
signals [CREATE_SPLIT] =
|
|
g_signal_new (g_intern_static_string ("create-split"),
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (IdePageClass, create_split),
|
|
g_signal_accumulator_first_wins, NULL,
|
|
NULL, IDE_TYPE_PAGE, 0);
|
|
}
|
|
|
|
static void
|
|
ide_page_init (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
g_autoptr(GSimpleActionGroup) group = g_simple_action_group_new ();
|
|
|
|
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
|
|
|
|
priv->mru_link.data = self;
|
|
priv->icon_name = g_intern_string ("text-x-generic-symbolic");
|
|
|
|
/* Add an action group out of convenience to plugins that want to
|
|
* stash a simple action somewhere.
|
|
*/
|
|
gtk_widget_insert_action_group (GTK_WIDGET (self), "view", G_ACTION_GROUP (group));
|
|
}
|
|
|
|
GtkWidget *
|
|
ide_page_new (void)
|
|
{
|
|
return g_object_new (IDE_TYPE_PAGE, NULL);
|
|
}
|
|
|
|
const gchar *
|
|
ide_page_get_title (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
return priv->title;
|
|
}
|
|
|
|
void
|
|
ide_page_set_title (IdePage *self,
|
|
const gchar *title)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
if (g_strcmp0 (title, priv->title) != 0)
|
|
{
|
|
g_free (priv->title);
|
|
priv->title = g_strdup (title);
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
|
|
}
|
|
}
|
|
|
|
const gchar *
|
|
ide_page_get_menu_id (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
return priv->menu_id;
|
|
}
|
|
|
|
void
|
|
ide_page_set_menu_id (IdePage *self,
|
|
const gchar *menu_id)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
menu_id = g_intern_string (menu_id);
|
|
|
|
if (menu_id != priv->menu_id)
|
|
{
|
|
priv->menu_id = menu_id;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MENU_ID]);
|
|
}
|
|
}
|
|
|
|
void
|
|
ide_page_agree_to_close_async (IdePage *self,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
|
|
|
IDE_PAGE_GET_CLASS (self)->agree_to_close_async (self, cancellable, callback, user_data);
|
|
}
|
|
|
|
gboolean
|
|
ide_page_agree_to_close_finish (IdePage *self,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), FALSE);
|
|
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
|
|
|
return IDE_PAGE_GET_CLASS (self)->agree_to_close_finish (self, result, error);
|
|
}
|
|
|
|
gboolean
|
|
ide_page_get_failed (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), FALSE);
|
|
|
|
return priv->failed;
|
|
}
|
|
|
|
void
|
|
ide_page_set_failed (IdePage *self,
|
|
gboolean failed)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
failed = !!failed;
|
|
|
|
if (failed != priv->failed)
|
|
{
|
|
priv->failed = failed;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_FAILED]);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
ide_page_get_modified (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), FALSE);
|
|
|
|
return priv->modified;
|
|
}
|
|
|
|
void
|
|
ide_page_set_modified (IdePage *self,
|
|
gboolean modified)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
modified = !!modified;
|
|
|
|
if (priv->modified != modified)
|
|
{
|
|
priv->modified = modified;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODIFIED]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ide_page_get_icon:
|
|
* @self: a #IdePage
|
|
*
|
|
* Gets the #GIcon to represent the view.
|
|
*
|
|
* Returns: (transfer none) (nullable): A #GIcon or %NULL
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
GIcon *
|
|
ide_page_get_icon (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
if (priv->icon == NULL)
|
|
{
|
|
if (priv->icon_name != NULL)
|
|
priv->icon = g_icon_new_for_string (priv->icon_name, NULL);
|
|
}
|
|
|
|
return priv->icon;
|
|
}
|
|
|
|
void
|
|
ide_page_set_icon (IdePage *self,
|
|
GIcon *icon)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
if (g_set_object (&priv->icon, icon))
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
|
|
}
|
|
|
|
const gchar *
|
|
ide_page_get_icon_name (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
return priv->icon_name;
|
|
}
|
|
|
|
void
|
|
ide_page_set_icon_name (IdePage *self,
|
|
const gchar *icon_name)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
icon_name = g_intern_string (icon_name);
|
|
|
|
if (icon_name != priv->icon_name)
|
|
{
|
|
priv->icon_name = icon_name;
|
|
g_clear_object (&priv->icon);
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON_NAME]);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
ide_page_get_can_split (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), FALSE);
|
|
|
|
return priv->can_split;
|
|
}
|
|
|
|
void
|
|
ide_page_set_can_split (IdePage *self,
|
|
gboolean can_split)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
can_split = !!can_split;
|
|
|
|
if (priv->can_split != can_split)
|
|
{
|
|
priv->can_split = can_split;
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_SPLIT]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ide_page_create_split:
|
|
* @self: an #IdePage
|
|
*
|
|
* This function requests that the #IdePage create a split version
|
|
* of itself so that the user may view the document in multiple views.
|
|
*
|
|
* The view should be added to an #IdeLayoutStack where appropriate.
|
|
*
|
|
* Returns: (nullable) (transfer full): A newly created #IdePage or %NULL.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
IdePage *
|
|
ide_page_create_split (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
IdePage *ret = NULL;
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
if (priv->can_split)
|
|
{
|
|
g_signal_emit (self, signals [CREATE_SPLIT], 0, &ret);
|
|
g_return_val_if_fail (!ret || IDE_IS_PAGE (ret), NULL);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* ide_page_get_primary_color_bg:
|
|
* @self: a #IdePage
|
|
*
|
|
* Gets the #IdePage:primary-color-bg property if it has been set.
|
|
*
|
|
* The primary-color-bg can be used to alter the color of the layout
|
|
* stack header to match the document contents.
|
|
*
|
|
* Returns: (transfer none) (nullable): a #GdkRGBA or %NULL.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
const GdkRGBA *
|
|
ide_page_get_primary_color_bg (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
return priv->primary_color_bg_set ? &priv->primary_color_bg : NULL;
|
|
}
|
|
|
|
/**
|
|
* ide_page_set_primary_color_bg:
|
|
* @self: a #IdePage
|
|
* @primary_color_bg: (nullable): a #GdkRGBA or %NULL
|
|
*
|
|
* Sets the #IdePage:primary-color-bg property.
|
|
* If @primary_color_bg is %NULL, the property is unset.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_page_set_primary_color_bg (IdePage *self,
|
|
const GdkRGBA *primary_color_bg)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
gboolean old_set;
|
|
GdkRGBA old;
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
old_set = priv->primary_color_bg_set;
|
|
old = priv->primary_color_bg;
|
|
|
|
if (primary_color_bg != NULL)
|
|
{
|
|
priv->primary_color_bg = *primary_color_bg;
|
|
priv->primary_color_bg_set = TRUE;
|
|
}
|
|
else
|
|
{
|
|
memset (&priv->primary_color_bg, 0, sizeof priv->primary_color_bg);
|
|
priv->primary_color_bg_set = FALSE;
|
|
}
|
|
|
|
if (old_set != priv->primary_color_bg_set ||
|
|
!gdk_rgba_equal (&old, &priv->primary_color_bg))
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIMARY_COLOR_BG]);
|
|
}
|
|
|
|
/**
|
|
* ide_page_get_primary_color_fg:
|
|
* @self: a #IdePage
|
|
*
|
|
* Gets the #IdePage:primary-color-fg property if it has been set.
|
|
*
|
|
* The primary-color-fg can be used to alter the foreground color of the layout
|
|
* stack header to match the document contents.
|
|
*
|
|
* Returns: (transfer none) (nullable): a #GdkRGBA or %NULL.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
const GdkRGBA *
|
|
ide_page_get_primary_color_fg (IdePage *self)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
return priv->primary_color_fg_set ? &priv->primary_color_fg : NULL;
|
|
}
|
|
|
|
/**
|
|
* ide_page_set_primary_color_fg:
|
|
* @self: a #IdePage
|
|
* @primary_color_fg: (nullable): a #GdkRGBA or %NULL
|
|
*
|
|
* Sets the #IdePage:primary-color-fg property.
|
|
* If @primary_color_fg is %NULL, the property is unset.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_page_set_primary_color_fg (IdePage *self,
|
|
const GdkRGBA *primary_color_fg)
|
|
{
|
|
IdePagePrivate *priv = ide_page_get_instance_private (self);
|
|
gboolean old_set;
|
|
GdkRGBA old;
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
old_set = priv->primary_color_fg_set;
|
|
old = priv->primary_color_fg;
|
|
|
|
if (primary_color_fg != NULL)
|
|
{
|
|
priv->primary_color_fg = *primary_color_fg;
|
|
priv->primary_color_fg_set = TRUE;
|
|
}
|
|
else
|
|
{
|
|
memset (&priv->primary_color_fg, 0, sizeof priv->primary_color_fg);
|
|
priv->primary_color_fg_set = FALSE;
|
|
}
|
|
|
|
if (old_set != priv->primary_color_fg_set ||
|
|
!gdk_rgba_equal (&old, &priv->primary_color_fg))
|
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIMARY_COLOR_FG]);
|
|
}
|
|
|
|
/**
|
|
* ide_page_report_error:
|
|
* @self: a #IdePage
|
|
* @format: a printf-style format string
|
|
*
|
|
* This function reports an error to the user in the layout view.
|
|
*
|
|
* @format should be a printf-style format string followed by the
|
|
* arguments for the format.
|
|
*
|
|
* Since: 3.32
|
|
*/
|
|
void
|
|
ide_page_report_error (IdePage *self,
|
|
const gchar *format,
|
|
...)
|
|
{
|
|
g_autofree gchar *message = NULL;
|
|
GtkInfoBar *infobar;
|
|
GtkWidget *content_area;
|
|
GtkLabel *label;
|
|
va_list args;
|
|
|
|
g_return_if_fail (IDE_IS_PAGE (self));
|
|
|
|
va_start (args, format);
|
|
message = g_strdup_vprintf (format, args);
|
|
va_end (args);
|
|
|
|
infobar = g_object_new (GTK_TYPE_INFO_BAR,
|
|
"message-type", GTK_MESSAGE_WARNING,
|
|
"show-close-button", TRUE,
|
|
"visible", TRUE,
|
|
NULL);
|
|
g_signal_connect (infobar,
|
|
"response",
|
|
G_CALLBACK (gtk_widget_destroy),
|
|
NULL);
|
|
g_signal_connect (infobar,
|
|
"close",
|
|
G_CALLBACK (gtk_widget_destroy),
|
|
NULL);
|
|
|
|
label = g_object_new (GTK_TYPE_LABEL,
|
|
"label", message,
|
|
"visible", TRUE,
|
|
"wrap", TRUE,
|
|
"xalign", 0.0f,
|
|
NULL);
|
|
|
|
content_area = gtk_info_bar_get_content_area (infobar);
|
|
gtk_container_add (GTK_CONTAINER (content_area), GTK_WIDGET (label));
|
|
|
|
gtk_container_add_with_properties (GTK_CONTAINER (self), GTK_WIDGET (infobar),
|
|
"position", 0,
|
|
NULL);
|
|
}
|
|
|
|
/**
|
|
* ide_page_get_file_or_directory:
|
|
* @self: a #IdePage
|
|
*
|
|
* Gets a #GFile representing a file or directory that best maps to this
|
|
* page. A terminal might use the current working directory while an editor
|
|
* or designer might use the backing file.
|
|
*
|
|
* Returns: (transfer full) (nullable): a #GFile or %NULL
|
|
*
|
|
* Since: 3.40
|
|
*/
|
|
GFile *
|
|
ide_page_get_file_or_directory (IdePage *self)
|
|
{
|
|
g_return_val_if_fail (IDE_IS_PAGE (self), NULL);
|
|
|
|
if (IDE_PAGE_GET_CLASS (self)->get_file_or_directory)
|
|
return IDE_PAGE_GET_CLASS (self)->get_file_or_directory (self);
|
|
|
|
return NULL;
|
|
}
|