[gnome-builder/wip/plugins: 4/36] workspace: sketch out new workspace layout
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/plugins: 4/36] workspace: sketch out new workspace layout
- Date: Mon, 8 Jun 2015 20:27:13 +0000 (UTC)
commit d05d5be52e47716fc4fb0c6df52e78e86545623e
Author: Christian Hergert <christian hergert me>
Date: Fri Jun 5 18:08:35 2015 -0700
workspace: sketch out new workspace layout
This adds a new custom layout manager, GbWorkspace and GbWorkspacePane to
contain the children of the workspace.
This is not a full docking library, on purpose. It only supports animated
panes on left, right, and bottom.
It does, however, allow us to avoid using GtkPaned, which has been a
nightmare for keeping sizing information how we want.
I expect GbViewGrid will get rewritten as part of this to be a custom
multi-paned in the same way that GbWorkspace is.
I think we need to dive into GtkTextView a bit, and do some performance
work there with overzealous invalidations. For example, when shrinking
or growing the textwindow, as long as we don't render an invalid area,
we can keep using the pixel cached content. We should be more lazy about
destroying/repainting the textview. (Should help make animations smoother).
Anyway, is what it is. Very eary draft, tons to do, and will likely get
rebased often.
data/theme/Adwaita-shared.css | 7 +
data/theme/shared.css | 9 +
data/ui/gb-workbench.ui | 91 ++-
data/ui/gb-workspace-pane.ui | 41 +
data/ui/gb-workspace.ui | 30 +
src/Makefile.am | 14 +-
src/app/gb-application.c | 5 +-
src/commands/gb-command-bar.c | 7 +-
src/commands/gb-command-gaction-provider.c | 3 +-
src/editor/gb-editor-view-actions.c | 6 +
src/resources/gnome-builder.gresource.xml | 3 +-
src/search/gb-search-box.c | 6 +-
src/workbench/gb-workbench-actions.c | 107 +++
src/workbench/gb-workbench-private.h | 6 +-
src/workbench/gb-workbench-types.h | 1 -
src/workbench/gb-workbench.c | 87 +--
src/workbench/gb-workbench.h | 6 -
src/workbench/gb-workspace.c | 221 ------
src/workbench/gb-workspace.h | 53 --
src/workspace/gb-workspace-pane.c | 275 +++++++
src/workspace/gb-workspace-pane.h | 43 +
src/workspace/gb-workspace.c | 1137 ++++++++++++++++++++++++++++
src/workspace/gb-workspace.h | 40 +
23 files changed, 1809 insertions(+), 389 deletions(-)
---
diff --git a/data/theme/Adwaita-shared.css b/data/theme/Adwaita-shared.css
index 283d7c1..96dc651 100644
--- a/data/theme/Adwaita-shared.css
+++ b/data/theme/Adwaita-shared.css
@@ -38,3 +38,10 @@ GbNewProjectDialog GtkFileChooserButton.linked-on-right .button {
border-radius: 3px 0 0 3px;
}
+
+/*
+ * Workspace pane header styling.
+ */
+GbWorkspacePane GtkBox.header {
+ border-bottom: 1px solid @borders;
+}
diff --git a/data/theme/shared.css b/data/theme/shared.css
index 96e876f..b0cafd6 100644
--- a/data/theme/shared.css
+++ b/data/theme/shared.css
@@ -110,3 +110,12 @@ GbGreeterWindow GtkFrame {
border-right: 1px solid alpha(@borders, 0.4);
border-bottom: none;
}
+
+
+GbWorkspacePane {
+ -GbWorkspacePane-handle-size: 1;
+ -gtk-icon-source: none;
+}
+GbWorkspacePane .pane-separator {
+ background-color: @borders;
+}
diff --git a/data/ui/gb-workbench.ui b/data/ui/gb-workbench.ui
index f3f17f6..20b6cd3 100644
--- a/data/ui/gb-workbench.ui
+++ b/data/ui/gb-workbench.ui
@@ -32,6 +32,40 @@
<property name="pack_type">end</property>
</packing>
</child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="visible">true</property>
+ <property name="margin-end">12</property>
+ <style>
+ <class name="linked"/>
+ </style>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="action-name">workbench.show-left-pane</property>
+ <property name="label">L</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="action-name">workbench.show-bottom-pane</property>
+ <property name="label">B</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkToggleButton">
+ <property name="action-name">workbench.show-right-pane</property>
+ <property name="label">R</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
</object>
</child>
<child>
@@ -39,15 +73,60 @@
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
- <object class="GtkStack" id="stack">
+ <object class="GbWorkspace" id="workspace">
<property name="expand">true</property>
- <property name="transition_type">slide-up-down</property>
<property name="visible">true</property>
- <property name="homogeneous">false</property>
- <child>
- <object class="GbEditorWorkspace" id="editor_workspace">
- <property name="visible">true</property>
+ <child internal-child="content_pane">
+ <object class="GbWorkspacePane">
+ <child internal-child="stack_switcher">
+ <object class="GtkStackSwitcher">
+ <property name="visible">false</property>
+ </object>
+ </child>
+ <child internal-child="stack">
+ <object class="GtkStack">
+ <child>
+ <object class="GbViewGrid" id="view_grid">
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="left_pane">
+ <object class="GbWorkspacePane">
+ <child internal-child="stack">
+ <object class="GtkStack">
+ <child>
+ <object class="GbProjectTree" id="project_tree">
+ <property name="headers-visible">false</property>
+ <property name="vexpand">true</property>
+ <property name="visible">true</property>
+ </object>
+ <packing>
+ <property name="icon-name">folder-symbolic</property>
+ <property name="name">project_tree</property>
+ <property name="title" translatable="yes">Project</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child internal-child="right_pane">
+ <object class="GbWorkspacePane">
+ </object>
+ <packing>
+ <property name="reveal">false</property>
+ </packing>
+ </child>
+ <child internal-child="bottom_pane">
+ <object class="GbWorkspacePane">
</object>
+ <packing>
+ <property name="reveal">false</property>
+ </packing>
</child>
</object>
</child>
diff --git a/data/ui/gb-workspace-pane.ui b/data/ui/gb-workspace-pane.ui
new file mode 100644
index 0000000..c3e7ffe
--- /dev/null
+++ b/data/ui/gb-workspace-pane.ui
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.16 -->
+ <template class="GbWorkspacePane" parent="GtkBin">
+ <child>
+ <object class="GtkBox" id="box">
+ <property name="orientation">vertical</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">true</property>
+ <property name="vexpand">false</property>
+ <style>
+ <class name="header"/>
+ <class name="notebook"/>
+ </style>
+ <child type="center">
+ <object class="GtkStackSwitcher" id="stack_switcher">
+ <property name="margin-top">3</property>
+ <property name="margin-bottom">3</property>
+ <property name="margin-start">6</property>
+ <property name="margin-end">6</property>
+ <property name="stack">stack</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="expand">true</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/gb-workspace.ui b/data/ui/gb-workspace.ui
new file mode 100644
index 0000000..5dc5073
--- /dev/null
+++ b/data/ui/gb-workspace.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.8 -->
+ <template class="GbWorkspace" parent="GtkOverlay">
+ <child type="overlay">
+ <object class="GbWorkspacePane" id="left_pane">
+ <property name="position">left</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GbWorkspacePane" id="right_pane">
+ <property name="position">right</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GbWorkspacePane" id="bottom_pane">
+ <property name="position">bottom</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child type="overlay">
+ <object class="GbWorkspacePane" id="content_pane">
+ <property name="position">top</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 52926a7..6b4b3e9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,11 +65,6 @@ libgnome_builder_la_SOURCES = \
editor/gb-editor-view-private.h \
editor/gb-editor-view.c \
editor/gb-editor-view.h \
- editor/gb-editor-workspace-actions.c \
- editor/gb-editor-workspace-actions.h \
- editor/gb-editor-workspace-private.h \
- editor/gb-editor-workspace.c \
- editor/gb-editor-workspace.h \
gd/gd-tagged-entry.c \
gd/gd-tagged-entry.h \
greeter/gb-greeter-pill-box.c \
@@ -167,11 +162,13 @@ libgnome_builder_la_SOURCES = \
workbench/gb-workbench-actions.c \
workbench/gb-workbench-actions.h \
workbench/gb-workbench-private.h \
- workbench/gb-workbench-types.h \
workbench/gb-workbench.c \
workbench/gb-workbench.h \
- workbench/gb-workspace.c \
- workbench/gb-workspace.h \
+ workbench/gb-workbench-types.h \
+ workspace/gb-workspace.c \
+ workspace/gb-workspace.h \
+ workspace/gb-workspace-pane.c \
+ workspace/gb-workspace-pane.h \
css/gb-css-provider.c \
css/gb-css-provider.h \
util/gb-settings.c \
@@ -223,6 +220,7 @@ libgnome_builder_la_CFLAGS = \
-I$(srcdir)/views \
-I$(srcdir)/vim \
-I$(srcdir)/workbench \
+ -I$(srcdir)/workspace \
-I$(top_builddir)/libide \
-I$(top_srcdir)/libide \
-I$(top_srcdir)/contrib/egg \
diff --git a/src/app/gb-application.c b/src/app/gb-application.c
index 8a51fd0..157255d 100644
--- a/src/app/gb-application.c
+++ b/src/app/gb-application.c
@@ -31,7 +31,6 @@
#include "gb-application-private.h"
#include "gb-css-provider.h"
#include "gb-editor-document.h"
-#include "gb-editor-workspace.h"
#include "gb-glib.h"
#include "gb-greeter-window.h"
#include "gb-projects-dialog.h"
@@ -136,7 +135,9 @@ gb_application_load_keybindings (GbApplication *self)
g_autoptr(GSettings) settings = NULL;
g_autofree gchar *name = NULL;
static const struct { gchar *name; gchar *binding; } shared_bindings[] = {
- { "workspace.toggle-sidebar", "F9" },
+ { "workbench.show-left-pane", "F9" },
+ { "workbench.show-right-pane", "<shift>F9" },
+ { "workbench.show-bottom-pane", "<ctrl>F9" },
{ "workspace.focus-sidebar", "<ctrl>0" },
{ "workspace.focus-stack(1)", "<ctrl>1" },
{ "workspace.focus-stack(2)", "<ctrl>2" },
diff --git a/src/commands/gb-command-bar.c b/src/commands/gb-command-bar.c
index b4735c2..ebca621 100644
--- a/src/commands/gb-command-bar.c
+++ b/src/commands/gb-command-bar.c
@@ -108,7 +108,6 @@ void
gb_command_bar_hide (GbCommandBar *self)
{
GbWorkbench *workbench;
- GbWorkspace *workspace;
GtkWidget *focus;
g_return_if_fail (GB_IS_COMMAND_BAR (self));
@@ -122,14 +121,10 @@ gb_command_bar_hide (GbCommandBar *self)
if ((workbench == NULL) || gb_workbench_get_closing (workbench))
return;
- workspace = gb_workbench_get_active_workspace (workbench);
- if (workspace == NULL)
- return;
-
if (self->last_focus)
focus = find_alternate_focus (self->last_focus);
else
- focus = GTK_WIDGET (workspace);
+ focus = GTK_WIDGET (workbench);
gtk_widget_grab_focus (focus);
}
diff --git a/src/commands/gb-command-gaction-provider.c b/src/commands/gb-command-gaction-provider.c
index 5199335..37115b3 100644
--- a/src/commands/gb-command-gaction-provider.c
+++ b/src/commands/gb-command-gaction-provider.c
@@ -22,7 +22,6 @@
#include <string.h>
#include <glib.h>
-#include "gb-editor-workspace.h"
#include "gb-editor-view.h"
#include "gb-command-gaction-provider.h"
@@ -180,7 +179,7 @@ discover_groups (GbCommandGactionProvider *provider)
/* We exclude these types, they're already in the widgets hierarchy */
type = G_OBJECT_TYPE (widget);
- if (type == GB_TYPE_EDITOR_WORKSPACE || type == GB_TYPE_EDITOR_VIEW)
+ if (type == GB_TYPE_EDITOR_VIEW)
continue;
prefixes = gtk_widget_list_action_prefixes (widget);
diff --git a/src/editor/gb-editor-view-actions.c b/src/editor/gb-editor-view-actions.c
index d935d76..1ca4563 100644
--- a/src/editor/gb-editor-view-actions.c
+++ b/src/editor/gb-editor-view-actions.c
@@ -31,6 +31,7 @@
#include "gb-widget.h"
#include "gb-workbench.h"
+#if 0
static void
gb_editor_view_actions_source_view_notify (IdeSourceView *source_view,
GParamSpec *pspec,
@@ -709,10 +710,12 @@ static GActionEntry GbEditorViewActions[] = {
{ "toggle-split", gb_editor_view_actions_toggle_split },
{ "use-spaces", NULL, "b", "false", gb_editor_view_actions_use_spaces },
};
+#endif
void
gb_editor_view_actions_init (GbEditorView *self)
{
+#if 0
g_autoptr(GSimpleActionGroup) group = NULL;
group = g_simple_action_group_new ();
@@ -739,11 +742,13 @@ gb_editor_view_actions_init (GbEditorView *self)
WATCH_PROPERTY ("tab-width");
#undef WATCH_PROPERTY
+#endif
}
void
gb_editor_view_actions_update (GbEditorView *self)
{
+#if 0
GtkSourceLanguage *language;
const gchar *lang_id = NULL;
GActionGroup *group;
@@ -764,4 +769,5 @@ gb_editor_view_actions_update (GbEditorView *self)
(g_strcmp0 (lang_id, "markdown") == 0));
action = g_action_map_lookup_action (G_ACTION_MAP (group), "preview");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+#endif
}
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index c9d42d9..d1c25e8 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -48,7 +48,6 @@
<file alias="ui/gb-editor-settings-widget.ui">../../data/ui/gb-editor-settings-widget.ui</file>
<file alias="ui/gb-editor-tweak-widget.ui">../../data/ui/gb-editor-tweak-widget.ui</file>
<file alias="ui/gb-editor-view.ui">../../data/ui/gb-editor-view.ui</file>
- <file alias="ui/gb-editor-workspace.ui">../../data/ui/gb-editor-workspace.ui</file>
<file alias="ui/gb-greeter-pill-box.ui">../../data/ui/gb-greeter-pill-box.ui</file>
<file alias="ui/gb-greeter-project-row.ui">../../data/ui/gb-greeter-project-row.ui</file>
<file alias="ui/gb-greeter-window.ui">../../data/ui/gb-greeter-window.ui</file>
@@ -71,5 +70,7 @@
<file alias="ui/gb-search-display-row.ui">../../data/ui/gb-search-display-row.ui</file>
<file alias="ui/gb-view-stack.ui">../../data/ui/gb-view-stack.ui</file>
<file alias="ui/gb-workbench.ui">../../data/ui/gb-workbench.ui</file>
+ <file alias="ui/gb-workspace.ui">../../data/ui/gb-workspace.ui</file>
+ <file alias="ui/gb-workspace-pane.ui">../../data/ui/gb-workspace-pane.ui</file>
</gresource>
</gresources>
diff --git a/src/search/gb-search-box.c b/src/search/gb-search-box.c
index 77b39b1..f4fe3d8 100644
--- a/src/search/gb-search-box.c
+++ b/src/search/gb-search-box.c
@@ -20,7 +20,6 @@
#include <glib/gi18n.h>
-#include "gb-editor-workspace.h"
#include "gb-glib.h"
#include "gb-scrolled-window.h"
#include "gb-search-box.h"
@@ -258,11 +257,10 @@ gb_search_box_display_result_activated (GbSearchBox *self,
else if (IDE_IS_DEVHELP_SEARCH_RESULT (result))
{
g_autofree gchar *uri = NULL;
- GbEditorWorkspace *workspace;
g_object_get (result, "uri", &uri, NULL);
- workspace = gb_workbench_get_workspace_typed (workbench, GB_TYPE_EDITOR_WORKSPACE);
- gb_editor_workspace_show_help (workspace, uri);
+ //workspace = gb_workbench_get_workspace_typed (workbench, GB_TYPE_EDITOR_WORKSPACE);
+ //gb_editor_workspace_show_help (workspace, uri);
}
else
{
diff --git a/src/workbench/gb-workbench-actions.c b/src/workbench/gb-workbench-actions.c
index 8ebf0a8..fcfdca8 100644
--- a/src/workbench/gb-workbench-actions.c
+++ b/src/workbench/gb-workbench-actions.c
@@ -278,6 +278,7 @@ gb_workbench_actions_search_docs (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
+#if 0
GbWorkbench *self = user_data;
const gchar *str;
@@ -285,6 +286,7 @@ gb_workbench_actions_search_docs (GSimpleAction *action,
str = g_variant_get_string (parameter, NULL);
gb_editor_workspace_search_help (self->editor_workspace, str);
+#endif
}
static void
@@ -299,6 +301,83 @@ gb_workbench_actions_show_gear_menu (GSimpleAction *action,
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->gear_menu_button), TRUE);
}
+static void
+gb_workbench_actions_show_left_pane (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GbWorkbench *self = user_data;
+ GtkWidget *left_pane;
+ gboolean reveal = FALSE;
+
+ g_assert (GB_IS_WORKBENCH (self));
+
+ left_pane = gb_workspace_get_left_pane (self->workspace);
+ gtk_container_child_get (GTK_CONTAINER (self->workspace), left_pane,
+ "reveal", &reveal,
+ NULL);
+ gtk_container_child_set (GTK_CONTAINER (self->workspace), left_pane,
+ "reveal", !reveal,
+ NULL);
+}
+
+static void
+gb_workbench_actions_show_right_pane (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GbWorkbench *self = user_data;
+ GtkWidget *right_pane;
+ gboolean reveal = FALSE;
+
+ g_assert (GB_IS_WORKBENCH (self));
+
+ right_pane = gb_workspace_get_right_pane (self->workspace);
+ gtk_container_child_get (GTK_CONTAINER (self->workspace), right_pane,
+ "reveal", &reveal,
+ NULL);
+ gtk_container_child_set (GTK_CONTAINER (self->workspace), right_pane,
+ "reveal", !reveal,
+ NULL);
+}
+
+static void
+gb_workbench_actions_show_bottom_pane (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GbWorkbench *self = user_data;
+ GtkWidget *bottom_pane;
+ gboolean reveal = FALSE;
+
+ g_assert (GB_IS_WORKBENCH (self));
+
+ bottom_pane = gb_workspace_get_bottom_pane (self->workspace);
+ gtk_container_child_get (GTK_CONTAINER (self->workspace), bottom_pane,
+ "reveal", &reveal,
+ NULL);
+ gtk_container_child_set (GTK_CONTAINER (self->workspace), bottom_pane,
+ "reveal", !reveal,
+ NULL);
+}
+
+static void
+sync_reveal_state (GtkWidget *child,
+ GParamSpec *pspec,
+ GSimpleAction *action)
+{
+ gboolean reveal = FALSE;
+
+ g_assert (GB_IS_WORKSPACE_PANE (child));
+ g_assert (pspec != NULL);
+ g_assert (G_IS_SIMPLE_ACTION (action));
+
+ gtk_container_child_get (GTK_CONTAINER (gtk_widget_get_parent (child)), child,
+ "reveal", &reveal,
+ NULL);
+ g_simple_action_set_state (action, g_variant_new_boolean (reveal));
+}
+
static const GActionEntry GbWorkbenchActions[] = {
{ "build", gb_workbench_actions_build },
{ "dayhack", gb_workbench_actions_dayhack },
@@ -313,6 +392,9 @@ static const GActionEntry GbWorkbenchActions[] = {
{ "search-docs", gb_workbench_actions_search_docs, "s" },
{ "show-command-bar", gb_workbench_actions_show_command_bar },
{ "show-gear-menu", gb_workbench_actions_show_gear_menu },
+ { "show-left-pane", gb_workbench_actions_show_left_pane, NULL, "true" },
+ { "show-right-pane", gb_workbench_actions_show_right_pane, NULL, "false" },
+ { "show-bottom-pane", gb_workbench_actions_show_bottom_pane, NULL, "false" },
};
void
@@ -335,5 +417,30 @@ gb_workbench_actions_init (GbWorkbench *self)
g_object_bind_property (self, "building", action, "enabled",
(G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN));
+ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "rebuild");
+ g_object_bind_property (self, "building", action, "enabled",
+ (G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN));
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "show-left-pane");
+ g_signal_connect_object (gb_workspace_get_left_pane (self->workspace),
+ "child-notify::reveal",
+ G_CALLBACK (sync_reveal_state),
+ action,
+ 0);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "show-right-pane");
+ g_signal_connect_object (gb_workspace_get_right_pane (self->workspace),
+ "child-notify::reveal",
+ G_CALLBACK (sync_reveal_state),
+ action,
+ 0);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (actions), "show-bottom-pane");
+ g_signal_connect_object (gb_workspace_get_bottom_pane (self->workspace),
+ "child-notify::reveal",
+ G_CALLBACK (sync_reveal_state),
+ action,
+ 0);
+
gtk_widget_insert_action_group (GTK_WIDGET (self), "workbench", G_ACTION_GROUP (actions));
}
diff --git a/src/workbench/gb-workbench-private.h b/src/workbench/gb-workbench-private.h
index 3d99018..d48c5a8 100644
--- a/src/workbench/gb-workbench-private.h
+++ b/src/workbench/gb-workbench-private.h
@@ -41,15 +41,11 @@ struct _GbWorkbench
GCancellable *unload_cancellable;
gchar *current_folder_uri;
- /* Weak reference */
- GbWorkspace *active_workspace;
-
/* Template references */
GbCommandBar *command_bar;
- GbEditorWorkspace *editor_workspace;
GeditMenuStackSwitcher *gear_menu_button;
GbSearchBox *search_box;
- GtkStack *stack;
+ GbWorkspace *workspace;
gulong project_notify_name_handler;
diff --git a/src/workbench/gb-workbench-types.h b/src/workbench/gb-workbench-types.h
index 9c5f6b3..8b95cf3 100644
--- a/src/workbench/gb-workbench-types.h
+++ b/src/workbench/gb-workbench-types.h
@@ -24,7 +24,6 @@
G_BEGIN_DECLS
typedef struct _GbWorkbench GbWorkbench;
-typedef struct _GbWorkspace GbWorkspace;
G_END_DECLS
diff --git a/src/workbench/gb-workbench.c b/src/workbench/gb-workbench.c
index 337bd4c..7f322bc 100644
--- a/src/workbench/gb-workbench.c
+++ b/src/workbench/gb-workbench.c
@@ -30,6 +30,9 @@
#include "gb-workbench-private.h"
#include "gb-workbench.h"
#include "gb-workspace.h"
+#include "gb-workspace-pane.h"
+#include "gb-project-tree.h"
+#include "gb-view-grid.h"
G_DEFINE_TYPE (GbWorkbench, gb_workbench, GTK_TYPE_APPLICATION_WINDOW)
@@ -100,7 +103,7 @@ gb_workbench__context_restore_cb (GObject *object,
if ((ide_buffer_manager_get_n_buffers (buffer_manager) == 0) && (self->has_opened == FALSE))
gb_workbench_add_temporary_buffer (self);
- gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
+ gtk_widget_grab_focus (GTK_WIDGET (self->workspace));
}
static void
@@ -284,7 +287,7 @@ gb_workbench_grab_focus (GtkWidget *widget)
g_assert (GB_IS_WORKBENCH (self));
- gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
+ gtk_widget_grab_focus (GTK_WIDGET (self->workspace));
}
static void
@@ -295,7 +298,7 @@ gb_workbench_realize (GtkWidget *widget)
if (GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize)
GTK_WIDGET_CLASS (gb_workbench_parent_class)->realize (widget);
- gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
+ gtk_widget_grab_focus (GTK_WIDGET (self->workspace));
ide_context_restore_async (self->context,
NULL,
@@ -314,18 +317,13 @@ gb_workbench_constructed (GObject *object)
G_OBJECT_CLASS (gb_workbench_parent_class)->constructed (object);
- gb_workbench_set_active_workspace (self, GB_WORKSPACE (self->editor_workspace));
-
gb_workbench_actions_init (self);
app = GTK_APPLICATION (g_application_get_default ());
menu = gtk_application_get_menu_by_id (app, "gear-menu");
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (self->gear_menu_button), G_MENU_MODEL (menu));
- if (self->active_workspace)
- gtk_widget_grab_focus (GTK_WIDGET (self->active_workspace));
- else
- gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
+ gtk_widget_grab_focus (GTK_WIDGET (self->workspace));
IDE_EXIT;
}
@@ -356,7 +354,6 @@ gb_workbench_finalize (GObject *object)
IDE_ENTRY;
- ide_clear_weak_pointer (&self->active_workspace);
g_clear_object (&self->context);
g_clear_pointer (&self->current_folder_uri, g_free);
@@ -375,10 +372,6 @@ gb_workbench_get_property (GObject *object,
switch (prop_id)
{
- case PROP_ACTIVE_WORKSPACE:
- g_value_set_object (value, gb_workbench_get_active_workspace (self));
- break;
-
case PROP_BUILDING:
g_value_set_boolean (value, self->building);
break;
@@ -406,10 +399,6 @@ gb_workbench_set_property (GObject *object,
switch (prop_id)
{
- case PROP_ACTIVE_WORKSPACE:
- gb_workbench_set_active_workspace (self, g_value_get_object (value));
- break;
-
case PROP_CONTEXT:
gb_workbench_set_context (self, g_value_get_object (value));
break;
@@ -487,14 +476,16 @@ gb_workbench_class_init (GbWorkbenchClass *klass)
GB_WIDGET_CLASS_TEMPLATE (klass, "gb-workbench.ui");
GB_WIDGET_CLASS_BIND (klass, GbWorkbench, command_bar);
- GB_WIDGET_CLASS_BIND (klass, GbWorkbench, editor_workspace);
GB_WIDGET_CLASS_BIND (klass, GbWorkbench, gear_menu_button);
GB_WIDGET_CLASS_BIND (klass, GbWorkbench, search_box);
- GB_WIDGET_CLASS_BIND (klass, GbWorkbench, stack);
+ GB_WIDGET_CLASS_BIND (klass, GbWorkbench, workspace);
g_type_ensure (GB_TYPE_COMMAND_BAR);
- g_type_ensure (GB_TYPE_EDITOR_WORKSPACE);
+ g_type_ensure (GB_TYPE_PROJECT_TREE);
g_type_ensure (GB_TYPE_SEARCH_BOX);
+ g_type_ensure (GB_TYPE_VIEW_GRID);
+ g_type_ensure (GB_TYPE_WORKSPACE);
+ g_type_ensure (GB_TYPE_WORKSPACE_PANE);
g_type_ensure (GEDIT_TYPE_MENU_STACK_SWITCHER);
}
@@ -545,38 +536,6 @@ gb_workbench_get_context (GbWorkbench *self)
return self->context;
}
-/**
- * gb_workbench_get_active_workspace:
- * @self: A #GbWorkbench.
- *
- * Gets the currently selected workspace.
- *
- * Returns: (transfer none): An #GbWorkspace.
- */
-GbWorkspace *
-gb_workbench_get_active_workspace (GbWorkbench *self)
-{
- g_return_val_if_fail (GB_IS_WORKBENCH (self), NULL);
-
- return self->active_workspace;
-}
-
-void
-gb_workbench_set_active_workspace (GbWorkbench *self,
- GbWorkspace *workspace)
-{
- GActionGroup *group;
-
- g_return_if_fail (GB_IS_WORKBENCH (self));
- g_return_if_fail (GB_IS_WORKSPACE (workspace));
-
- if (ide_set_weak_pointer (&self->active_workspace, workspace))
- gtk_stack_set_visible_child (self->stack, GTK_WIDGET (workspace));
-
- group = gtk_widget_get_action_group (GTK_WIDGET (workspace), "workspace");
- gtk_widget_insert_action_group (GTK_WIDGET (self), "workspace", group);
-}
-
static gboolean
supports_content_type (const gchar *filename,
const gchar *content_type)
@@ -732,26 +691,6 @@ gb_workbench_open_uri_list (GbWorkbench *self,
}
}
-/**
- * gb_workbench_get_workspace_typed:
- * @self: A #GbWorkbench.
- *
- * Gets the workspace matching @workspace_type
- *
- * Returns: (transfer none): A #GbWorkspace.
- */
-gpointer
-gb_workbench_get_workspace_typed (GbWorkbench *self,
- GType workspace_type)
-{
- g_return_val_if_fail (GB_IS_WORKBENCH (self), NULL);
-
- if (workspace_type == GB_TYPE_EDITOR_WORKSPACE)
- return self->editor_workspace;
-
- return NULL;
-}
-
static void
gb_workbench__builder_build_cb (GObject *object,
GAsyncResult *result,
@@ -890,5 +829,5 @@ gb_workbench_views_foreach (GbWorkbench *self,
g_return_if_fail (GB_IS_WORKBENCH (self));
g_return_if_fail (callback != NULL);
- gb_workspace_views_foreach (GB_WORKSPACE (self->editor_workspace), callback, callback_data);
+ //gb_workspace_views_foreach (GB_WORKSPACE (self->editor_workspace), callback, callback_data);
}
diff --git a/src/workbench/gb-workbench.h b/src/workbench/gb-workbench.h
index 1675710..8bd1fac 100644
--- a/src/workbench/gb-workbench.h
+++ b/src/workbench/gb-workbench.h
@@ -23,7 +23,6 @@
#include <ide.h>
#include "gb-command-manager.h"
-#include "gb-workbench-types.h"
G_BEGIN_DECLS
@@ -40,9 +39,6 @@ gboolean gb_workbench_build_finish (GbWorkbench *self,
GAsyncResult *result,
GError **error);
IdeContext *gb_workbench_get_context (GbWorkbench *self);
-GbWorkspace *gb_workbench_get_active_workspace (GbWorkbench *self);
-void gb_workbench_set_active_workspace (GbWorkbench *self,
- GbWorkspace *workspace);
void gb_workbench_add_temporary_buffer (GbWorkbench *self);
void gb_workbench_open (GbWorkbench *self,
GFile *file);
@@ -51,8 +47,6 @@ void gb_workbench_open_with_editor (GbWorkbench *self,
void gb_workbench_open_uri_list (GbWorkbench *self,
const gchar * const *uri_list);
GbCommandManager *gb_workbench_get_command_manager (GbWorkbench *self);
-gpointer gb_workbench_get_workspace_typed (GbWorkbench *self,
- GType workspace_type);
gboolean gb_workbench_get_closing (GbWorkbench *self);
void gb_workbench_views_foreach (GbWorkbench *self,
GtkCallback callback,
diff --git a/src/workspace/gb-workspace-pane.c b/src/workspace/gb-workspace-pane.c
new file mode 100644
index 0000000..02d86fc
--- /dev/null
+++ b/src/workspace/gb-workspace-pane.c
@@ -0,0 +1,275 @@
+/* gb-workspace-pane.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include <glib/gi18n.h>
+
+#include "gb-workspace-pane.h"
+
+struct _GbWorkspacePane
+{
+ GtkBin parent_instance;
+
+ GtkBox *box;
+ GtkStackSwitcher *stack_switcher;
+ GtkStack *stack;
+
+ GdkRectangle handle_pos;
+
+ GtkPositionType position;
+};
+
+G_DEFINE_TYPE (GbWorkspacePane, gb_workspace_pane, GTK_TYPE_BIN)
+
+enum {
+ PROP_0,
+ PROP_POSITION,
+ LAST_PROP
+};
+
+enum {
+ STYLE_PROP_0,
+ STYLE_PROP_HANDLE_SIZE,
+ LAST_STYLE_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+static GParamSpec *gStyleParamSpecs [LAST_STYLE_PROP];
+
+static gboolean
+gb_workspace_pane_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ GbWorkspacePane *self = (GbWorkspacePane *)widget;
+ GtkStyleContext *style_context;
+ gboolean ret;
+
+ g_assert (GB_IS_WORKSPACE_PANE (self));
+ g_assert (cr != NULL);
+
+ ret = GTK_WIDGET_CLASS (gb_workspace_pane_parent_class)->draw (widget, cr);
+
+ style_context = gtk_widget_get_style_context (widget);
+
+ gtk_style_context_save (style_context);
+ gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_PANE_SEPARATOR);
+ gtk_render_handle (style_context, cr,
+ self->handle_pos.x,
+ self->handle_pos.y,
+ self->handle_pos.width,
+ self->handle_pos.height);
+ gtk_style_context_restore (style_context);
+
+ return ret;
+}
+
+static void
+gb_workspace_pane_size_allocate (GtkWidget *widget,
+ GtkAllocation *alloc)
+{
+ GbWorkspacePane *self = (GbWorkspacePane *)widget;
+ GtkWidget *child;
+ GtkAllocation child_alloc;
+ gint handle_size;
+
+ g_assert (GB_IS_WORKSPACE_PANE (self));
+
+ gtk_widget_set_allocation (widget, alloc);
+
+ child = gtk_bin_get_child (GTK_BIN (self));
+ if (child == NULL || !gtk_widget_get_visible (child))
+ return;
+
+ gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+
+ child_alloc = *alloc;
+
+ switch (self->position)
+ {
+ case GTK_POS_LEFT:
+ child_alloc.width -= handle_size;
+ self->handle_pos.x = child_alloc.x + child_alloc.width;
+ self->handle_pos.width = handle_size;
+ self->handle_pos.height = child_alloc.height;
+ self->handle_pos.y = child_alloc.y;
+ break;
+
+ case GTK_POS_RIGHT:
+ child_alloc.x += handle_size;
+ child_alloc.width -= handle_size;
+ self->handle_pos.x = alloc->x;
+ self->handle_pos.width = handle_size;
+ self->handle_pos.height = child_alloc.height;
+ self->handle_pos.y = child_alloc.y;
+ break;
+
+ case GTK_POS_BOTTOM:
+ child_alloc.y += handle_size;
+ child_alloc.height -= handle_size;
+ self->handle_pos.x = alloc->x;
+ self->handle_pos.width = alloc->width;
+ self->handle_pos.height = handle_size;
+ self->handle_pos.y = alloc->y;
+ break;
+
+ case GTK_POS_TOP:
+ self->handle_pos.x = 0;
+ self->handle_pos.y = 0;
+ self->handle_pos.width = 0;
+ self->handle_pos.height = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ gtk_widget_size_allocate (child, &child_alloc);
+}
+
+static void
+gb_workspace_pane_finalize (GObject *object)
+{
+ GbWorkspacePane *self = (GbWorkspacePane *)object;
+
+ self->stack = NULL;
+ self->stack_switcher = NULL;
+
+ G_OBJECT_CLASS (gb_workspace_pane_parent_class)->finalize (object);
+}
+
+static void
+gb_workspace_pane_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbWorkspacePane *self = GB_WORKSPACE_PANE (object);
+
+ switch (prop_id)
+ {
+ case PROP_POSITION:
+ g_value_set_enum (value, gb_workspace_pane_get_position (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_pane_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbWorkspacePane *self = GB_WORKSPACE_PANE (object);
+
+ switch (prop_id)
+ {
+ case PROP_POSITION:
+ gb_workspace_pane_set_position (self, g_value_get_enum (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_pane_class_init (GbWorkspacePaneClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gb_workspace_pane_finalize;
+ object_class->get_property = gb_workspace_pane_get_property;
+ object_class->set_property = gb_workspace_pane_set_property;
+
+ widget_class->draw = gb_workspace_pane_draw;
+ widget_class->size_allocate = gb_workspace_pane_size_allocate;
+
+ /**
+ * GbWorkspacePane:position:
+ *
+ * The position at which to place the pane. This also dictates which
+ * direction that animations will occur.
+ *
+ * For example, setting to %GTK_POS_LEFT will result in the resize grip
+ * being placed on the right, and animations to and from the leftmost
+ * of the allocation.
+ */
+ gParamSpecs [PROP_POSITION] =
+ g_param_spec_enum ("position",
+ _("Position"),
+ _("The position of the pane."),
+ GTK_TYPE_POSITION_TYPE,
+ GTK_POS_LEFT,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
+
+ gStyleParamSpecs [STYLE_PROP_HANDLE_SIZE] =
+ g_param_spec_int ("handle-size",
+ "Handle Size",
+ "Width of handle.",
+ 0, G_MAXINT,
+ 1,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gtk_widget_class_install_style_property (widget_class,
+ gStyleParamSpecs [STYLE_PROP_HANDLE_SIZE]);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/gb-workspace-pane.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbWorkspacePane, box);
+ gtk_widget_class_bind_template_child_internal (widget_class, GbWorkspacePane, stack);
+ gtk_widget_class_bind_template_child_internal (widget_class, GbWorkspacePane, stack_switcher);
+}
+
+static void
+gb_workspace_pane_init (GbWorkspacePane *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GtkWidget *
+gb_workspace_pane_new (void)
+{
+ return g_object_new (GB_TYPE_WORKSPACE_PANE, NULL);
+}
+
+GtkPositionType
+gb_workspace_pane_get_position (GbWorkspacePane *self)
+{
+ g_return_val_if_fail (GB_IS_WORKSPACE_PANE (self), GTK_POS_LEFT);
+
+ return self->position;
+}
+
+void
+gb_workspace_pane_set_position (GbWorkspacePane *self,
+ GtkPositionType position)
+{
+ g_return_if_fail (GB_IS_WORKSPACE_PANE (self));
+ g_return_if_fail (position >= GTK_POS_LEFT);
+ g_return_if_fail (position <= GTK_POS_BOTTOM);
+
+ if (position != self->position)
+ {
+ self->position = position;
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_POSITION]);
+ }
+}
diff --git a/src/workspace/gb-workspace-pane.h b/src/workspace/gb-workspace-pane.h
new file mode 100644
index 0000000..66e8db8
--- /dev/null
+++ b/src/workspace/gb-workspace-pane.h
@@ -0,0 +1,43 @@
+/* gb-workspace-pane.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_WORKSPACE_PANE_H
+#define GB_WORKSPACE_PANE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_WORKSPACE_PANE (gb_workspace_pane_get_type())
+
+G_DECLARE_FINAL_TYPE (GbWorkspacePane, gb_workspace_pane, GB, WORKSPACE_PANE, GtkBin)
+
+gboolean gb_workspace_pane_get_floating (GbWorkspacePane *self);
+guint gb_workspace_pane_get_transition_duration (GbWorkspacePane *self);
+GtkWidget *gb_workspace_pane_new (void);
+void gb_workspace_pane_set_floating (GbWorkspacePane *self,
+ gboolean floating);
+void gb_workspace_pane_set_transition_duration (GbWorkspacePane *self,
+ guint transition_duration);
+GtkPositionType gb_workspace_pane_get_position (GbWorkspacePane *self);
+void gb_workspace_pane_set_position (GbWorkspacePane *self,
+ GtkPositionType position);
+
+G_END_DECLS
+
+#endif /* GB_WORKSPACE_PANE_H */
diff --git a/src/workspace/gb-workspace.c b/src/workspace/gb-workspace.c
new file mode 100644
index 0000000..e4810d9
--- /dev/null
+++ b/src/workspace/gb-workspace.c
@@ -0,0 +1,1137 @@
+/* gb-workspace.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#include <glib/gi18n.h>
+#include <ide.h>
+#include <string.h>
+
+#include "gb-workspace.h"
+#include "gb-workspace-pane.h"
+
+#define ANIMATION_MODE IDE_ANIMATION_EASE_IN_OUT_QUAD
+#define ANIMATION_DURATION 250
+#define HORIZ_GRIP_EXTRA 10
+#define VERT_GRIP_EXTRA 10
+#define MIN_POSITION 100
+
+typedef struct
+{
+ GtkWidget *widget;
+ GtkAdjustment *adjustment;
+ IdeAnimation *animation;
+ GdkWindow *handle;
+ GtkAllocation handle_pos;
+ GtkAllocation alloc;
+ gint min_width;
+ gint min_height;
+ gint nat_width;
+ gint nat_height;
+ gint position;
+ gint restore_position;
+ GdkCursorType cursor_type;
+ GtkPositionType type : 4;
+ guint reveal : 1;
+ guint hiding : 1;
+ guint showing : 1;
+} GbWorkspaceChild;
+
+struct _GbWorkspace
+{
+ GtkOverlay parent_instance;
+
+ GbWorkspaceChild children[4];
+
+ GtkGesture *pan_gesture;
+
+ GbWorkspaceChild *drag_child;
+ gdouble drag_position;
+};
+
+G_DEFINE_TYPE (GbWorkspace, gb_workspace, GTK_TYPE_OVERLAY)
+
+enum {
+ PROP_0,
+ PROP_BOTTOM_PANE,
+ PROP_CONTENT_PANE,
+ PROP_LEFT_PANE,
+ PROP_RIGHT_PANE,
+ LAST_PROP
+};
+
+enum {
+ CHILD_PROP_0,
+ CHILD_PROP_REVEAL,
+ CHILD_PROP_POSITION,
+ LAST_CHILD_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+static GParamSpec *gChildParamSpecs [LAST_CHILD_PROP];
+
+static void
+gb_workspace_move_resize_handle (GbWorkspace *self,
+ GtkPositionType type)
+{
+ GbWorkspaceChild *child;
+ GtkAllocation alloc;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert ((type == GTK_POS_LEFT) ||
+ (type == GTK_POS_RIGHT) ||
+ (type == GTK_POS_BOTTOM));
+
+ child = &self->children [type];
+
+ if (child->handle == NULL)
+ return;
+
+ gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+ switch (type)
+ {
+ case GTK_POS_LEFT:
+ child->handle_pos.x = alloc.x + child->alloc.x + child->alloc.width - HORIZ_GRIP_EXTRA;
+ child->handle_pos.y = alloc.y + child->alloc.y;
+ child->handle_pos.width = 2 * HORIZ_GRIP_EXTRA;
+ child->handle_pos.height = child->alloc.height;
+ break;
+
+ case GTK_POS_RIGHT:
+ child->handle_pos.x = alloc.x + child->alloc.x - HORIZ_GRIP_EXTRA;
+ child->handle_pos.y = alloc.y + child->alloc.y;
+ child->handle_pos.width = 2 * HORIZ_GRIP_EXTRA;
+ child->handle_pos.height = child->alloc.height;
+ break;
+
+ case GTK_POS_BOTTOM:
+ child->handle_pos.x = alloc.x + child->alloc.x;
+ child->handle_pos.y = alloc.y + child->alloc.y - VERT_GRIP_EXTRA;
+ child->handle_pos.width = child->alloc.width;
+ child->handle_pos.height = 2 * VERT_GRIP_EXTRA;
+ break;
+
+ case GTK_POS_TOP:
+ default:
+ break;
+ }
+
+ if (!gtk_widget_get_child_visible (child->widget))
+ memset (&child->handle_pos, 0, sizeof child->handle_pos);
+
+ if (gtk_widget_get_mapped (GTK_WIDGET (self)))
+ gdk_window_move_resize (child->handle,
+ child->handle_pos.x,
+ child->handle_pos.y,
+ child->handle_pos.width,
+ child->handle_pos.height);
+}
+
+static void
+gb_workspace_create_handle_window (GbWorkspace *self,
+ GtkPositionType type)
+{
+ GbWorkspaceChild *child;
+ GtkAllocation alloc;
+ GdkWindowAttr attributes = { 0 };
+ GdkWindow *parent;
+ GdkDisplay *display;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert ((type == GTK_POS_LEFT) ||
+ (type == GTK_POS_RIGHT) ||
+ (type == GTK_POS_BOTTOM));
+
+ display = gtk_widget_get_display (GTK_WIDGET (self));
+ parent = gtk_widget_get_window (GTK_WIDGET (self));
+
+ g_assert (GDK_IS_DISPLAY (display));
+ g_assert (GDK_IS_WINDOW (parent));
+
+ gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+ child = &self->children [type];
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.x = child->handle_pos.x;
+ attributes.y = child->handle_pos.y;
+ attributes.width = child->handle_pos.width;
+ attributes.height = child->handle_pos.height;
+ attributes.visual = gtk_widget_get_visual (GTK_WIDGET (self));
+ attributes.event_mask = gtk_widget_get_events (GTK_WIDGET (self));
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK);
+ attributes.cursor = gdk_cursor_new_for_display (display, child->cursor_type);
+
+ child->handle = gdk_window_new (parent, &attributes, (GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y));
+ gtk_widget_register_window (GTK_WIDGET (self), child->handle);
+
+ g_clear_object (&attributes.cursor);
+}
+
+static void
+gb_workspace_destroy_handle_window (GbWorkspace *self,
+ GtkPositionType type)
+{
+ GbWorkspaceChild *child;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ child = &self->children [type];
+
+ if (child->handle)
+ {
+ gdk_window_hide (child->handle);
+ gtk_widget_unregister_window (GTK_WIDGET (self), child->handle);
+ gdk_window_destroy (child->handle);
+ child->handle = NULL;
+ }
+}
+
+static void
+gb_workspace_relayout (GbWorkspace *self,
+ const GtkAllocation *alloc)
+{
+ GbWorkspaceChild *left;
+ GbWorkspaceChild *right;
+ GbWorkspaceChild *content;
+ GbWorkspaceChild *bottom;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (alloc != NULL);
+
+ left = &self->children [GTK_POS_LEFT];
+ right = &self->children [GTK_POS_RIGHT];
+ content = &self->children [GTK_POS_TOP];
+ bottom = &self->children [GTK_POS_BOTTOM];
+
+ /*
+ * Determine everything as if we are animating in/out or the child is visible.
+ */
+
+ if (left->reveal)
+ {
+ left->alloc.x = 0;
+ left->alloc.y = 0;
+ left->alloc.width = left->position;
+ left->alloc.height = alloc->height;
+
+ left->alloc.x -= gtk_adjustment_get_value (left->adjustment) * left->position;
+ }
+ else
+ {
+ left->alloc.x = -left->position;
+ left->alloc.y = 0;
+ left->alloc.width = left->position;
+ left->alloc.height = alloc->height;
+ }
+
+ if (right->reveal)
+ {
+ right->alloc.x = alloc->width - right->position;
+ right->alloc.y = 0;
+ right->alloc.width = right->position;
+ right->alloc.height = alloc->height;
+
+ right->alloc.x += gtk_adjustment_get_value (right->adjustment) * right->position;
+ }
+ else
+ {
+ right->alloc.x = alloc->width;
+ right->alloc.y = 0;
+ right->alloc.width = right->position;
+ right->alloc.height = alloc->height;
+ }
+
+ if (bottom->reveal)
+ {
+ bottom->alloc.x = left->alloc.x + left->alloc.width;
+ bottom->alloc.y = alloc->height - bottom->position;
+ bottom->alloc.width = right->alloc.x - bottom->alloc.x;
+ bottom->alloc.height = bottom->position;
+
+ bottom->alloc.y += gtk_adjustment_get_value (bottom->adjustment) * bottom->position;
+ }
+ else
+ {
+ bottom->alloc.x = left->alloc.x + left->alloc.width;
+ bottom->alloc.y = alloc->height;
+ bottom->alloc.width = right->alloc.x - bottom->alloc.x;
+ bottom->alloc.height = bottom->position;
+ }
+
+ if (content->reveal)
+ {
+ content->alloc.x = left->alloc.x + left->alloc.width;
+ content->alloc.y = 0;
+ content->alloc.width = right->alloc.x - content->alloc.x;
+ content->alloc.height = bottom->alloc.y;
+
+ content->alloc.y -= gtk_adjustment_get_value (content->adjustment) * content->alloc.height;
+ }
+ else
+ {
+ content->alloc.x = left->alloc.x + left->alloc.width;
+ content->alloc.y = -bottom->alloc.y;
+ content->alloc.width = right->alloc.x - content->alloc.x;
+ content->alloc.height = bottom->alloc.y;
+ }
+
+ /*
+ * Now adjust for child visibility.
+ *
+ * We need to ensure we don't give the non-visible children an allocation
+ * as it will interfere with hit targets.
+ */
+ if (!gtk_widget_get_child_visible (content->widget))
+ memset (&content->alloc, 0, sizeof content->alloc);
+ if (!gtk_widget_get_child_visible (left->widget))
+ memset (&left->alloc, 0, sizeof left->alloc);
+ if (!gtk_widget_get_child_visible (right->widget))
+ memset (&right->alloc, 0, sizeof right->alloc);
+ if (!gtk_widget_get_child_visible (bottom->widget))
+ memset (&bottom->alloc, 0, sizeof bottom->alloc);
+
+ gb_workspace_move_resize_handle (self, GTK_POS_LEFT);
+ gb_workspace_move_resize_handle (self, GTK_POS_RIGHT);
+ gb_workspace_move_resize_handle (self, GTK_POS_BOTTOM);
+}
+
+static void
+gb_workspace_size_allocate (GtkWidget *widget,
+ GtkAllocation *alloc)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (alloc != NULL);
+
+ gb_workspace_relayout (self, alloc);
+
+ GTK_WIDGET_CLASS (gb_workspace_parent_class)->size_allocate (widget, alloc);
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ if ((child->handle != NULL) &&
+ gtk_widget_get_visible (child->widget) &&
+ gtk_widget_get_child_visible (child->widget))
+ gdk_window_raise (child->handle);
+ }
+}
+
+static GbWorkspaceChild *
+gb_workspace_child_find (GbWorkspace *self,
+ GtkWidget *child)
+{
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *item = &self->children [i];
+
+ if (item->widget == child)
+ return item;
+ }
+
+ g_warning ("Child of type %s was not found in this GbWorkspace.",
+ g_type_name (G_OBJECT_TYPE (child)));
+
+ return NULL;
+}
+
+static void
+gb_workspace_animation_cb (gpointer data)
+{
+ g_autoptr(GtkWidget) child = data;
+ GtkWidget *parent;
+ GbWorkspace *self;
+ GbWorkspaceChild *item;
+
+ g_assert (GTK_IS_WIDGET (child));
+
+ parent = gtk_widget_get_parent (child);
+ if (!GB_IS_WORKSPACE (parent))
+ return;
+
+ self = GB_WORKSPACE (parent);
+
+ item = gb_workspace_child_find (self, child);
+ if (item == NULL)
+ return;
+
+ if (item->hiding)
+ {
+ gtk_widget_set_child_visible (item->widget, FALSE);
+ if (item->restore_position > item->position)
+ item->position = item->restore_position;
+ }
+
+ item->showing = FALSE;
+ item->hiding = FALSE;
+ item->reveal = gtk_adjustment_get_value (item->adjustment) == 0.0;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ gtk_container_child_notify (GTK_CONTAINER (self), child, "reveal");
+}
+
+static gboolean
+gb_workspace_get_child_position (GtkOverlay *overlay,
+ GtkWidget *child,
+ GtkAllocation *alloc)
+{
+ GbWorkspace *self = (GbWorkspace *)overlay;
+ GbWorkspaceChild *item;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+ g_assert (alloc != NULL);
+
+ if (!(item = gb_workspace_child_find (self, child)))
+ return FALSE;
+
+ *alloc = item->alloc;
+
+ return TRUE;
+}
+
+static guint
+gb_workspace_child_get_position (GbWorkspace *self,
+ GtkWidget *child)
+{
+ GbWorkspaceChild *item;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ if (!(item = gb_workspace_child_find (self, child)))
+ return FALSE;
+
+ return item->position;
+}
+
+static void
+gb_workspace_child_set_position (GbWorkspace *self,
+ GtkWidget *child,
+ guint position)
+{
+ GbWorkspaceChild *item;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ if (!(item = gb_workspace_child_find (self, child)))
+ return;
+
+ item->position = position;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ gtk_container_child_notify (GTK_CONTAINER (self), child, "position");
+}
+
+static gboolean
+gb_workspace_child_get_reveal (GbWorkspace *self,
+ GtkWidget *child)
+{
+ GbWorkspaceChild *item;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ if (!(item = gb_workspace_child_find (self, child)))
+ return FALSE;
+
+ return item->reveal;
+}
+
+static void
+gb_workspace_child_set_reveal (GbWorkspace *self,
+ GtkWidget *child,
+ gboolean reveal)
+{
+ GbWorkspaceChild *item;
+ GdkFrameClock *frame_clock;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_WIDGET (child));
+
+ reveal = !!reveal;
+
+ if (!(item = gb_workspace_child_find (self, child)) || (item->reveal == reveal))
+ return;
+
+ if (item->animation != NULL)
+ {
+ ide_animation_stop (item->animation);
+ ide_clear_weak_pointer (&item->animation);
+ }
+
+ item->reveal = TRUE;
+ item->showing = reveal;
+ item->hiding = !reveal;
+
+ if (item->position > MIN_POSITION)
+ {
+ item->restore_position = item->position;
+ gtk_container_child_notify (GTK_CONTAINER (self), item->widget, "position");
+ }
+
+ gtk_widget_set_child_visible (child, TRUE);
+
+ frame_clock = gtk_widget_get_frame_clock (child);
+
+ item->animation = ide_object_animate_full (item->adjustment,
+ ANIMATION_MODE,
+ ANIMATION_DURATION,
+ frame_clock,
+ gb_workspace_animation_cb,
+ g_object_ref (child),
+ "value", reveal ? 0.0 : 1.0,
+ NULL);
+ g_object_add_weak_pointer (G_OBJECT (item->animation), (gpointer *)&item->animation);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static void
+gb_workspace_get_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbWorkspace *self = (GbWorkspace *)container;
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_REVEAL:
+ g_value_set_boolean (value, gb_workspace_child_get_reveal (self, child));
+ break;
+
+ case CHILD_PROP_POSITION:
+ g_value_set_uint (value, gb_workspace_child_get_position (self, child));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_set_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbWorkspace *self = (GbWorkspace *)container;
+
+ switch (prop_id)
+ {
+ case CHILD_PROP_REVEAL:
+ gb_workspace_child_set_reveal (self, child, g_value_get_boolean (value));
+ break;
+
+ case CHILD_PROP_POSITION:
+ gb_workspace_child_set_position (self, child, g_value_get_uint (value));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_get_preferred_width (GtkWidget *widget,
+ gint *min_width,
+ gint *nat_width)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ if (gtk_widget_get_visible (child->widget))
+ gtk_widget_get_preferred_width (child->widget, &child->min_width, &child->nat_width);
+ }
+
+ *min_width = self->children [GTK_POS_LEFT].min_width
+ + self->children [GTK_POS_RIGHT].min_width
+ + MAX (self->children [GTK_POS_TOP].min_width,
+ self->children [GTK_POS_BOTTOM].min_width);
+ *nat_width = self->children [GTK_POS_LEFT].nat_width
+ + self->children [GTK_POS_RIGHT].nat_width
+ + MAX (self->children [GTK_POS_TOP].nat_width,
+ self->children [GTK_POS_BOTTOM].nat_width);
+}
+
+static void
+gb_workspace_get_preferred_height (GtkWidget *widget,
+ gint *min_height,
+ gint *nat_height)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ if (gtk_widget_get_visible (child->widget))
+ gtk_widget_get_preferred_height (child->widget, &child->min_height, &child->nat_height);
+ }
+
+ *min_height = MAX (MAX (self->children [GTK_POS_LEFT].min_height,
+ self->children [GTK_POS_RIGHT].min_height),
+ (self->children [GTK_POS_BOTTOM].position +
+ self->children [GTK_POS_TOP].min_height));
+
+ *nat_height = MAX (MAX (self->children [GTK_POS_LEFT].nat_height,
+ self->children [GTK_POS_RIGHT].nat_height),
+ (self->children [GTK_POS_BOTTOM].position +
+ self->children [GTK_POS_TOP].nat_height));
+}
+
+static GtkSizeRequestMode
+gb_workspace_get_request_mode (GtkWidget *widget)
+{
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+static GtkAdjustment *
+gb_workspace_create_adjustment (GbWorkspace *self)
+{
+ GtkAdjustment *adj;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ adj = g_object_new (GTK_TYPE_ADJUSTMENT,
+ "lower", 0.0,
+ "upper", 1.0,
+ "value", 0.0,
+ NULL);
+
+ g_signal_connect_object (adj,
+ "value-changed",
+ G_CALLBACK (gtk_widget_queue_resize),
+ self,
+ G_CONNECT_SWAPPED);
+
+ return adj;
+}
+
+static void
+gb_workspace_drag_begin_cb (GbWorkspace *self,
+ gdouble x,
+ gdouble y,
+ GtkGesturePan *pan)
+{
+ GbWorkspaceChild *left;
+ GbWorkspaceChild *right;
+ GbWorkspaceChild *bottom;
+ GdkEventSequence *sequence;
+ const GdkEvent *event;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_GESTURE_PAN (pan));
+
+ left = &self->children [GTK_POS_LEFT];
+ right = &self->children [GTK_POS_RIGHT];
+ bottom = &self->children [GTK_POS_BOTTOM];
+
+ sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (pan));
+ event = gtk_gesture_get_last_event (GTK_GESTURE (pan), sequence);
+
+ if (event->any.window == left->handle)
+ {
+ gtk_gesture_pan_set_orientation (pan, GTK_ORIENTATION_HORIZONTAL);
+ self->drag_child = left;
+ }
+ else if (event->any.window == right->handle)
+ {
+ gtk_gesture_pan_set_orientation (pan, GTK_ORIENTATION_HORIZONTAL);
+ self->drag_child = right;
+ }
+ else if (event->any.window == bottom->handle)
+ {
+ gtk_gesture_pan_set_orientation (pan, GTK_ORIENTATION_VERTICAL);
+ self->drag_child = bottom;
+ }
+ else
+ {
+ gtk_gesture_set_state (GTK_GESTURE (pan), GTK_EVENT_SEQUENCE_DENIED);
+ self->drag_child = NULL;
+ return;
+ }
+
+ self->drag_position = MAX (self->drag_child->position, MIN_POSITION);
+ gtk_gesture_set_state (GTK_GESTURE (pan), GTK_EVENT_SEQUENCE_CLAIMED);
+ gtk_container_child_notify (GTK_CONTAINER (self), self->drag_child->widget, "position");
+}
+
+static void
+gb_workspace_drag_end_cb (GbWorkspace *self,
+ gdouble x,
+ gdouble y,
+ GtkGesturePan *pan)
+{
+ GdkEventSequence *sequence;
+ GtkEventSequenceState state;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_GESTURE_PAN (pan));
+
+ if (self->drag_child == NULL)
+ return;
+
+ sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (pan));
+ state = gtk_gesture_get_sequence_state (GTK_GESTURE (pan), sequence);
+ if (state == GTK_EVENT_SEQUENCE_DENIED)
+ {
+ self->drag_child = NULL;
+ return;
+ }
+
+ if (self->drag_child->position < MIN_POSITION)
+ {
+ gtk_container_child_set (GTK_CONTAINER (self), self->drag_child->widget,
+ "reveal", FALSE,
+ NULL);
+ self->drag_child->restore_position = self->drag_position;
+ }
+
+ gtk_container_child_notify (GTK_CONTAINER (self), self->drag_child->widget, "position");
+
+ self->drag_child = NULL;
+ self->drag_position = 0;
+}
+
+static void
+gb_workspace_pan_cb (GbWorkspace *self,
+ GtkPanDirection direction,
+ gdouble offset,
+ GtkGesturePan *pan)
+{
+ GtkAllocation alloc;
+ gint target_position = 0;
+ gint center_min_width;
+ gint left_max;
+ gint right_max;
+ gint bottom_max;
+
+ g_assert (GB_IS_WORKSPACE (self));
+ g_assert (GTK_IS_GESTURE_PAN (pan));
+ g_assert (self->drag_child != NULL);
+
+ /*
+ * NOTE: This is trickier than it looks, so I choose to be
+ * very verbose. Feel free to clean it up.
+ */
+
+ gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+ switch (direction)
+ {
+ case GTK_PAN_DIRECTION_LEFT:
+ if (self->drag_child->type == GTK_POS_LEFT)
+ target_position = self->drag_position - offset;
+ else if (self->drag_child->type == GTK_POS_RIGHT)
+ target_position = self->drag_position + offset;
+ break;
+
+ case GTK_PAN_DIRECTION_RIGHT:
+ if (self->drag_child->type == GTK_POS_LEFT)
+ target_position = self->drag_position + offset;
+ else if (self->drag_child->type == GTK_POS_RIGHT)
+ target_position = self->drag_position - offset;
+ break;
+
+ case GTK_PAN_DIRECTION_UP:
+ if (self->drag_child->type == GTK_POS_BOTTOM)
+ target_position = self->drag_position + offset;
+ break;
+
+ case GTK_PAN_DIRECTION_DOWN:
+ if (self->drag_child->type == GTK_POS_BOTTOM)
+ target_position = self->drag_position - offset;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ center_min_width = MAX (self->children [GTK_POS_BOTTOM].min_width,
+ self->children [GTK_POS_TOP].min_width);
+ left_max = alloc.width - self->children [GTK_POS_RIGHT].alloc.width - center_min_width;
+ right_max = alloc.width - self->children [GTK_POS_LEFT].position - center_min_width;
+ bottom_max = alloc.height - self->children [GTK_POS_TOP].min_height;
+
+ switch (self->drag_child->type)
+ {
+ case GTK_POS_LEFT:
+ target_position = MIN (left_max, target_position);
+ break;
+
+ case GTK_POS_RIGHT:
+ target_position = MIN (right_max, target_position);
+ break;
+
+ case GTK_POS_BOTTOM:
+ target_position = MIN (bottom_max, target_position);
+ break;
+
+ case GTK_POS_TOP:
+ default:
+ g_assert_not_reached ();
+ }
+
+ self->drag_child->position = MAX (0, target_position);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static GtkGesture *
+gb_workspace_create_pan_gesture (GbWorkspace *self,
+ GtkOrientation orientation)
+{
+ GtkGesture *gesture;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ gesture = gtk_gesture_pan_new (GTK_WIDGET (self), orientation);
+ gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
+ gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
+
+ g_signal_connect_object (gesture,
+ "drag-begin",
+ G_CALLBACK (gb_workspace_drag_begin_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (gesture,
+ "drag-end",
+ G_CALLBACK (gb_workspace_drag_end_cb),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (gesture,
+ "pan",
+ G_CALLBACK (gb_workspace_pan_cb),
+ self,
+ G_CONNECT_SWAPPED);
+
+ return gesture;
+}
+
+static void
+gb_workspace_realize (GtkWidget *widget)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ GTK_WIDGET_CLASS (gb_workspace_parent_class)->realize (widget);
+
+ gb_workspace_create_handle_window (self, GTK_POS_LEFT);
+ gb_workspace_create_handle_window (self, GTK_POS_RIGHT);
+ gb_workspace_create_handle_window (self, GTK_POS_BOTTOM);
+}
+
+static void
+gb_workspace_unrealize (GtkWidget *widget)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ gb_workspace_destroy_handle_window (self, GTK_POS_LEFT);
+ gb_workspace_destroy_handle_window (self, GTK_POS_RIGHT);
+ gb_workspace_destroy_handle_window (self, GTK_POS_BOTTOM);
+
+ GTK_WIDGET_CLASS (gb_workspace_parent_class)->unrealize (widget);
+}
+
+static void
+gb_workspace_map (GtkWidget *widget)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ GTK_WIDGET_CLASS (gb_workspace_parent_class)->map (widget);
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ if (child->handle != NULL)
+ gdk_window_show (child->handle);
+ }
+}
+
+static void
+gb_workspace_unmap (GtkWidget *widget)
+{
+ GbWorkspace *self = (GbWorkspace *)widget;
+ int i;
+
+ g_assert (GB_IS_WORKSPACE (self));
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ if (child->handle != NULL)
+ gdk_window_hide (child->handle);
+ }
+
+ GTK_WIDGET_CLASS (gb_workspace_parent_class)->unmap (widget);
+}
+
+static void
+gb_workspace_finalize (GObject *object)
+{
+ GbWorkspace *self = (GbWorkspace *)object;
+ gsize i;
+
+ for (i = 0; i < G_N_ELEMENTS (self->children); i++)
+ {
+ GbWorkspaceChild *child = &self->children [i];
+
+ ide_clear_weak_pointer (&child->animation);
+ g_clear_object (&child->adjustment);
+ }
+
+ g_clear_object (&self->pan_gesture);
+
+ G_OBJECT_CLASS (gb_workspace_parent_class)->finalize (object);
+}
+
+static void
+gb_workspace_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbWorkspace *self = GB_WORKSPACE (object);
+
+ switch (prop_id)
+ {
+ case PROP_LEFT_PANE:
+ g_value_set_object (value, gb_workspace_get_left_pane (self));
+ break;
+
+ case PROP_RIGHT_PANE:
+ g_value_set_object (value, gb_workspace_get_right_pane (self));
+ break;
+
+ case PROP_BOTTOM_PANE:
+ g_value_set_object (value, gb_workspace_get_bottom_pane (self));
+ break;
+
+ case PROP_CONTENT_PANE:
+ g_value_set_object (value, gb_workspace_get_content_pane (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gb_workspace_class_init (GbWorkspaceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+ GtkOverlayClass *overlay_class = GTK_OVERLAY_CLASS (klass);
+
+ object_class->finalize = gb_workspace_finalize;
+ object_class->get_property = gb_workspace_get_property;
+ object_class->set_property = gb_workspace_set_property;
+
+ widget_class->get_preferred_height = gb_workspace_get_preferred_height;
+ widget_class->get_preferred_width = gb_workspace_get_preferred_width;
+ widget_class->get_request_mode = gb_workspace_get_request_mode;
+ widget_class->map = gb_workspace_map;
+ widget_class->unmap = gb_workspace_unmap;
+ widget_class->realize = gb_workspace_realize;
+ widget_class->unrealize = gb_workspace_unrealize;
+ widget_class->size_allocate = gb_workspace_size_allocate;
+
+ container_class->get_child_property = gb_workspace_get_child_property;
+ container_class->set_child_property = gb_workspace_set_child_property;
+
+ overlay_class->get_child_position = gb_workspace_get_child_position;
+
+ gParamSpecs [PROP_LEFT_PANE] =
+ g_param_spec_object ("left-pane",
+ _("Left Pane"),
+ _("The left workspace pane."),
+ GTK_TYPE_WIDGET,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gParamSpecs [PROP_RIGHT_PANE] =
+ g_param_spec_object ("right-pane",
+ _("Right Pane"),
+ _("The right workspace pane."),
+ GTK_TYPE_WIDGET,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gParamSpecs [PROP_BOTTOM_PANE] =
+ g_param_spec_object ("bottom-pane",
+ _("Bottom Pane"),
+ _("The bottom workspace pane."),
+ GTK_TYPE_WIDGET,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ gParamSpecs [PROP_CONTENT_PANE] =
+ g_param_spec_object ("content-pane",
+ _("Content Pane"),
+ _("The content workspace pane."),
+ GTK_TYPE_WIDGET,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
+
+ gChildParamSpecs [CHILD_PROP_POSITION] =
+ g_param_spec_uint ("position",
+ _("Position"),
+ _("The position of the pane relative to it's edge."),
+ 0, G_MAXUINT,
+ 0,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gtk_container_class_install_child_property (container_class, CHILD_PROP_POSITION,
+ gChildParamSpecs [CHILD_PROP_POSITION]);
+
+ gChildParamSpecs [CHILD_PROP_REVEAL] =
+ g_param_spec_boolean ("reveal",
+ _("Reveal"),
+ _("If the pane should be revealed."),
+ TRUE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gtk_container_class_install_child_property (container_class, CHILD_PROP_REVEAL,
+ gChildParamSpecs [CHILD_PROP_REVEAL]);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/gb-workspace.ui");
+
+ gtk_widget_class_bind_template_child_full (widget_class, "bottom_pane", TRUE,
+ G_STRUCT_OFFSET (GbWorkspace, children[GTK_POS_BOTTOM].widget));
+ gtk_widget_class_bind_template_child_full (widget_class, "content_pane", TRUE,
+ G_STRUCT_OFFSET (GbWorkspace, children[GTK_POS_TOP].widget));
+ gtk_widget_class_bind_template_child_full (widget_class, "left_pane", TRUE,
+ G_STRUCT_OFFSET (GbWorkspace, children[GTK_POS_LEFT].widget));
+ gtk_widget_class_bind_template_child_full (widget_class, "right_pane", TRUE,
+ G_STRUCT_OFFSET (GbWorkspace, children[GTK_POS_RIGHT].widget));
+}
+
+static void
+gb_workspace_init (GbWorkspace *self)
+{
+ self->children [GTK_POS_LEFT].type = GTK_POS_LEFT;
+ self->children [GTK_POS_LEFT].reveal = TRUE;
+ self->children [GTK_POS_LEFT].position = 250;
+ self->children [GTK_POS_LEFT].adjustment = gb_workspace_create_adjustment (self);
+ self->children [GTK_POS_LEFT].cursor_type = GDK_SB_H_DOUBLE_ARROW;
+
+ self->children [GTK_POS_RIGHT].type = GTK_POS_RIGHT;
+ self->children [GTK_POS_RIGHT].reveal = TRUE;
+ self->children [GTK_POS_RIGHT].position = 250;
+ self->children [GTK_POS_RIGHT].adjustment = gb_workspace_create_adjustment (self);
+ self->children [GTK_POS_RIGHT].cursor_type = GDK_SB_H_DOUBLE_ARROW;
+
+ self->children [GTK_POS_BOTTOM].type = GTK_POS_BOTTOM;
+ self->children [GTK_POS_BOTTOM].reveal = TRUE;
+ self->children [GTK_POS_BOTTOM].position = 150;
+ self->children [GTK_POS_BOTTOM].adjustment = gb_workspace_create_adjustment (self);
+ self->children [GTK_POS_BOTTOM].cursor_type = GDK_SB_V_DOUBLE_ARROW;
+
+ self->children [GTK_POS_TOP].type = GTK_POS_TOP;
+ self->children [GTK_POS_TOP].reveal = TRUE;
+ self->children [GTK_POS_TOP].adjustment = gb_workspace_create_adjustment (self);
+
+ self->pan_gesture = gb_workspace_create_pan_gesture (self, GTK_ORIENTATION_HORIZONTAL);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GtkWidget *
+gb_workspace_new (void)
+{
+ return g_object_new (GB_TYPE_WORKSPACE, NULL);
+}
+
+GtkWidget *
+gb_workspace_get_left_pane (GbWorkspace *self)
+{
+ g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
+
+ return self->children [GTK_POS_LEFT].widget;
+}
+
+GtkWidget *
+gb_workspace_get_right_pane (GbWorkspace *self)
+{
+ g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
+
+ return self->children [GTK_POS_RIGHT].widget;
+}
+
+GtkWidget *
+gb_workspace_get_bottom_pane (GbWorkspace *self)
+{
+ g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
+
+ return self->children [GTK_POS_BOTTOM].widget;
+}
+
+GtkWidget *
+gb_workspace_get_content_pane (GbWorkspace *self)
+{
+ g_return_val_if_fail (GB_IS_WORKSPACE (self), NULL);
+
+ return self->children [GTK_POS_TOP].widget;
+}
diff --git a/src/workspace/gb-workspace.h b/src/workspace/gb-workspace.h
new file mode 100644
index 0000000..fc7ad1a
--- /dev/null
+++ b/src/workspace/gb-workspace.h
@@ -0,0 +1,40 @@
+/* gb-workspace.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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/>.
+ */
+
+#ifndef GB_WORKSPACE_H
+#define GB_WORKSPACE_H
+
+#include <gtk/gtk.h>
+
+#include "gb-workspace-pane.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_WORKSPACE (gb_workspace_get_type())
+
+G_DECLARE_FINAL_TYPE (GbWorkspace, gb_workspace, GB, WORKSPACE, GtkOverlay)
+
+GtkWidget *gb_workspace_new (void);
+GtkWidget *gb_workspace_get_left_pane (GbWorkspace *self);
+GtkWidget *gb_workspace_get_right_pane (GbWorkspace *self);
+GtkWidget *gb_workspace_get_bottom_pane (GbWorkspace *self);
+GtkWidget *gb_workspace_get_content_pane (GbWorkspace *self);
+
+G_END_DECLS
+
+#endif /* GB_WORKSPACE_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]