[gnome-builder/wip/chergert/perspective] libide: more libide, more interfaces, get rid of most of src/
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/perspective] libide: more libide, more interfaces, get rid of most of src/
- Date: Tue, 3 Nov 2015 05:52:02 +0000 (UTC)
commit 5a012c936e523fb06071df772574807697aa8dbf
Author: Christian Hergert <chergert redhat com>
Date: Mon Nov 2 21:51:37 2015 -0800
libide: more libide, more interfaces, get rid of most of src/
contrib/egg/Makefile.am | 14 +
.../egg/egg-pill-box.c | 60 +-
.../egg/egg-pill-box.h | 20 +-
.../egg/egg-pill-box.ui | 4 +-
contrib/egg/egg.gresource.xml | 6 +
data/theme/Adwaita-dark.css | 6 +
data/theme/Adwaita.css | 2 +-
data/theme/shared.css | 11 +
data/ui/ide-greeter-perspective.ui | 146 +++
data/ui/ide-workbench-header-bar.ui | 25 +
data/ui/ide-workbench.ui | 33 +
libide/Makefile.am | 34 +-
libide/ide-application-actions.c | 317 ++++++
.../ide-application-actions.h | 19 +-
libide/ide-application-addin.c | 81 ++
libide/ide-application-addin.h | 47 +
libide/ide-application-credits.h | 554 +++++++++++
.../ide-application-private.h | 37 +-
libide/ide-application.c | 1002 ++++++++++++++++++++
libide/ide-application.h | 57 ++
libide/ide-css-provider.c | 176 ++++
.../ide-css-provider.h | 17 +-
libide/ide-greeter-perspective.c | 83 ++
.../ide-greeter-perspective.h | 21 +-
libide/ide-internal.h | 2 +-
libide/ide-keybindings.c | 282 ++++++
libide/ide-keybindings.h | 39 +
libide/ide-layout-manager.c | 72 ++
libide/ide-layout-manager.h | 60 ++
libide/ide-perspective.c | 236 +++++
libide/ide-perspective.h | 61 ++
libide/ide-preferences-addin.c | 81 ++
libide/ide-preferences-addin.h | 49 +
libide/ide-preferences.c | 116 +++
libide/ide-preferences.h | 105 ++
libide/ide-thread-pool.c | 21 +-
libide/ide-view.c | 129 +++
libide/ide-view.h | 61 ++
libide/ide-workbench-addin.c | 83 ++
libide/ide-workbench-addin.h | 47 +
libide/ide-workbench-header-bar.c | 58 ++
.../ide-workbench-header-bar.h | 24 +-
libide/ide-workbench.c | 323 +++++++
libide/ide-workbench.h | 69 ++
libide/ide.c | 36 -
libide/ide.h | 6 +
libide/resources/libide.gresource.xml | 7 +
src/Makefile.am | 2 -
src/greeter/gb-greeter-project-row.c | 4 +-
src/main.c | 3 +-
src/resources/gnome-builder.gresource.xml | 1 -
51 files changed, 4597 insertions(+), 152 deletions(-)
---
diff --git a/contrib/egg/Makefile.am b/contrib/egg/Makefile.am
index 3c0f260..1255205 100644
--- a/contrib/egg/Makefile.am
+++ b/contrib/egg/Makefile.am
@@ -1,6 +1,7 @@
CLEANFILES =
DISTCLEANFILES =
EXTRA_DIST =
+BUILT_SOURCES =
pkglibdir = $(libdir)/gnome-builder
pkglib_LTLIBRARIES = libegg-private.la
@@ -16,6 +17,8 @@ libegg_private_la_SOURCES = \
egg-frame-source.h \
egg-heap.c \
egg-heap.h \
+ egg-pill-box.c \
+ egg-pill-box.h \
egg-private.h \
egg-search-bar.c \
egg-search-bar.h \
@@ -35,6 +38,17 @@ libegg_private_la_SOURCES = \
egg-task-cache.h \
$(NULL)
+nodist_libegg_private_la_SOURCES = \
+ egg-resources.c \
+ egg-resources.h \
+ $(NULL)
+
+glib_resources_c = egg-resources.c
+glib_resources_h = egg-resources.h
+glib_resources_xml = egg.gresource.xml
+glib_resources_namespace = egg
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
libegg_private_la_CFLAGS = \
$(EGG_CFLAGS) \
$(NULL)
diff --git a/src/greeter/gb-greeter-pill-box.c b/contrib/egg/egg-pill-box.c
similarity index 55%
rename from src/greeter/gb-greeter-pill-box.c
rename to contrib/egg/egg-pill-box.c
index fdf1e56..a40630a 100644
--- a/src/greeter/gb-greeter-pill-box.c
+++ b/contrib/egg/egg-pill-box.c
@@ -1,4 +1,4 @@
-/* gb-greeter-pill-box.c
+/* egg-pill-box.c
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -16,20 +16,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define G_LOG_DOMAIN "gb-greeter-pill-box"
+#define G_LOG_DOMAIN "egg-pill-box"
#include <glib/gi18n.h>
-#include "gb-greeter-pill-box.h"
+#include "egg-pill-box.h"
-struct _GbGreeterPillBox
+struct _EggPillBox
{
GtkEventBox parent_instance;
GtkLabel *label;
};
-G_DEFINE_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GTK_TYPE_EVENT_BOX)
+G_DEFINE_TYPE (EggPillBox, egg_pill_box, GTK_TYPE_EVENT_BOX)
enum {
PROP_0,
@@ -40,42 +40,42 @@ enum {
static GParamSpec *properties [LAST_PROP];
const gchar *
-gb_greeter_pill_box_get_label (GbGreeterPillBox *self)
+egg_pill_box_get_label (EggPillBox *self)
{
- g_return_val_if_fail (GB_IS_GREETER_PILL_BOX (self), NULL);
+ g_return_val_if_fail (EGG_IS_PILL_BOX (self), NULL);
return gtk_label_get_label (self->label);
}
void
-gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label)
+egg_pill_box_set_label (EggPillBox *self,
+ const gchar *label)
{
- g_return_if_fail (GB_IS_GREETER_PILL_BOX (self));
+ g_return_if_fail (EGG_IS_PILL_BOX (self));
gtk_label_set_label (self->label, label);
}
GtkWidget *
-gb_greeter_pill_box_new (const gchar *label)
+egg_pill_box_new (const gchar *label)
{
- return g_object_new (GB_TYPE_GREETER_PILL_BOX,
+ return g_object_new (EGG_TYPE_PILL_BOX,
"label", label,
NULL);
}
static void
-gb_greeter_pill_box_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+egg_pill_box_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- GbGreeterPillBox *self = GB_GREETER_PILL_BOX (object);
+ EggPillBox *self = EGG_PILL_BOX (object);
switch (prop_id)
{
case PROP_LABEL:
- g_value_set_string (value, gb_greeter_pill_box_get_label (self));
+ g_value_set_string (value, egg_pill_box_get_label (self));
break;
default:
@@ -84,17 +84,17 @@ gb_greeter_pill_box_get_property (GObject *object,
}
static void
-gb_greeter_pill_box_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+egg_pill_box_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GbGreeterPillBox *self = GB_GREETER_PILL_BOX (object);
+ EggPillBox *self = EGG_PILL_BOX (object);
switch (prop_id)
{
case PROP_LABEL:
- gb_greeter_pill_box_set_label (self, g_value_get_string (value));
+ egg_pill_box_set_label (self, g_value_get_string (value));
break;
default:
@@ -103,13 +103,13 @@ gb_greeter_pill_box_set_property (GObject *object,
}
static void
-gb_greeter_pill_box_class_init (GbGreeterPillBoxClass *klass)
+egg_pill_box_class_init (EggPillBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
- object_class->get_property = gb_greeter_pill_box_get_property;
- object_class->set_property = gb_greeter_pill_box_set_property;
+ object_class->get_property = egg_pill_box_get_property;
+ object_class->set_property = egg_pill_box_set_property;
properties [PROP_LABEL] =
g_param_spec_string ("label",
@@ -119,12 +119,12 @@ gb_greeter_pill_box_class_init (GbGreeterPillBoxClass *klass)
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_LABEL, properties [PROP_LABEL]);
- gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/gb-greeter-pill-box.ui");
- gtk_widget_class_bind_template_child (widget_class, GbGreeterPillBox, label);
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libegg-private/egg-pill-box.ui");
+ gtk_widget_class_bind_template_child (widget_class, EggPillBox, label);
}
static void
-gb_greeter_pill_box_init (GbGreeterPillBox *self)
+egg_pill_box_init (EggPillBox *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
diff --git a/src/greeter/gb-greeter-pill-box.h b/contrib/egg/egg-pill-box.h
similarity index 58%
copy from src/greeter/gb-greeter-pill-box.h
copy to contrib/egg/egg-pill-box.h
index 394a333..88faf6c 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/contrib/egg/egg-pill-box.h
@@ -1,4 +1,4 @@
-/* gb-greeter-pill-box.h
+/* egg-pill-box.h
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -16,22 +16,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef EGG_PILL_BOX_H
+#define EGG_PILL_BOX_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
+#define EGG_TYPE_PILL_BOX (egg_pill_box_get_type())
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
+G_DECLARE_FINAL_TYPE (EggPillBox, egg_pill_box, EGG, PILL_BOX, GtkEventBox)
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+GtkWidget *egg_pill_box_new (const gchar *label);
+const gchar *egg_pill_box_get_label (EggPillBox *self);
+void egg_pill_box_set_label (EggPillBox *self,
+ const gchar *label);
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* EGG_PILL_BOX_H */
diff --git a/data/ui/gb-greeter-pill-box.ui b/contrib/egg/egg-pill-box.ui
similarity index 91%
rename from data/ui/gb-greeter-pill-box.ui
rename to contrib/egg/egg-pill-box.ui
index 069e75f..1fb94f7 100644
--- a/data/ui/gb-greeter-pill-box.ui
+++ b/contrib/egg/egg-pill-box.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <!-- interface-requires gtk+ 3.15 -->
- <template class="GbGreeterPillBox" parent="GtkEventBox">
+ <!-- interface-requires gtk+ 3.18 -->
+ <template class="EggPillBox" parent="GtkEventBox">
<style>
<class name="pill-box"/>
</style>
diff --git a/contrib/egg/egg.gresource.xml b/contrib/egg/egg.gresource.xml
new file mode 100644
index 0000000..41879df
--- /dev/null
+++ b/contrib/egg/egg.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/libegg-private">
+ <file>egg-pill-box.ui</file>
+ </gresource>
+</gresources>
diff --git a/data/theme/Adwaita-dark.css b/data/theme/Adwaita-dark.css
index 7ae52c2..35d7e2b 100644
--- a/data/theme/Adwaita-dark.css
+++ b/data/theme/Adwaita-dark.css
@@ -15,6 +15,12 @@ treeview.view.cell:selected {
}
+EggPillBox {
+ background-color: #1e1e1e;
+ border-radius: 3px;
+}
+
+
RgGraph {
background-color: #2e3436;
background-size: 8px 8px;
diff --git a/data/theme/Adwaita.css b/data/theme/Adwaita.css
index 5be481f..32ef4f4 100644
--- a/data/theme/Adwaita.css
+++ b/data/theme/Adwaita.css
@@ -15,7 +15,7 @@ GbWorkbench treeview.view.cell:selected {
}
-GbGreeterPillBox {
+EggPillBox {
background-color: #eeeeec;
border-radius: 3px;
}
diff --git a/data/theme/shared.css b/data/theme/shared.css
index a17facf..b3f3ac7 100644
--- a/data/theme/shared.css
+++ b/data/theme/shared.css
@@ -164,3 +164,14 @@ GbWorkspacePane .pane-separator {
GbEditorFrame textview {
padding-bottom: 250px;
}
+
+
+IdeWorkbench IdeGreeterPerspective GtkListBox {
+ border: 1px solid alpha(@borders, 0.4);
+}
+IdeWorkbench IdeGreeterPerspective GtkListBox GtkListBoxRow {
+ border-bottom: 1px solid alpha(@borders, 0.4);
+}
+IdeWorkbench IdeGreeterPerspective GtkListBox GtkListBoxRow:last-child {
+ border-bottom: 0px;
+}
diff --git a/data/ui/ide-greeter-perspective.ui b/data/ui/ide-greeter-perspective.ui
new file mode 100644
index 0000000..e10bcde
--- /dev/null
+++ b/data/ui/ide-greeter-perspective.ui
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.19 -->
+ <template class="IdeGreeterPerspective" parent="GtkBin">
+ <child>
+ <object class="GtkBox">
+ <property name="expand">true</property>
+ <property name="orientation">vertical</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="EggSearchBar" id="search_bar">
+ <property name="visible">true</property>
+ <child internal-child="entry">
+ <object class="GtkSearchEntry">
+ <property name="width-chars">40</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="vexpand">true</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkBox">
+ <property name="margin">24</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">24</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkBox">
+ <property name="halign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="visible">true</property>
+ <property name="width-request">600</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Recent Projects</property>
+ <property name="visible">true</property>
+ <property name="xalign">0.0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="recent_projects_list_box">
+ <property name="selection-mode">none</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="height-request">60</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="halign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="visible">true</property>
+ <property name="width-request">600</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Other Projects</property>
+ <property name="visible">true</property>
+ <property name="xalign">0.0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="other_projects_list_box">
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkHeaderBar" id="titlebar">
+ <property name="show-close-button">true</property>
+ <property name="visible">true</property>
+ <property name="title" translatable="yes">Select a Project</property>
+ <child>
+ <object class="GtkToggleButton" id="select_object_button">
+ <property name="focus-on-click">false</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">true</property>
+ <property name="icon-name">object-select-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="search_button">
+ <property name="focus-on-click">false</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">true</property>
+ <property name="icon-name">edit-find-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/data/ui/ide-workbench-header-bar.ui b/data/ui/ide-workbench-header-bar.ui
new file mode 100644
index 0000000..5e050f5
--- /dev/null
+++ b/data/ui/ide-workbench-header-bar.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.17 -->
+ <template class="IdeWorkbenchHeaderBar" parent="GtkHeaderBar">
+ <property name="show-close-button">true</property>
+ <child>
+ <object class="GtkMenuButton" id="menu_button">
+ <property name="visible">true</property>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">open-menu-symbolic</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/ide-workbench.ui b/data/ui/ide-workbench.ui
new file mode 100644
index 0000000..675cfbf
--- /dev/null
+++ b/data/ui/ide-workbench.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.17 -->
+ <template class="IdeWorkbench" parent="GtkApplicationWindow">
+ <child type="titlebar">
+ <object class="GtkStack" id="header_bar_stack">
+ <property name="visible">true</property>
+ <property name="transition-type">crossfade</property>
+ <property name="transition-duration">333</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="homogeneous">false</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkStackSwitcher" id="perspectives_stack_switcher">
+ <property name="orientation">vertical</property>
+ <property name="stack">perspectives_stack</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="perspectives_stack">
+ <property name="homogeneous">false</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 881f5ad..06d7d93 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -17,6 +17,10 @@ libide_1_0_la_public_sources = \
git/ide-git-remote-callbacks.h \
git/ide-git-vcs.c \
git/ide-git-vcs.h \
+ ide-application.c \
+ ide-application.h \
+ ide-application-addin.c \
+ ide-application-addin.h \
ide-back-forward-item.c \
ide-back-forward-item.h \
ide-back-forward-list.c \
@@ -86,9 +90,17 @@ libide_1_0_la_public_sources = \
ide-indent-style.h \
ide-indenter.c \
ide-indenter.h \
+ ide-layout-manager.c \
+ ide-layout-manager.h \
ide-log.c \
ide-log.h \
ide-macros.h \
+ ide-perspective.c \
+ ide-perspective.h \
+ ide-preferences.c \
+ ide-preferences.h \
+ ide-preferences-addin.c \
+ ide-preferences-addin.h \
ide-object.c \
ide-object.h \
ide-pattern-spec.c \
@@ -172,10 +184,18 @@ libide_1_0_la_public_sources = \
ide-unsaved-file.h \
ide-unsaved-files.c \
ide-unsaved-files.h \
+ ide-view.c \
+ ide-view.h \
ide-vcs-uri.c \
ide-vcs-uri.h \
ide-vcs.c \
ide-vcs.h \
+ ide-workbench.c \
+ ide-workbench.h \
+ ide-workbench-addin.c \
+ ide-workbench-addin.h \
+ ide-workbench-header-bar.c \
+ ide-workbench-header-bar.h \
ide-worker.c \
ide-worker.h \
ide.c \
@@ -197,18 +217,27 @@ libide_1_0_la_SOURCES = \
gsettings/ide-gsettings-file-settings.h \
gsettings/ide-language-defaults.c \
gsettings/ide-language-defaults.h \
+ ide-application-actions.c \
+ ide-application-actions.h \
+ ide-application-private.h \
ide-async-helper.c \
ide-async-helper.h \
ide-battery-monitor.c \
ide-battery-monitor.h \
+ ide-css-provider.c \
+ ide-css-provider.h \
ide-debug.h \
ide-extension-util.c \
ide-extension-util.h \
+ ide-greeter-perspective.c \
+ ide-greeter-perspective.h \
ide-internal.h \
ide-line-change-gutter-renderer.c \
ide-line-change-gutter-renderer.h \
ide-line-diagnostics-gutter-renderer.c \
ide-line-diagnostics-gutter-renderer.h \
+ ide-keybindings.c \
+ ide-keybindings.h \
ide-ref-ptr.c \
ide-ref-ptr.h \
ide-search-reducer.c \
@@ -257,7 +286,10 @@ libide_1_0_la_SOURCES = \
libide_1_0_la_includes = \
$(DEBUG_CFLAGS) \
- -DLIBDIR="\"$(libdir)\"" \
+ -DPACKAGE_DATADIR="\"${datadir}\"" \
+ -DPACKAGE_LOCALE_DIR=\""${datadir}/locale"\" \
+ -DPACKAGE_LIBDIR=\""${libdir}"\" \
+ -DBUILDDIR=\""${abs_top_builddir}"\" \
-I$(top_builddir)/libide \
-I$(top_srcdir)/contrib/egg \
-I$(top_srcdir)/contrib/libeditorconfig \
diff --git a/libide/ide-application-actions.c b/libide/ide-application-actions.c
new file mode 100644
index 0000000..0bd0970
--- /dev/null
+++ b/libide/ide-application-actions.c
@@ -0,0 +1,317 @@
+/* ide-application-actions.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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-application-actions"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "ide-application.h"
+#include "ide-application-actions.h"
+#include "ide-application-credits.h"
+#include "ide-application-private.h"
+#include "ide-debug.h"
+#include "ide-workbench.h"
+
+static void
+ide_application_actions_preferences (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+#if 0
+ IdeApplication *self = user_data;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ if (self->preferences_window == NULL)
+ {
+ IdePreferencesWindow *window;
+
+ window = g_object_new (IDE_TYPE_PREFERENCES_WINDOW,
+ "type-hint", GDK_WINDOW_TYPE_HINT_DIALOG,
+ "window-position", GTK_WIN_POS_CENTER,
+ NULL);
+ ide_set_weak_pointer (&self->preferences_window, window);
+ }
+
+ gtk_window_present (GTK_WINDOW (self->preferences_window));
+
+ IDE_EXIT;
+#endif
+}
+
+#if 0
+static void
+ide_application_actions_support (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+ GtkWidget *dialog;
+ gchar *text = NULL;
+ GList *windows;
+ GError *error = NULL;
+ gchar *str = NULL;
+ gchar *log_path = NULL;
+ gchar *name = NULL;
+
+ name = g_strdup_printf ("gnome-builder-%u.log", (int)getpid ());
+ log_path = g_build_filename (g_get_home_dir (), name, NULL);
+ g_free (name);
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ str = ide_get_support_log ();
+
+ if (!g_file_set_contents (log_path, str, -1, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ goto cleanup;
+ }
+
+ text = g_strdup_printf (_("The support log file has been written to '%s'. "
+ "Please provide this file as an attachment on "
+ "your bug report or support request."),
+ log_path);
+
+ g_message ("%s", text);
+
+ dialog = gtk_message_dialog_new (windows ? windows->data : NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "%s", text);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (dialog));
+
+cleanup:
+ g_free (text);
+ g_clear_error (&error);
+ g_free (str);
+ g_free (log_path);
+}
+#endif
+
+static void
+ide_application_actions_quit (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ g_application_quit (G_APPLICATION (self));
+
+ IDE_EXIT;
+}
+
+static void
+ide_application_actions_about (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+ GtkDialog *dialog;
+ GtkWindow *parent = NULL;
+ GList *iter;
+ GList *windows;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ for (iter = windows; iter; iter = iter->next)
+ {
+ if (IDE_IS_WORKBENCH (iter->data))
+ {
+ parent = iter->data;
+ break;
+ }
+ }
+
+ dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+ "artists", ide_application_credits_artists,
+ "authors", ide_application_credits_authors,
+ "comments", _("An IDE for GNOME"),
+ "documenters", ide_application_credits_documenters,
+ "license-type", GTK_LICENSE_GPL_3_0,
+ "logo-icon-name", "builder",
+ "modal", FALSE,
+ "program-name", _("GNOME Builder"),
+ "transient-for", parent,
+ "translator-credits", _("translator-credits"),
+ "version", PACKAGE_VERSION,
+ "website", "https://wiki.gnome.org/Apps/Builder",
+ "website-label", _("Learn more about GNOME Builder"),
+ NULL);
+ gtk_about_dialog_add_credit_section (GTK_ABOUT_DIALOG (dialog),
+ _("Funded By"),
+ ide_application_credits_funders);
+
+ g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+#if 0
+static void
+ide_application_actions_open_project (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ ide_application_show_projects_window (self);
+}
+
+static void
+ide_application_actions_open_project_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeApplication *self = (IdeApplication *)object;
+ g_autoptr(IdeNewProjectDialog) window = user_data;
+ g_autoptr(GError) error = NULL;
+ GtkWindow *transient_for;
+
+ g_assert (IDE_IS_NEW_PROJECT_DIALOG (window));
+
+ if (!ide_application_open_project_finish (self, result, &error))
+ {
+ /* todo: warning message */
+ g_warning ("%s", error->message);
+ }
+
+ transient_for = gtk_window_get_transient_for (GTK_WINDOW (window));
+
+ if (IDE_IS_GREETER_WINDOW (transient_for))
+ g_object_ref (transient_for);
+ else
+ transient_for = NULL;
+
+ gtk_widget_destroy (GTK_WIDGET (window));
+
+ if (transient_for != NULL)
+ {
+ gtk_widget_destroy (GTK_WIDGET (transient_for));
+ g_object_unref (transient_for);
+ }
+}
+
+static void
+ide_application_actions__window_open_project (IdeApplication *self,
+ GFile *project_file,
+ IdeNewProjectDialog *window)
+{
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (G_IS_FILE (project_file));
+ g_assert (IDE_IS_NEW_PROJECT_DIALOG (window));
+
+ ide_application_open_project_async (self, project_file, NULL, NULL,
+ ide_application_actions_open_project_cb,
+ g_object_ref (window));
+}
+
+static void
+ide_application_actions_new_project (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+ GtkWindow *transient_for = NULL;
+ GtkWindow *window;
+ GList *windows;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ for (windows = gtk_window_group_list_windows (self->greeter_group);
+ windows;
+ windows = windows->next)
+ {
+ if (IDE_IS_NEW_PROJECT_DIALOG (windows->data))
+ {
+ gtk_window_present (windows->data);
+ goto cleanup;
+ }
+ else if (IDE_IS_GREETER_WINDOW (windows->data))
+ {
+ transient_for = windows->data;
+ }
+ }
+
+ window = g_object_new (IDE_TYPE_NEW_PROJECT_DIALOG,
+ "type-hint", GDK_WINDOW_TYPE_HINT_DIALOG,
+ "transient-for", transient_for,
+ "window-position", transient_for ? GTK_WIN_POS_CENTER_ON_PARENT
+ : GTK_WIN_POS_CENTER,
+ NULL);
+
+ g_signal_connect_object (window,
+ "open-project",
+ G_CALLBACK (ide_application_actions__window_open_project),
+ self,
+ G_CONNECT_SWAPPED);
+
+ gtk_window_group_add_window (self->greeter_group, GTK_WINDOW (window));
+ gtk_window_present (window);
+
+cleanup:
+ g_list_free (windows);
+}
+
+static void
+ide_application_actions_shortcuts (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ IdeShortcutsWindow *window;
+
+ window = g_object_new (IDE_TYPE_SHORTCUTS_WINDOW,
+ "window-position", GTK_WIN_POS_CENTER,
+ "default-width", 800,
+ "default-height", 600,
+ NULL);
+
+ gtk_window_present (GTK_WINDOW (window));
+}
+#endif
+
+static const GActionEntry IdeApplicationActions[] = {
+ { "about", ide_application_actions_about },
+ //{ "open-project", ide_application_actions_open_project },
+ //{ "new-project", ide_application_actions_new_project },
+ { "preferences", ide_application_actions_preferences },
+ { "quit", ide_application_actions_quit },
+ //{ "shortcuts", ide_application_actions_shortcuts },
+ //{ "support", ide_application_actions_support },
+};
+
+void
+ide_application_actions_init (IdeApplication *self)
+{
+ g_action_map_add_action_entries (G_ACTION_MAP (self), IdeApplicationActions,
+ G_N_ELEMENTS (IdeApplicationActions), self);
+}
diff --git a/src/greeter/gb-greeter-pill-box.h b/libide/ide-application-actions.h
similarity index 56%
copy from src/greeter/gb-greeter-pill-box.h
copy to libide/ide-application-actions.h
index 394a333..e4cb961 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/libide/ide-application-actions.h
@@ -1,4 +1,4 @@
-/* gb-greeter-pill-box.h
+/* ide-application-actions.h
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -16,22 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef IDE_APPLICATION_ACTIONS_H
+#define IDE_APPLICATION_ACTIONS_H
-#include <gtk/gtk.h>
+#include "ide-application.h"
G_BEGIN_DECLS
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
-
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
-
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+void ide_application_actions_init (IdeApplication *self);
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* IDE_APPLICATION_ACTIONS_H */
diff --git a/libide/ide-application-addin.c b/libide/ide-application-addin.c
new file mode 100644
index 0000000..d03d5f5
--- /dev/null
+++ b/libide/ide-application-addin.c
@@ -0,0 +1,81 @@
+/* ide-application-addin.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-application-addin.h"
+
+G_DEFINE_INTERFACE (IdeApplicationAddin, ide_application_addin, G_TYPE_OBJECT)
+
+static void
+ide_application_addin_real_load (IdeApplicationAddin *self,
+ IdeApplication *application)
+{
+}
+
+static void
+ide_application_addin_real_unload (IdeApplicationAddin *self,
+ IdeApplication *application)
+{
+}
+
+static void
+ide_application_addin_default_init (IdeApplicationAddinInterface *iface)
+{
+ iface->load = ide_application_addin_real_load;
+ iface->unload = ide_application_addin_real_unload;
+}
+
+/**
+ * ide_application_addin_load:
+ * @self: An #IdeApplicationAddin.
+ * @application: An #IdeApplication.
+ *
+ * This interface method is called when the application is started or
+ * the plugin has just been activated.
+ *
+ * Use this to setup code in your plugin that needs to be loaded once
+ * per application process.
+ */
+void
+ide_application_addin_load (IdeApplicationAddin *self,
+ IdeApplication *application)
+{
+ g_return_if_fail (IDE_IS_APPLICATION_ADDIN (self));
+ g_return_if_fail (IDE_IS_APPLICATION (application));
+
+ IDE_APPLICATION_ADDIN_GET_IFACE (self)->load (self, application);
+}
+
+/**
+ * ide_application_addin_unload:
+ * @self: An #IdeApplicationAddin.
+ * @application: An #IdeApplication.
+ *
+ * This inteface method is called when the application is shutting down
+ * or the plugin has been unloaded.
+ *
+ * Use this function to cleanup after anything setup in ide_application_addin_load().
+ */
+void
+ide_application_addin_unload (IdeApplicationAddin *self,
+ IdeApplication *application)
+{
+ g_return_if_fail (IDE_IS_APPLICATION_ADDIN (self));
+ g_return_if_fail (IDE_IS_APPLICATION (application));
+
+ IDE_APPLICATION_ADDIN_GET_IFACE (self)->unload (self, application);
+}
diff --git a/libide/ide-application-addin.h b/libide/ide-application-addin.h
new file mode 100644
index 0000000..8ecde9b
--- /dev/null
+++ b/libide/ide-application-addin.h
@@ -0,0 +1,47 @@
+/* ide-application-addin.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_APPLICATION_ADDIN_H
+#define IDE_APPLICATION_ADDIN_H
+
+#include "ide-application.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_APPLICATION_ADDIN (ide_application_addin_get_type())
+
+G_DECLARE_INTERFACE (IdeApplicationAddin, ide_application_addin, IDE, APPLICATION_ADDIN, GObject)
+
+struct _IdeApplicationAddinInterface
+{
+ GTypeInterface parent_interface;
+
+ void (*load) (IdeApplicationAddin *self,
+ IdeApplication *application);
+ void (*unload) (IdeApplicationAddin *self,
+ IdeApplication *application);
+};
+
+void ide_application_addin_load (IdeApplicationAddin *self,
+ IdeApplication *application);
+void ide_application_addin_unload (IdeApplicationAddin *self,
+ IdeApplication *application);
+
+G_END_DECLS
+
+#endif /* IDE_APPLICATION_ADDIN_H */
diff --git a/libide/ide-application-credits.h b/libide/ide-application-credits.h
new file mode 100644
index 0000000..abe7f92
--- /dev/null
+++ b/libide/ide-application-credits.h
@@ -0,0 +1,554 @@
+/* ide-application-credits.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser 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 IDE_APPLICATION_CREDITS_H
+#define IDE_APPLICATION_CREDITS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+static const gchar *ide_application_credits_artists[] = {
+ "Allan Day",
+ "Hylke Bons",
+ "Jakub Steiner",
+ NULL
+};
+
+static const gchar *ide_application_credits_authors[] = {
+ "Alexander Larsson",
+ "Alexandre Franke",
+ "Andika Triwidada",
+ "Andreas Henriksson",
+ "Antoine Jacoutot",
+ "Aurimas Černius",
+ "Baurzhan Muftakhidinov",
+ "Ben Iofel",
+ "Bernd Homuth",
+ "burningTyger",
+ "Carlos Garnacho",
+ "Carlos Soriano",
+ "Changwoo Ryu",
+ "Chao-Hsiung Liao",
+ "Cheng-Chia Tseng",
+ "Christian Hergert",
+ "Christian Kirbach",
+ "Cosimo Cecchi",
+ "Damien Lespiau",
+ "Daniel Korostil",
+ "Daniel Mustieles",
+ "David King",
+ "Dimitris Zenios",
+ "Dušan Kazik",
+ "Ekaterina Gerasimova",
+ "Elad Alfassa",
+ "Erick Pérez Castellanos",
+ "Fabiano Fidêncio",
+ "Florian Bäuerle",
+ "Florian Müllner",
+ "Fran Dieguez",
+ "Gabor Kelemen",
+ "Gábor Kelemen",
+ "Garrett Regier",
+ "Giovanni Campagna",
+ "Hashem Nasarat",
+ "Hylke Bons",
+ "Ian Hernandez",
+ "Ignacio Casal Quinteiro",
+ "Igor Gnatenko",
+ "Jakub Steiner",
+ "Jasper St. Pierre",
+ "Jonathon Jongsma",
+ "Jordi Mas",
+ "Kalev Lember",
+ "Kjartan Maraas",
+ "Kristjan SCHMIDT",
+ "Lars Uebernickel",
+ "Lionel Landwerlin",
+ "Marek Černocký",
+ "Matej Urbančič",
+ "Mathieu Bridon",
+ "Matthias Clasen",
+ "Megh Parikh",
+ "Michael Catanzaro",
+ "Mohan R",
+ "Muhammet Kara",
+ "Мирослав Николић",
+ "Paolo Borelli",
+ "Patrick Griffis",
+ "Pedro Albuquerque",
+ "Pete Travis",
+ "Piotr Drąg",
+ "Ray Strode",
+ "Roberto Majadas",
+ "Samir Ribic",
+ "Sébastien Lafargue",
+ "Timm Bäder",
+ "TingPing",
+ "Ting-Wei Lan",
+ "Tobias Schönberg",
+ "Tom Tryfonidis",
+ "Trinh Anh Ngoc",
+ "Wolf Vollprecht",
+ "Yannick Inizan",
+ "Yosef Or Boczko",
+ "zilla hmt im",
+ NULL
+};
+
+static const gchar *ide_application_credits_documenters[] = {
+ "Christian Hergert",
+ NULL
+};
+
+static const gchar *ide_application_credits_funders[] = {
+ "曾政嘉",
+ "Aaron Hergert",
+ "Abdul Kadri Gündoğdu",
+ "Abimael Martinez Carrete",
+ "Adam grunden",
+ "Adrian Bradshaw",
+ "Adrian Rocha",
+ "Adrià Arrufat",
+ "Alaska Subedi",
+ "Albert Murciego Rico",
+ "Alessandro Bono",
+ "Alexander B Libby",
+ "Alexander Gleason",
+ "Alexander Khatsayuk",
+ "Alexander Larsson",
+ "Alexander Murray",
+ "Alexander Murray",
+ "Alexandre Amoedo",
+ "Alexandre Franke",
+ "Alexandros Diavatis",
+ "Alfonso de Cala Bravo",
+ "Alfred Santacatalina Gea",
+ "Ambrose Andrews",
+ "Andreas Nilsson",
+ "Andrew Stiegmann",
+ "Andrew Walton",
+ "Anthony Taranto",
+ "Anton Shafarenko",
+ "Aram J Agajanian",
+ "Arne Hoch",
+ "Arturo Buentello G",
+ "Arun Raghavan",
+ "Ashley Sommer",
+ "Aurélien Naldi",
+ "B. Mille-Mathias",
+ "Baldessari Michele",
+ "Bastian Ilsø Hougaard",
+ "Bastien Nocera",
+ "Bastien Nocera",
+ "Benjamin Grimm-Lebsanft",
+ "Bernd Homuth",
+ "Bill Roth",
+ "Brad Taylor",
+ "Brendan Long",
+ "Brijesh Kartha",
+ "Bruce Cowan",
+ "Bruce M Franklin",
+ "Búza Géza",
+ "Canek Pelaez Valdes",
+ "Carlos Soriano Sanchez",
+ "Casey E Megginson",
+ "Cedric Briner",
+ "Cees Meijer",
+ "Centricular Ltd",
+ "Chema Casanova",
+ "Cheng-Chia Tseng",
+ "Chris Bagwell",
+ "Chris Kühl",
+ "Chris Tonkinson",
+ "Christian Hergert",
+ "Christian Lange",
+ "Christopher Brian Sherlock",
+ "Christopher Horton",
+ "Christopher Kim",
+ "Christopher William Bell",
+ "Chun-Sheng Wu",
+ "Cody Russell",
+ "Cosimo Cecchi",
+ "Craig A Cabrey",
+ "Dag Robøle",
+ "Daiki Ueno",
+ "Damián Nohales",
+ "Daniel Buch",
+ "Daniel Dui",
+ "Daniel Espinosa Ortiz",
+ "Daniel Menchaca",
+ "Daniel Nemec",
+ "Daniel Pfeifer",
+ "Daniel Vazquez Rivera",
+ "Danilo Gropelo",
+ "Danylo Korostil",
+ "Debarshi Ray",
+ "Demetris Lambrou",
+ "Dennis Schulmeister",
+ "Denver Gingerich",
+ "Dolgoff ",
+ "Eduardo Silva",
+ "Eitan Isaacson",
+ "Elad Alfassa",
+ "Ellis Kenyo",
+ "Emanuele Aina",
+ "Emanuele Gissi",
+ "Emmanuele Bassi",
+ "Enrique Ocaña González",
+ "Eric Streit",
+ "Eric T Miller",
+ "Erik Helin",
+ "Ernest hershey",
+ "Erwan Bousse",
+ "Erwan Georget",
+ "F. Kooman",
+ "Fabian Alexander Wilms",
+ "Fabien Cortina",
+ "Fabio Valentini",
+ "Faizan Qazi",
+ "Faron S Anslow",
+ "Fasiello Nicomede",
+ "Federico Mena Quintero",
+ "Felix Schröter",
+ "Filipe Santos",
+ "Florian Bäuerle",
+ "Florian Over",
+ "Florian Schweikert",
+ "Florin Florica",
+ "Frank Dietrich",
+ "Frank Hansen",
+ "Fränz Ney",
+ "Fredrik Schaller",
+ "G A Foster",
+ "Gabriel Rauter",
+ "Garrett LeSage",
+ "Georges Seguin",
+ "Georges-Mickael Seguin",
+ "Gianluigi Calcaterra",
+ "Gil Forcada Codinachs",
+ "Giovanni Forte",
+ "Go Min YounG",
+ "Gonzalo Paniagua Javier",
+ "Gordon Martin",
+ "Guilherme Rodrigues",
+ "Guillaume Beaudin",
+ "Guillaume Hain",
+ "Guillaume Quintard",
+ "Gustavo Arejano",
+ "Gustavo N Silva",
+ "Hain Guillaume",
+ "Hannes Ovrén",
+ "Harald Hoyer",
+ "Havoc Pennington",
+ "Hendrik Richter",
+ "Henrique Almeida",
+ "Henry Finucane",
+ "I Martin Rodriguez",
+ "Ian Bolf",
+ "Ian McKellar",
+ "Ignacio Casal Quinteiro",
+ "Igor Gnatenko",
+ "Ilya Novosyolov",
+ "Ioram Gordadze",
+ "Ivan Nezhdanov",
+ "J. Pereira Rocha",
+ "J.A.J. Vermeulen",
+ "Jack Jennings",
+ "James M Cape",
+ "James Mason",
+ "James",
+ "Jan Dudulski",
+ "Jan-Christoph Borchardt",
+ "Jason Carey",
+ "Jason D Levine",
+ "Jason R Anderson",
+ "Jason Scurtu",
+ "Javier Jardón",
+ "Javier Monteagudo",
+ "Jean-François Fortin Tam",
+ "Jeff Waugh",
+ "Jeffrey Dorrycott",
+ "Jesse van den Kieboom",
+ "Jim Campbell",
+ "Jiri Eischmann",
+ "Joakim Söderlund",
+ "Joaquin Mendez",
+ "Johan Dahlin",
+ "John Gary Billings",
+ "John M Carr",
+ "John Palmieri",
+ "Jonathan Lane",
+ "Jonathan Lestrelin",
+ "Jonathan Zuñiga Juarez",
+ "Jonathon Jongsma",
+ "Jorge Rodriguez Flores Esp",
+ "Joseph Hain",
+ "Juan Jose Marin Martinez",
+ "Jugoslav Gacas",
+ "Julien Girardin",
+ "Jussi Henrik Kukkonen",
+ "Justin D Kruger",
+ "Justin Roth",
+ "Justyn Butler",
+ "Katrin Leinweber",
+ "Keith Tokash",
+ "Kenneth Nielsen",
+ "Khalid Eldehairy",
+ "Kris Thomsen",
+ "Lapo Calamandrei",
+ "Lars Uebernickel",
+ "Laurent Mouillart",
+ "Le Guevel Gwendal",
+ "Leif Gruenwoldt",
+ "Lionel Landwerlin",
+ "Logan VanCuren",
+ "Lucas Almeida Rocha",
+ "Lukasz Ochoda",
+ "Luke Gaudreau",
+ "M C V Crouch",
+ "M. Aurélien Couderc",
+ "Mac Baker",
+ "Maciej M Piechotka",
+ "Magnun Leno Silva",
+ "Marc Andre Lureau",
+ "Marc Thomas",
+ "Marcio Sousa Rocha",
+ "Marco Barisione",
+ "Marcus Husar",
+ "Marcus Lundblad",
+ "Marek Suchánek",
+ "Marina Zhurakhinskaya",
+ "Mario Sanchez-Prada",
+ "Marius Heidenreich",
+ "Marius Mather",
+ "Markus Berg",
+ "Mart Roosmaa",
+ "Martin A Stembel",
+ "Martin Andersson",
+ "Martin Blanchard",
+ "Martin C Foster",
+ "Martin Unzner",
+ "Matej Smid",
+ "Mathieu Bridon",
+ "Matthew Nicholson",
+ "Mattias Bengtsson",
+ "Max Whittingham",
+ "Maxim Yaskevich",
+ "Michael Catanzaro",
+ "Michael Grundy",
+ "Michael Hill",
+ "Michael Ivanov",
+ "Michael Kuhn",
+ "Michael Mansell",
+ "Michael S DePaulo",
+ "Michael Scofield",
+ "Michel Alexandre Salim",
+ "Miguel e dos Santos",
+ "Mikel Olasagasti Uranga",
+ "Mikhail Feshchenko",
+ "Molly Shelestak",
+ "Nasser Alshammari",
+ "Nathan Samson",
+ "Neil Stalker",
+ "Neils Nesse",
+ "Nelson Jesus Benitez Leon",
+ "Nicholas E Richards",
+ "Nicholas George",
+ "Nick Melnick",
+ "Niclas Moeslund Overby",
+ "Nicola Mazbar",
+ "Nicolas Jeker",
+ "Niklas Rosenqvist",
+ "Nikola Trifunovic",
+ "Nil Gradisnik",
+ "Nirbheek Chauhan",
+ "Olav Vitters",
+ "Oliver Propst",
+ "Olivier Crete",
+ "Ondřej Holý",
+ "Ondřej Tůma",
+ "Owen Taylor",
+ "P Tunnell Wilson",
+ "P.F. Mulder",
+ "Pacaud Emmanuel",
+ "Pakkanen Jussi T",
+ "Paolo Borelli",
+ "Pascal Garber",
+ "Patrick Griffis",
+ "Patrick Wspanialy",
+ "Patrik Nilsson",
+ "Patrizio Bruno",
+ "Paul R Martin",
+ "Pedro J Ayala Gomariz",
+ "Perry L Peters",
+ "Peter Baumgarten",
+ "Peter Cornelis",
+ "Peter J Shinners",
+ "Peter Weber",
+ "Philip Corbett",
+ "Philip F Chimento",
+ "Philip J Freeman",
+ "Philip Whitfield",
+ "Piotr Zurek",
+ "R A McQueen",
+ "R A McQueen",
+ "RM van Schouwen",
+ "Radosław Sierbiński",
+ "Ray Strode",
+ "Remco Kranenburg",
+ "Remi Grolleau",
+ "Rickard Johansson",
+ "Robert Carr",
+ "Robert Taylor",
+ "Roberto Clapis",
+ "Rodolphe PP",
+ "Rory MacQueen",
+ "Rosanna Blandford",
+ "Ross N Gardiner",
+ "Rouchon Jean-Noel",
+ "Rui Paulo Barreira",
+ "Russell Cox",
+ "Ryan Hartlage",
+ "Ryan Lerch",
+ "Rémi Lauzier",
+ "S Axon",
+ "Sajid Badi-uz-zaman",
+ "Samuel B Thursfield",
+ "Samuel Gyger",
+ "Sasan Namiranian",
+ "Saul Vargas Sandoval",
+ "Sebastian Droege",
+ "Shapor Naghibzadeh",
+ "Shawn Ferris",
+ "Shlomo Choina",
+ "Shuji Narazaki",
+ "Simon Roesch",
+ "Sriram Ramkrishna",
+ "Stefi T Petit",
+ "Stephany Wilkes",
+ "Stephen Genusa",
+ "Stephen Shaw",
+ "Steve Z McCauley",
+ "Steven J Herber",
+ "Steven W Brown",
+ "Steven Wills",
+ "Stewart Webb",
+ "Stuart Ellis",
+ "Stéphane Démurget",
+ "Stéphane Maniaci",
+ "Søren Hauberg",
+ "Tadej Janež",
+ "Ted Hennicke",
+ "Thibault Saunier",
+ "Thomas Andersen",
+ "Thomas Maffia",
+ "Thomas McDonald",
+ "Tom Erik Gundersen",
+ "Tomas Peterka",
+ "Tommi Tauriainen",
+ "Tomáš Krchňák",
+ "Tomáš Popela",
+ "Toni Willberg",
+ "Torsten Scholak",
+ "Travis Hartwell",
+ "Tyler J. Brock",
+ "Uwe Hametner",
+ "Vadzim Rutkouski",
+ "Valter Schütz",
+ "WP MANLEY",
+ "WP Manley",
+ "Wee Weea",
+ "Wesley Wiser",
+ "Will Binns-Smith",
+ "William Hoffmann",
+ "William J Thompson",
+ "William J Thompson",
+ "William Jon McCann",
+ "William R Lachance",
+ "Z Jedrzejewski-Szmek",
+ "adam820",
+ "arclnx",
+ "aurelien.busi",
+ "carwyn",
+ "d.westerik",
+ "daniel.fontaine",
+ "david odenwald",
+ "dchristidis",
+ "demirtas burakk",
+ "eik.w1911",
+ "eliasdorneles",
+ "elken.tdos",
+ "fafatheone",
+ "florian.muellner",
+ "gerald.b.nunn",
+ "gyger",
+ "ich",
+ "ideasman42",
+ "jimmac",
+ "jnoel",
+ "joannis.orlandos",
+ "joaquin8mendez",
+ "joel",
+ "juanjomarin96",
+ "kamilprusko",
+ "kenneth",
+ "kesmarag",
+ "kevin",
+ "kidoz",
+ "kuba",
+ "lovenemesis",
+ "luke.a.morton",
+ "madstitz",
+ "marc.chocolat",
+ "mariospr",
+ "markpariente",
+ "matthias.clasen",
+ "maxlupo",
+ "mcatanzaro",
+ "muflone",
+ "nils.werner",
+ "otaylor",
+ "pedroclg",
+ "peterldev94",
+ "pizzamartijn",
+ "pseus7+indiegogo",
+ "public228",
+ "ray strode",
+ "ross",
+ "sandquist",
+ "scottm2031",
+ "sebastien lafargue",
+ "sebastien.wilmet",
+ "sfs",
+ "slyon",
+ "swalf",
+ "sylvain.pasche",
+ "tglman",
+ "theo",
+ "tommaso.visconti",
+ "vamega",
+ "verduler",
+ "vperetokin",
+ "w.vollprecht",
+ NULL
+};
+
+G_END_DECLS
+
+#endif /* IDE_APPLICATION_CREDITS_H */
diff --git a/src/greeter/gb-greeter-pill-box.h b/libide/ide-application-private.h
similarity index 51%
copy from src/greeter/gb-greeter-pill-box.h
copy to libide/ide-application-private.h
index 394a333..cf3856f 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/libide/ide-application-private.h
@@ -1,4 +1,4 @@
-/* gb-greeter-pill-box.h
+/* gb-application-private.h
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -16,22 +16,35 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef IDE_APPLICATION_PRIVATE_H
+#define IDE_APPLICATION_PRIVATE_H
#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <libpeas/peas.h>
-G_BEGIN_DECLS
-
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
+#include "ide-keybindings.h"
+#include "ide-recent-projects.h"
+#include "ide-worker-manager.h"
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
+G_BEGIN_DECLS
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+struct _IdeApplication
+{
+ GtkApplication parent_instance;
+
+ gchar *argv0;
+ gchar *dbus_address;
+ PeasExtensionSet *extensions;
+ GtkWindowGroup *greeter_group;
+ IdeKeybindings *keybindings;
+ GtkWindow *preferences_window;
+ IdeRecentProjects *recent_projects;
+ GDateTime *startup_time;
+ gchar *type;
+ IdeWorkerManager *worker_manager;
+};
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* GB_APPLICATION_PRIVATE_H */
diff --git a/libide/ide-application.c b/libide/ide-application.c
new file mode 100644
index 0000000..faab43a
--- /dev/null
+++ b/libide/ide-application.c
@@ -0,0 +1,1002 @@
+/* ide-application.c
+ *
+ * Copyright (C) 2014 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-application"
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef __linux
+# include <sys/prctl.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <gtksourceview/gtksource.h>
+#include <libgit2-glib/ggit.h>
+
+#include "ide-application.h"
+#include "ide-application-actions.h"
+#include "ide-application-addin.h"
+#include "ide-application-private.h"
+#include "ide-css-provider.h"
+#include "ide-debug.h"
+#include "ide-internal.h"
+#include "ide-file.h"
+#include "ide-log.h"
+#include "ide-macros.h"
+#include "ide-resources.h"
+#include "ide-vcs.h"
+#include "ide-workbench.h"
+#include "ide-worker.h"
+
+#include "modeline-parser.h"
+
+G_DEFINE_TYPE (IdeApplication, ide_application, GTK_TYPE_APPLICATION)
+
+static gboolean
+ide_application_can_load_plugin (IdeApplication *self,
+ PeasPluginInfo *plugin_info)
+{
+ const gchar *plugin_name;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (plugin_info != NULL);
+
+ /* Currently we only allow in-tree plugins */
+ if (!peas_plugin_info_is_builtin (plugin_info))
+ return FALSE;
+
+ plugin_name = peas_plugin_info_get_module_name (plugin_info);
+ if (ide_str_equal0 (plugin_name, self->type))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+ide_application_load_plugins (IdeApplication *self)
+{
+ PeasEngine *engine = peas_engine_get_default ();
+ const GList *list;
+
+ peas_engine_enable_loader (engine, "python3");
+
+ if (g_getenv ("BUiLDER_IN_TREE_PLUGINS") != NULL)
+ {
+ GDir *dir;
+
+ g_irepository_require_private (g_irepository_get_default (),
+ BUILDDIR"/libide",
+ "Ide", "1.0", 0, NULL);
+
+ if ((dir = g_dir_open (BUILDDIR"/plugins", 0, NULL)))
+ {
+ const gchar *name;
+
+ while ((name = g_dir_read_name (dir)))
+ {
+ gchar *path;
+
+ path = g_build_filename (BUILDDIR, "plugins", name, NULL);
+ peas_engine_prepend_search_path (engine, path, path);
+ g_free (path);
+ }
+
+ g_dir_close (dir);
+ }
+ }
+ else
+ {
+ peas_engine_prepend_search_path (engine,
+ PACKAGE_LIBDIR"/gnome-builder/plugins",
+ PACKAGE_DATADIR"/gnome-builder/plugins");
+ }
+
+ list = peas_engine_get_plugin_list (engine);
+
+ for (; list; list = list->next)
+ {
+ if (ide_application_can_load_plugin (self, list->data))
+ peas_engine_load_plugin (engine, list->data);
+ }
+}
+
+static gboolean
+ide_application_is_worker (IdeApplication *self)
+{
+ g_assert (IDE_IS_APPLICATION (self));
+
+ return (self->type != NULL) && (self->dbus_address != NULL);
+}
+
+static void
+ide_application_load_worker (IdeApplication *self)
+{
+ g_autoptr(GDBusConnection) connection = NULL;
+ PeasEngine *engine;
+ PeasPluginInfo *plugin_info;
+ GError *error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (ide_application_is_worker (self));
+
+#ifdef __linux
+ /* Ensure we are killed with our parent */
+ prctl (PR_SET_PDEATHSIG, 15);
+#endif
+
+ IDE_TRACE_MSG ("Connecting to %s", self->dbus_address);
+
+ connection = g_dbus_connection_new_for_address_sync (self->dbus_address,
+ (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING),
+ NULL, NULL, &error);
+
+ if (error != NULL)
+ {
+ g_error ("DBus failure: %s", error->message);
+ g_clear_error (&error);
+ IDE_EXIT;
+ }
+
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+
+ engine = peas_engine_get_default ();
+ plugin_info = peas_engine_get_plugin_info (engine, self->type);
+
+ if ((plugin_info != NULL) && peas_plugin_info_is_loaded (plugin_info))
+ {
+ PeasExtension *exten;
+
+ exten = peas_engine_create_extension (engine, plugin_info, IDE_TYPE_WORKER, NULL);
+
+ if (exten != NULL)
+ {
+ ide_worker_register_service (IDE_WORKER (exten), connection);
+ IDE_GOTO (success);
+ }
+ }
+
+ g_error ("Failed to create \"%s\" worker.", self->type);
+
+ IDE_EXIT;
+
+success:
+ g_application_hold (G_APPLICATION (self));
+ g_dbus_connection_start_message_processing (connection);
+
+ IDE_EXIT;
+}
+
+static void
+ide_application_setup_search_paths (void)
+{
+ GtkSourceStyleSchemeManager *style_scheme_manager;
+ static gboolean initialized;
+
+ if (initialized)
+ return;
+
+ style_scheme_manager = gtk_source_style_scheme_manager_get_default ();
+ gtk_source_style_scheme_manager_append_search_path (style_scheme_manager,
+ PACKAGE_DATADIR"/gtksourceview-3.0/styles/");
+ initialized = TRUE;
+}
+
+/**
+ * ide_application_make_skeleton_dirs:
+ * @self: A #IdeApplication.
+ *
+ * Creates all the directories we might need later. Simpler to just ensure they
+ * are created during startup.
+ */
+static void
+ide_application_make_skeleton_dirs (IdeApplication *self)
+{
+ gchar *path;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+
+ path = g_build_filename (g_get_user_data_dir (),
+ "gnome-builder",
+ NULL);
+ g_mkdir_with_parents (path, 0750);
+ g_free (path);
+
+ path = g_build_filename (g_get_user_config_dir (),
+ "gnome-builder",
+ NULL);
+ g_mkdir_with_parents (path, 0750);
+ g_free (path);
+
+ path = g_build_filename (g_get_user_config_dir (),
+ "gnome-builder",
+ "snippets",
+ NULL);
+ g_mkdir_with_parents (path, 0750);
+ g_free (path);
+}
+
+static void
+ide_application_register_theme_overrides (IdeApplication *application)
+{
+ g_autoptr(GSettings) settings = NULL;
+ g_autoptr(GtkCssProvider) provider = NULL;
+ GtkSettings *gtk_settings;
+ GdkScreen *screen;
+
+ IDE_ENTRY;
+
+ gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/org/gnome/builder/icons/");
+
+ provider = ide_css_provider_new ();
+ screen = gdk_screen_get_default ();
+ gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ gtk_settings = gtk_settings_get_for_screen (screen);
+ settings = g_settings_new ("org.gnome.builder");
+ g_settings_bind (settings, "night-mode", gtk_settings, "gtk-application-prefer-dark-theme",
+ G_SETTINGS_BIND_DEFAULT);
+
+ IDE_EXIT;
+}
+
+static void
+ide_application_load_keybindings (IdeApplication *self)
+{
+ g_autoptr(GSettings) settings = NULL;
+ g_autofree gchar *name = NULL;
+
+ /* TODO: Move this to keybindings */
+ static const struct { gchar *name; gchar *binding; } shared_bindings[] = {
+ { "workbench.show-left-pane", "F9" },
+ { "workbench.show-right-pane", "<shift>F9" },
+ { "workbench.show-bottom-pane", "<ctrl>F9" },
+ { "workbench.toggle-panels", "<ctrl><shift>F9" },
+ { "workbench.focus-left", "<ctrl>grave" },
+ { "workbench.focus-right", "<ctrl>9" },
+ { "workbench.focus-stack(1)", "<ctrl>1" },
+ { "workbench.focus-stack(2)", "<ctrl>2" },
+ { "workbench.focus-stack(3)", "<ctrl>3" },
+ { "workbench.focus-stack(4)", "<ctrl>4" },
+ { "workbench.focus-stack(5)", "<ctrl>5" },
+ { "workbench.show-gear-menu", "F10" },
+ { "workbench.global-search", "<ctrl>period" },
+ { "app.preferences", "<Primary>comma" },
+ { "app.shortcuts", "<ctrl>question" },
+ { "workbench.new-document", "<ctrl>n" },
+ { "workbench.open-document", "<ctrl>o" },
+ { NULL }
+ };
+ gsize i;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ settings = g_settings_new ("org.gnome.builder.editor");
+ name = g_settings_get_string (settings, "keybindings");
+ self->keybindings = ide_keybindings_new (GTK_APPLICATION (self), name);
+ g_settings_bind (settings, "keybindings", self->keybindings, "mode", G_SETTINGS_BIND_GET);
+
+ for (i = 0; shared_bindings [i].name; i++)
+ {
+ const gchar *accels[2] = { shared_bindings [i].binding, NULL };
+ gtk_application_set_accels_for_action (GTK_APPLICATION (self),
+ shared_bindings [i].name,
+ accels);
+ }
+}
+
+static IdeWorkbench *
+ide_application_find_workbench_for_file (IdeApplication *self,
+ GFile *file)
+{
+ GList *iter;
+ GList *workbenches;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (G_IS_FILE (file));
+
+ workbenches = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ /*
+ * Find the a project that contains this file in its working directory.
+ */
+ for (iter = workbenches; iter; iter = iter->next)
+ {
+ if (IDE_IS_WORKBENCH (iter->data))
+ {
+ IdeWorkbench *workbench = iter->data;
+ g_autofree gchar *relpath = NULL;
+ IdeContext *context;
+ IdeVcs *vcs;
+ GFile *workdir;
+
+ context = ide_workbench_get_context (workbench);
+ vcs = ide_context_get_vcs (context);
+ workdir = ide_vcs_get_working_directory (vcs);
+
+ relpath = g_file_get_relative_path (workdir, file);
+
+ if (relpath != NULL)
+ return workbench;
+ }
+ }
+
+ /*
+ * No matches found, take the first workbench we find.
+ */
+ for (iter = workbenches; iter; iter = iter->next)
+ if (IDE_IS_WORKBENCH (iter->data))
+ return iter->data;
+
+ return NULL;
+}
+
+static void
+ide_application__context_new_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ g_autoptr(IdeContext) context = NULL;
+ IdeApplication *self;
+ IdeWorkbench *workbench;
+ GPtrArray *ar;
+ GError *error = NULL;
+ gsize i;
+
+ g_assert (G_IS_TASK (task));
+
+ self = g_task_get_source_object (task);
+ ar = g_task_get_task_data (task);
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (ar);
+
+ context = ide_context_new_finish (result, &error);
+
+ if (!context)
+ {
+ g_task_return_error (task, error);
+ goto cleanup;
+ }
+
+ {
+ IdeVcs *vcs;
+ GFile *workdir;
+ g_autofree gchar *path = NULL;
+
+ vcs = ide_context_get_vcs (context);
+ workdir = ide_vcs_get_working_directory (vcs);
+ path = g_file_get_path (workdir);
+
+ g_debug ("Project working directory: %s", path);
+ }
+
+ workbench = g_object_new (IDE_TYPE_WORKBENCH,
+ "application", self,
+ "context", context,
+ NULL);
+
+ for (i = 0; i < ar->len; i++)
+ {
+ GFile *file;
+
+ file = g_ptr_array_index (ar, i);
+ g_assert (G_IS_FILE (file));
+
+ //ide_workbench_open (workbench, file);
+ }
+
+ gtk_window_present (GTK_WINDOW (workbench));
+
+ g_task_return_boolean (task, TRUE);
+
+cleanup:
+ g_application_unmark_busy (G_APPLICATION (self));
+ g_application_release (G_APPLICATION (self));
+}
+
+/**
+ * ide_application_open_project_async:
+ * @self: A #IdeApplication.
+ * @file: A #GFile.
+ * @additional_files: (element-type GFile) (nullable): A #GPtrArray of #GFile or %NULL.
+ *
+ */
+void
+ide_application_open_project_async (IdeApplication *self,
+ GFile *file,
+ GPtrArray *additional_files,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GFile) directory = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GPtrArray) ar = NULL;
+ GList *windows;
+ GList *iter;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ for (iter = windows; iter; iter = iter->next)
+ {
+ if (IDE_IS_WORKBENCH (iter->data))
+ {
+ IdeContext *context;
+
+ context = ide_workbench_get_context (iter->data);
+
+ if (context != NULL)
+ {
+ GFile *project_file;
+
+ project_file = ide_context_get_project_file (context);
+
+ if (g_file_equal (file, project_file))
+ {
+ gtk_window_present (iter->data);
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+ }
+ }
+ }
+
+ if (additional_files)
+ ar = g_ptr_array_ref (additional_files);
+ else
+ ar = g_ptr_array_new ();
+
+ g_task_set_task_data (task, g_ptr_array_ref (ar), (GDestroyNotify)g_ptr_array_unref);
+
+ if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
+ directory = g_object_ref (file);
+ else
+ directory = g_file_get_parent (file);
+
+ g_application_mark_busy (G_APPLICATION (self));
+ g_application_hold (G_APPLICATION (self));
+
+ ide_context_new_async (directory,
+ NULL,
+ ide_application__context_new_cb,
+ g_object_ref (task));
+}
+
+gboolean
+ide_application_open_project_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+ g_return_val_if_fail (G_IS_TASK (task), FALSE);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+static void
+ide_application_open (GApplication *application,
+ GFile **files,
+ gint n_files,
+ const gchar *hint)
+{
+ IdeApplication *self = (IdeApplication *)application;
+ IdeWorkbench *workbench;
+ g_autoptr(GPtrArray) ar = NULL;
+ guint i;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ /*
+ * Try to open the files using an existing workbench.
+ */
+ for (i = 0; i < n_files; i++)
+ {
+ GFile *file = files [i];
+
+ g_assert (G_IS_FILE (file));
+
+ workbench = ide_application_find_workbench_for_file (self, file);
+
+ if (workbench != NULL)
+ {
+ //ide_workbench_open (workbench, file);
+ gtk_window_present (GTK_WINDOW (workbench));
+ continue;
+ }
+
+ if (!ar)
+ ar = g_ptr_array_new_with_free_func (g_object_unref);
+ g_ptr_array_add (ar, g_object_ref (file));
+ }
+
+ /*
+ * No workbench found for these files, let's create one!
+ */
+ if (ar && ar->len)
+ {
+ GFile *file = g_ptr_array_index (ar, 0);
+
+ ide_application_open_project_async (self, file, ar, NULL, NULL, NULL);
+ }
+
+ IDE_EXIT;
+}
+
+void
+ide_application_show_projects_window (IdeApplication *self)
+{
+#if 0
+ IdeProjectsDialog *window;
+ GList *windows;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ for (; windows; windows = windows->next)
+ {
+ if (IDE_IS_GREETER_WINDOW (windows->data))
+ {
+ gtk_window_present (windows->data);
+ return;
+ }
+ }
+
+ if (self->recent_projects == NULL)
+ {
+ self->recent_projects = ide_recent_projects_new ();
+ ide_recent_projects_discover_async (self->recent_projects, NULL, NULL, NULL);
+ }
+
+ window = g_object_new (IDE_TYPE_GREETER_WINDOW,
+ "application", self,
+ "recent-projects", self->recent_projects,
+ NULL);
+ gtk_window_group_add_window (self->greeter_group, GTK_WINDOW (window));
+ gtk_window_present (GTK_WINDOW (window));
+#endif
+}
+
+static void
+ide_application_activate (GApplication *application)
+{
+ IdeApplication *self = (IdeApplication *)application;
+ IdeWorkbench *workbench;
+ GList *list;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ if (ide_application_is_worker (self))
+ {
+ ide_application_load_worker (self);
+ return;
+ }
+
+ list = gtk_application_get_windows (GTK_APPLICATION (application));
+
+ for (; list; list = list->next)
+ {
+ if (IDE_IS_WORKBENCH (list->data))
+ {
+ gtk_window_present (GTK_WINDOW (list->data));
+ return;
+ }
+ }
+
+ workbench = g_object_new (IDE_TYPE_WORKBENCH,
+ "application", self,
+ NULL);
+ gtk_window_maximize (GTK_WINDOW (workbench));
+ gtk_window_present (GTK_WINDOW (workbench));
+}
+
+static void
+ide_application__extension_added (PeasExtensionSet *extensions,
+ PeasPluginInfo *plugin_info,
+ IdeApplicationAddin *addin,
+ IdeApplication *self)
+{
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_APPLICATION_ADDIN (addin));
+ g_assert (PEAS_IS_EXTENSION_SET (extensions));
+
+ ide_application_addin_load (addin, self);
+}
+
+static void
+ide_application__extension_removed (PeasExtensionSet *extensions,
+ PeasPluginInfo *plugin_info,
+ IdeApplicationAddin *addin,
+ IdeApplication *self)
+{
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_APPLICATION_ADDIN (addin));
+ g_assert (PEAS_IS_EXTENSION_SET (extensions));
+
+ ide_application_addin_unload (addin, self);
+}
+
+static void
+ide_application_load_addins (IdeApplication *self)
+{
+ PeasEngine *engine;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ engine = peas_engine_get_default ();
+
+ self->extensions = peas_extension_set_new (engine, IDE_TYPE_APPLICATION_ADDIN, NULL);
+
+ peas_extension_set_foreach (self->extensions,
+ (PeasExtensionSetForeachFunc)ide_application__extension_added,
+ self);
+
+ g_signal_connect_object (self->extensions,
+ "extension-added",
+ G_CALLBACK (ide_application__extension_added),
+ self,
+ 0);
+
+ g_signal_connect_object (self->extensions,
+ "extension-removed",
+ G_CALLBACK (ide_application__extension_removed),
+ self,
+ 0);
+}
+
+static void
+ide_application_startup (GApplication *app)
+{
+ IdeApplication *self = (IdeApplication *)app;
+ GgitFeatureFlags ggit_flags;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ self->startup_time = g_date_time_new_now_utc ();
+
+ g_resources_register (ide_get_resource ());
+
+ g_application_set_resource_base_path (app, "/org/gnome/builder");
+
+ g_irepository_prepend_search_path (PACKAGE_LIBDIR"/gnome-builder/girepository-1.0");
+
+ if (!ide_application_is_worker (self))
+ self->greeter_group = gtk_window_group_new ();
+
+ _ide_battery_monitor_init ();
+ _ide_thread_pool_init (ide_application_is_worker (self));
+
+ modeline_parser_init ();
+
+ ggit_init ();
+
+ ggit_flags = ggit_get_features ();
+
+ if ((ggit_flags & GGIT_FEATURE_THREADS) == 0)
+ {
+ g_error (_("Builder requires libgit2-glib with threading support."));
+ exit (EXIT_FAILURE);
+ }
+
+ if ((ggit_flags & GGIT_FEATURE_SSH) == 0)
+ {
+ g_error (_("Builder requires libgit2-glib with SSH support."));
+ exit (EXIT_FAILURE);
+ }
+
+ G_APPLICATION_CLASS (ide_application_parent_class)->startup (app);
+
+ if (!ide_application_is_worker (self))
+ {
+ ide_application_make_skeleton_dirs (self);
+ ide_application_actions_init (self);
+ ide_application_register_theme_overrides (self);
+ ide_application_setup_search_paths ();
+ ide_application_load_keybindings (self);
+ ide_application_load_plugins (self);
+ ide_application_load_addins (self);
+ }
+
+ IDE_EXIT;
+}
+
+static gboolean
+ide_application_increase_verbosity (void)
+{
+ ide_log_increase_verbosity ();
+ return TRUE;
+}
+
+static gint
+ide_application_handle_local_options (GApplication *app,
+ GVariantDict *options)
+{
+ if (g_variant_dict_contains (options, "version"))
+ {
+ g_print ("%s - Version %s\n", g_get_application_name (), VERSION);
+ return 0;
+ }
+
+ if (g_variant_dict_contains (options, "standalone") || g_variant_dict_contains (options, "type"))
+ {
+ GApplicationFlags flags;
+
+ flags = g_application_get_flags (app);
+ g_application_set_flags (app, flags | G_APPLICATION_NON_UNIQUE);
+ }
+
+ return -1;
+}
+
+static gboolean
+ide_application_local_command_line (GApplication *application,
+ gchar ***arguments,
+ int *exit_status)
+{
+ IdeApplication *self = (IdeApplication *)application;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (arguments != NULL);
+ g_assert (*arguments != NULL);
+ g_assert (exit_status != NULL);
+
+ self->argv0 = g_strdup ((*arguments) [0]);
+
+ return G_APPLICATION_CLASS (ide_application_parent_class)->
+ local_command_line (application, arguments, exit_status);
+}
+
+static void
+ide_application_finalize (GObject *object)
+{
+ IdeApplication *self = (IdeApplication *)object;
+
+ IDE_ENTRY;
+
+ g_clear_object (&self->extensions);
+ g_clear_pointer (&self->startup_time, g_date_time_unref);
+ g_clear_pointer (&self->argv0, g_free);
+ g_clear_object (&self->keybindings);
+ g_clear_object (&self->recent_projects);
+ g_clear_object (&self->greeter_group);
+
+ G_OBJECT_CLASS (ide_application_parent_class)->finalize (object);
+
+ IDE_EXIT;
+}
+
+static void
+ide_application_class_init (IdeApplicationClass *klass)
+{
+ GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ IDE_ENTRY;
+
+ object_class->finalize = ide_application_finalize;
+
+ app_class->activate = ide_application_activate;
+ app_class->startup = ide_application_startup;
+ app_class->open = ide_application_open;
+ app_class->local_command_line = ide_application_local_command_line;
+ app_class->handle_local_options = ide_application_handle_local_options;
+
+ IDE_EXIT;
+}
+
+static void
+ide_application_init (IdeApplication *app)
+{
+ GOptionEntry options[] = {
+ { "standalone",
+ 's',
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_NONE,
+ NULL,
+ N_("Run Builder in standalone mode") },
+
+ { "version",
+ 0,
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_NONE,
+ NULL,
+ N_("Show the application's version") },
+
+ { "verbose",
+ 'v',
+ G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_CALLBACK,
+ ide_application_increase_verbosity,
+ N_("Increase verbosity. May be specified multiple times.") },
+
+ { "dbus-address",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING,
+ &app->dbus_address,
+ N_("The DBus server address for which to connect.") },
+
+ { "type",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING,
+ &app->type,
+ N_("The type of plugin worker process to run.") },
+
+ { NULL }
+ };
+
+ IDE_ENTRY;
+
+ g_application_add_main_option_entries (G_APPLICATION (app), options);
+
+ IDE_EXIT;
+}
+
+GDateTime *
+ide_application_get_startup_time (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ return self->startup_time;
+}
+
+const gchar *
+ide_application_get_keybindings_mode (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ return ide_keybindings_get_mode (self->keybindings);
+}
+
+static void
+ide_application_get_worker_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeWorkerManager *worker_manager = (IdeWorkerManager *)object;
+ g_autoptr(GTask) task = user_data;
+ GError *error = NULL;
+ GDBusProxy *proxy;
+
+ g_assert (IDE_IS_WORKER_MANAGER (worker_manager));
+
+ proxy = ide_worker_manager_get_worker_finish (worker_manager, result, &error);
+
+ if (proxy == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, proxy, g_object_unref);
+}
+
+/**
+ * ide_application_get_worker_async:
+ * @self: A #IdeApplication
+ * @plugin_name: The name of the plugin.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback or %NULL.
+ * @user_data: user data for @callback.
+ *
+ * Asynchronously requests a #GDBusProxy to a service provided in a worker
+ * process. The worker should be an #IdeWorker implemented by the plugin named
+ * @plugin_name. The #IdeWorker is responsible for created both the service
+ * registered on the bus and the proxy to it.
+ *
+ * The #IdeApplication is responsible for spawning a subprocess for the worker.
+ *
+ * @callback should call ide_application_get_worker_finish() with the result
+ * provided to retrieve the result.
+ */
+void
+ide_application_get_worker_async (IdeApplication *self,
+ const gchar *plugin_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task = NULL;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+ g_return_if_fail (plugin_name != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ if (self->worker_manager == NULL)
+ self->worker_manager = ide_worker_manager_new (self->argv0);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ ide_worker_manager_get_worker_async (self->worker_manager,
+ plugin_name,
+ cancellable,
+ ide_application_get_worker_cb,
+ task);
+}
+
+/**
+ * ide_application_get_worker_finish:
+ * @self: A #IdeApplication.
+ * @result: A #GAsyncResult
+ * @error: a location for a #GError, or %NULL.
+ *
+ * Completes an asynchronous request to get a proxy to a worker process.
+ *
+ * Returns: (transfer full): A #GDBusProxy or %NULL.
+ */
+GDBusProxy *
+ide_application_get_worker_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+ g_return_val_if_fail (G_IS_TASK (task), NULL);
+
+ return g_task_propagate_pointer (task, error);
+}
+
+/**
+ * ide_application_get_recent_projects:
+ * @self: An #IdeApplication.
+ *
+ * This method will retreive an #IdeRecentProjects for the application that
+ * represents recent and discover projects on the system. The first time
+ * the #IdeRecentProjects is loaded, discovery of projects will occur. There
+ * is no need to call ide_recent_projects_discover_async().
+ *
+ * If you would like to display a spinner while discovery is in process, simply
+ * connect to the #IdeRecentProjects:busy: property notification.
+ *
+ * Returns: (transfer none): An #IdeRecentProjects.
+ */
+IdeRecentProjects *
+ide_application_get_recent_projects (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ if (self->recent_projects == NULL)
+ {
+ self->recent_projects = ide_recent_projects_new ();
+ ide_recent_projects_discover_async (self->recent_projects, NULL, NULL, NULL);
+ }
+
+ return self->recent_projects;
+}
diff --git a/libide/ide-application.h b/libide/ide-application.h
new file mode 100644
index 0000000..ba2282c
--- /dev/null
+++ b/libide/ide-application.h
@@ -0,0 +1,57 @@
+/* ide-application.h
+ *
+ * Copyright (C) 2014 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 IDE_APPLICATION_H
+#define IDE_APPLICATION_H
+
+#include <gtk/gtk.h>
+
+#include "ide-recent-projects.h"
+
+G_BEGIN_DECLS
+
+#define IDE_APPLICATION_DEFAULT (IDE_APPLICATION(g_application_get_default()))
+#define IDE_TYPE_APPLICATION (ide_application_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeApplication, ide_application, IDE, APPLICATION, GtkApplication)
+
+const gchar *ide_application_get_keybindings_mode (IdeApplication *self);
+GDateTime *ide_application_get_startup_time (IdeApplication *self);
+IdeRecentProjects *ide_application_get_recent_projects (IdeApplication *self);
+void ide_application_show_projects_window (IdeApplication *self);
+void ide_application_open_project_async (IdeApplication *self,
+ GFile *file,
+ GPtrArray *additional_files,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_application_open_project_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error);
+void ide_application_get_worker_async (IdeApplication *self,
+ const gchar *plugin_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDBusProxy *ide_application_get_worker_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* IDE_APPLICATION_H */
diff --git a/libide/ide-css-provider.c b/libide/ide-css-provider.c
new file mode 100644
index 0000000..ccf1857
--- /dev/null
+++ b/libide/ide-css-provider.c
@@ -0,0 +1,176 @@
+/* ide-css-provider.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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-css-provider"
+
+#include <glib/gi18n.h>
+#include <ide.h>
+
+#include "ide-css-provider.h"
+
+struct _IdeCssProvider
+{
+ GtkCssProvider parent_instance;
+
+ GtkSettings *settings;
+ gulong notify_gtk_theme_name_handler;
+};
+
+G_DEFINE_TYPE (IdeCssProvider, ide_css_provider, GTK_TYPE_CSS_PROVIDER)
+
+GtkCssProvider *
+ide_css_provider_new (void)
+{
+ return g_object_new (IDE_TYPE_CSS_PROVIDER, NULL);
+}
+
+static void
+ide_css_provider_update (IdeCssProvider *self)
+{
+ g_autofree gchar *theme_name = NULL;
+ g_autofree gchar *resource_path = NULL;
+ gboolean prefer_dark_theme = FALSE;
+ gsize len = 0;
+ guint32 flags = 0;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_CSS_PROVIDER (self));
+ g_assert (GTK_IS_SETTINGS (self->settings));
+
+ g_object_get (self->settings,
+ "gtk-theme-name", &theme_name,
+ "gtk-application-prefer-dark-theme", &prefer_dark_theme,
+ NULL);
+
+ resource_path = g_strdup_printf ("/org/gnome/builder/theme/%s%s.css",
+ theme_name,
+ prefer_dark_theme ? "-dark" : "");
+
+ if (!g_resources_get_info (resource_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &len, &flags, NULL))
+ {
+ g_free (resource_path);
+ resource_path = g_strdup ("/org/gnome/builder/theme/shared.css");
+ }
+
+ gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (self), resource_path);
+
+ IDE_EXIT;
+}
+
+static void
+ide_css_provider__settings_notify_gtk_theme_name (IdeCssProvider *self,
+ GParamSpec *pspec,
+ GtkSettings *settings)
+{
+ g_assert (IDE_IS_CSS_PROVIDER (self));
+
+ ide_css_provider_update (self);
+}
+
+static void
+ide_css_provider__settings_notify_gtk_application_prefer_dark_theme (IdeCssProvider *self,
+ GParamSpec *pspec,
+ GtkSettings *settings)
+{
+ g_assert (IDE_IS_CSS_PROVIDER (self));
+
+ ide_css_provider_update (self);
+}
+
+static void
+ide_css_provider_parsing_error (GtkCssProvider *provider,
+ GtkCssSection *section,
+ const GError *error)
+{
+ g_autofree gchar *uri = NULL;
+ GFile *file;
+ guint line = 0;
+ guint line_offset = 0;
+
+ g_assert (IDE_IS_CSS_PROVIDER (provider));
+ g_assert (error != NULL);
+
+ if (section != NULL)
+ {
+ file = gtk_css_section_get_file (section);
+ uri = g_file_get_uri (file);
+ line = gtk_css_section_get_start_line (section);
+ line_offset = gtk_css_section_get_start_position (section);
+ g_warning ("Parsing Error: %s @ %u:%u: %s", uri, line, line_offset, error->message);
+ }
+ else
+ {
+ g_warning ("%s", error->message);
+ }
+}
+
+static void
+ide_css_provider_constructed (GObject *object)
+{
+ IdeCssProvider *self = (IdeCssProvider *)object;
+
+ G_OBJECT_CLASS (ide_css_provider_parent_class)->constructed (object);
+
+ self->settings = g_object_ref (gtk_settings_get_default ());
+
+ self->notify_gtk_theme_name_handler =
+ g_signal_connect_object (self->settings,
+ "notify::gtk-theme-name",
+ G_CALLBACK (ide_css_provider__settings_notify_gtk_theme_name),
+ self,
+ G_CONNECT_SWAPPED);
+
+ self->notify_gtk_theme_name_handler =
+ g_signal_connect_object (
+ self->settings,
+ "notify::gtk-application-prefer-dark-theme",
+ G_CALLBACK (ide_css_provider__settings_notify_gtk_application_prefer_dark_theme),
+ self,
+ G_CONNECT_SWAPPED);
+
+ ide_css_provider_update (self);
+}
+
+static void
+ide_css_provider_finalize (GObject *object)
+{
+ IdeCssProvider *self = (IdeCssProvider *)object;
+
+ ide_clear_signal_handler (self->settings, &self->notify_gtk_theme_name_handler);
+ g_clear_object (&self->settings);
+
+ G_OBJECT_CLASS (ide_css_provider_parent_class)->finalize (object);
+}
+
+static void
+ide_css_provider_class_init (IdeCssProviderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkCssProviderClass *provider_class = GTK_CSS_PROVIDER_CLASS (klass);
+
+ object_class->finalize = ide_css_provider_finalize;
+ object_class->constructed = ide_css_provider_constructed;
+
+ provider_class->parsing_error = ide_css_provider_parsing_error;
+}
+
+static void
+ide_css_provider_init (IdeCssProvider *self)
+{
+}
diff --git a/src/greeter/gb-greeter-pill-box.h b/libide/ide-css-provider.h
similarity index 58%
copy from src/greeter/gb-greeter-pill-box.h
copy to libide/ide-css-provider.h
index 394a333..cd36e30 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/libide/ide-css-provider.h
@@ -1,4 +1,4 @@
-/* gb-greeter-pill-box.h
+/* ide-css-provider.h
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -16,22 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef IDE_CSS_PROVIDER_H
+#define IDE_CSS_PROVIDER_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
+#define IDE_TYPE_CSS_PROVIDER (ide_css_provider_get_type())
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
+G_DECLARE_FINAL_TYPE (IdeCssProvider, ide_css_provider, IDE, CSS_PROVIDER, GtkCssProvider)
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+GtkCssProvider *ide_css_provider_new (void);
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* IDE_CSS_PROVIDER_H */
diff --git a/libide/ide-greeter-perspective.c b/libide/ide-greeter-perspective.c
new file mode 100644
index 0000000..d8bc1ff
--- /dev/null
+++ b/libide/ide-greeter-perspective.c
@@ -0,0 +1,83 @@
+/* ide-greeter-perspective.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-greeter-perspective"
+
+#include <glib/gi18n.h>
+
+#include "egg-search-bar.h"
+
+#include "ide-greeter-perspective.h"
+#include "ide-perspective.h"
+
+struct _IdeGreeterPerspective
+{
+ GtkBin parent_instance;
+
+ GtkHeaderBar *titlebar;
+ EggSearchBar *search_bar;
+ GtkToggleButton *search_button;
+};
+
+static void ide_greeter_perspective_init_perspective (IdePerspectiveInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (IdeGreeterPerspective, ide_greeter_perspective, GTK_TYPE_BIN, 0,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE,
+ ide_greeter_perspective_init_perspective))
+
+static GtkWidget *
+ide_greeter_perspective_get_titlebar (IdePerspective *perspective)
+{
+ return GTK_WIDGET (((IdeGreeterPerspective *)perspective)->titlebar);
+}
+
+static void
+ide_greeter_perspective_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ide_greeter_perspective_parent_class)->finalize (object);
+}
+
+static void
+ide_greeter_perspective_class_init (IdeGreeterPerspectiveClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = ide_greeter_perspective_finalize;
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/builder/ui/ide-greeter-perspective.ui");
+ gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, titlebar);
+ gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, search_bar);
+ gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, search_button);
+}
+
+static void
+ide_greeter_perspective_init_perspective (IdePerspectiveInterface *iface)
+{
+ iface->get_titlebar = ide_greeter_perspective_get_titlebar;
+}
+
+static void
+ide_greeter_perspective_init (IdeGreeterPerspective *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ g_object_bind_property (self->search_button, "active", self->search_bar, "search-mode-enabled",
+ (G_BINDING_SYNC_CREATE|G_BINDING_BIDIRECTIONAL));
+}
diff --git a/src/greeter/gb-greeter-pill-box.h b/libide/ide-greeter-perspective.h
similarity index 51%
copy from src/greeter/gb-greeter-pill-box.h
copy to libide/ide-greeter-perspective.h
index 394a333..7ca4f5a 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/libide/ide-greeter-perspective.h
@@ -1,6 +1,6 @@
-/* gb-greeter-pill-box.h
+/* ide-greeter-perspective.h
*
- * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 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
@@ -16,22 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef IDE_GREETER_PERSPECTIVE_H
+#define IDE_GREETER_PERSPECTIVE_H
-#include <gtk/gtk.h>
+#include "ide-perspective.h"
G_BEGIN_DECLS
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
+#define IDE_TYPE_GREETER_PERSPECTIVE (ide_greeter_perspective_get_type())
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
-
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+G_DECLARE_FINAL_TYPE (IdeGreeterPerspective, ide_greeter_perspective, IDE, GREETER_PERSPECTIVE, GtkBin)
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* IDE_GREETER_PERSPECTIVE_H */
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index 814d8d9..460ac33 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -96,7 +96,7 @@ void _ide_source_view_set_count (IdeSourceView
guint count);
void _ide_source_view_set_modifier (IdeSourceView *self,
gunichar modifier);
-void _ide_thread_pool_init (void);
+void _ide_thread_pool_init (gboolean is_worker);
IdeUnsavedFile *_ide_unsaved_file_new (GFile *file,
GBytes *content,
const gchar *temp_path,
diff --git a/libide/ide-keybindings.c b/libide/ide-keybindings.c
new file mode 100644
index 0000000..37b2b32
--- /dev/null
+++ b/libide/ide-keybindings.c
@@ -0,0 +1,282 @@
+/* ide-keybindings.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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-keybindings"
+
+#include <glib/gi18n.h>
+#include <ide.h>
+
+#include "ide-keybindings.h"
+
+struct _IdeKeybindings
+{
+ GObject parent_instance;
+
+ GtkApplication *application;
+ GtkCssProvider *css_provider;
+ gchar *mode;
+ guint constructed : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_APPLICATION,
+ PROP_MODE,
+ LAST_PROP
+};
+
+G_DEFINE_TYPE (IdeKeybindings, ide_keybindings, G_TYPE_OBJECT)
+
+static GParamSpec *properties [LAST_PROP];
+
+IdeKeybindings *
+ide_keybindings_new (GtkApplication *application,
+ const gchar *mode)
+{
+ g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
+
+ return g_object_new (IDE_TYPE_KEYBINDINGS,
+ "application", application,
+ "mode", mode,
+ NULL);
+}
+
+static void
+ide_keybindings_reload (IdeKeybindings *self)
+{
+ const gchar *mode;
+ g_autofree gchar *path = NULL;
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_KEYBINDINGS (self));
+
+ mode = self->mode ? self->mode : "default";
+ IDE_TRACE_MSG ("Loading %s keybindings", mode);
+ path = g_strdup_printf ("/org/gnome/builder/keybindings/%s.css", mode);
+ bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, &error);
+
+ if (error == NULL)
+ gtk_css_provider_load_from_data (self->css_provider,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ &error);
+
+ if (error)
+ g_warning ("%s", error->message);
+
+ IDE_EXIT;
+}
+
+const gchar *
+ide_keybindings_get_mode (IdeKeybindings *self)
+{
+ g_return_val_if_fail (IDE_IS_KEYBINDINGS (self), NULL);
+
+ return self->mode;
+}
+
+void
+ide_keybindings_set_mode (IdeKeybindings *self,
+ const gchar *mode)
+{
+ g_return_if_fail (IDE_IS_KEYBINDINGS (self));
+
+ if (mode != self->mode)
+ {
+ g_free (self->mode);
+ self->mode = g_strdup (mode);
+ if (self->constructed)
+ ide_keybindings_reload (self);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODE]);
+ }
+}
+
+GtkApplication *
+ide_keybindings_get_application (IdeKeybindings *self)
+{
+ g_return_val_if_fail (IDE_IS_KEYBINDINGS (self), NULL);
+
+ return self->application;
+}
+
+static void
+ide_keybindings_set_application (IdeKeybindings *self,
+ GtkApplication *application)
+{
+ g_assert (IDE_IS_KEYBINDINGS (self));
+ g_assert (!application || GTK_IS_APPLICATION (application));
+
+ if (application != self->application)
+ {
+ if (self->application)
+ {
+ /* remove keybindings */
+ g_clear_object (&self->application);
+ }
+
+ if (application)
+ {
+ /* connect keybindings */
+ self->application = g_object_ref (application);
+ }
+ }
+}
+
+static void
+ide_keybindings_parsing_error (GtkCssProvider *css_provider,
+ GtkCssSection *section,
+ GError *error,
+ gpointer user_data)
+{
+ g_autofree gchar *filename = NULL;
+ GFile *file;
+ guint start_line;
+ guint end_line;
+
+ file = gtk_css_section_get_file (section);
+ filename = g_file_get_uri (file);
+ start_line = gtk_css_section_get_start_line (section);
+ end_line = gtk_css_section_get_end_line (section);
+
+ g_warning ("CSS parsing error in %s between lines %u and %u", filename, start_line, end_line);
+}
+
+static void
+ide_keybindings_constructed (GObject *object)
+{
+ IdeKeybindings *self = (IdeKeybindings *)object;
+ GdkScreen *screen;
+
+ IDE_ENTRY;
+
+ G_OBJECT_CLASS (ide_keybindings_parent_class)->constructed (object);
+
+ screen = gdk_screen_get_default ();
+ gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (self->css_provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ self->constructed = TRUE;
+
+ ide_keybindings_reload (self);
+
+ IDE_EXIT;
+}
+
+static void
+ide_keybindings_finalize (GObject *object)
+{
+ IdeKeybindings *self = (IdeKeybindings *)object;
+
+ IDE_ENTRY;
+
+ g_clear_object (&self->application);
+ g_clear_object (&self->css_provider);
+ g_clear_pointer (&self->mode, g_free);
+
+ G_OBJECT_CLASS (ide_keybindings_parent_class)->finalize (object);
+
+ IDE_EXIT;
+}
+
+static void
+ide_keybindings_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeKeybindings *self = IDE_KEYBINDINGS (object);
+
+ switch (prop_id)
+ {
+ case PROP_APPLICATION:
+ g_value_set_object (value, ide_keybindings_get_application (self));
+ break;
+
+ case PROP_MODE:
+ g_value_set_string (value, ide_keybindings_get_mode (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_keybindings_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeKeybindings *self = IDE_KEYBINDINGS (object);
+
+ switch (prop_id)
+ {
+ case PROP_APPLICATION:
+ ide_keybindings_set_application (self, g_value_get_object (value));
+ break;
+
+ case PROP_MODE:
+ ide_keybindings_set_mode (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_keybindings_class_init (IdeKeybindingsClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = ide_keybindings_constructed;
+ object_class->finalize = ide_keybindings_finalize;
+ object_class->get_property = ide_keybindings_get_property;
+ object_class->set_property = ide_keybindings_set_property;
+
+ properties [PROP_APPLICATION] =
+ g_param_spec_object ("application",
+ "Application",
+ "The application to register keybindings for.",
+ GTK_TYPE_APPLICATION,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_MODE] =
+ g_param_spec_string ("mode",
+ "Mode",
+ "The name of the keybindings mode.",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+ide_keybindings_init (IdeKeybindings *self)
+{
+ self->css_provider = gtk_css_provider_new ();
+
+ g_signal_connect (self->css_provider,
+ "parsing-error",
+ G_CALLBACK (ide_keybindings_parsing_error),
+ NULL);
+}
diff --git a/libide/ide-keybindings.h b/libide/ide-keybindings.h
new file mode 100644
index 0000000..a1196b6
--- /dev/null
+++ b/libide/ide-keybindings.h
@@ -0,0 +1,39 @@
+/* ide-keybindings.h
+ *
+ * Copyright (C) 2014-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 IDE_KEYBINDINGS_H
+#define IDE_KEYBINDINGS_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_KEYBINDINGS (ide_keybindings_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeKeybindings, ide_keybindings, IDE, KEYBINDINGS, GObject)
+
+IdeKeybindings *ide_keybindings_new (GtkApplication *application,
+ const gchar *mode);
+GtkApplication *ide_keybindings_get_application (IdeKeybindings *self);
+const gchar *ide_keybindings_get_mode (IdeKeybindings *self);
+void ide_keybindings_set_mode (IdeKeybindings *self,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* IDE_KEYBINDINGS_H */
diff --git a/libide/ide-layout-manager.c b/libide/ide-layout-manager.c
new file mode 100644
index 0000000..ff37280
--- /dev/null
+++ b/libide/ide-layout-manager.c
@@ -0,0 +1,72 @@
+/* ide-layout-manager.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-layout-manager.h"
+
+G_DEFINE_INTERFACE (IdeLayoutManager, ide_layout_manager, G_TYPE_OBJECT)
+
+static void
+ide_layout_manager_default_init (IdeLayoutManagerInterface *iface)
+{
+}
+
+/**
+ * ide_layout_manager_add:
+ * @self: An #IdeLayoutManager.
+ * @hints: (nullable): optional hints for the layout.
+ * @child: A #GtkWidget.
+ *
+ * Adds @child to the layout, optionally hinting to the layout manager about where to
+ * place the child.
+ *
+ * Returns: A layout specific identifier greater than zero, which should be passed to
+ * ide_layout_manager_remove() to remove the widget from the layout.
+ */
+guint
+ide_layout_manager_add (IdeLayoutManager *self,
+ const IdeLayoutHints *hints,
+ GtkWidget *child)
+{
+ guint ret;
+
+ g_return_val_if_fail (IDE_IS_LAYOUT_MANAGER (self), 0);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), 0);
+
+ ret = IDE_LAYOUT_MANAGER_GET_IFACE (self)->add (self, hints, child);
+
+ g_return_val_if_fail (ret > 0, 0);
+
+ return ret;
+}
+
+/**
+ * ide_layout_manager_remove:
+ * @self: An #IdeLayoutManager.
+ * @layout_id: The layout id from ide_layout_manager_add()
+ *
+ * Removes a widget from the layout that was generated by calling * ide_layout_manager_add().
+ */
+void
+ide_layout_manager_remove (IdeLayoutManager *self,
+ guint layout_id)
+{
+ g_return_if_fail (IDE_IS_LAYOUT_MANAGER (self));
+ g_return_if_fail (layout_id > 0);
+
+ IDE_LAYOUT_MANAGER_GET_IFACE (self)->remove (self, layout_id);
+}
diff --git a/libide/ide-layout-manager.h b/libide/ide-layout-manager.h
new file mode 100644
index 0000000..3372138
--- /dev/null
+++ b/libide/ide-layout-manager.h
@@ -0,0 +1,60 @@
+/* ide-layout-manager.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_LAYOUT_MANAGER_H
+#define IDE_LAYOUT_MANAGER_H
+
+#include <gtk/gtk.h>
+
+#include "ide-view.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_LAYOUT_MANAGER (ide_layout_manager_get_type())
+
+G_DECLARE_INTERFACE (IdeLayoutManager, ide_layout_manager, IDE, LAYOUT_MANAGER, GObject)
+
+typedef struct
+{
+ GtkWidget *left_of;
+ GtkWidget *right_of;
+ GtkWidget *above;
+ GtkWidget *below;
+ gint column;
+} IdeLayoutHints;
+
+struct _IdeLayoutManagerInterface
+{
+ GTypeInterface parent_instance;
+
+ guint (*add) (IdeLayoutManager *self,
+ const IdeLayoutHints *hints,
+ GtkWidget *child);
+ void (*remove) (IdeLayoutManager *self,
+ guint layout_id);
+};
+
+guint ide_layout_manager_add (IdeLayoutManager *self,
+ const IdeLayoutHints *hints,
+ GtkWidget *child);
+void ide_layout_manager_remove (IdeLayoutManager *self,
+ guint layout_id);
+
+G_END_DECLS
+
+#endif /* IDE_LAYOUT_MANAGER_H */
diff --git a/libide/ide-perspective.c b/libide/ide-perspective.c
new file mode 100644
index 0000000..3b9a8ec
--- /dev/null
+++ b/libide/ide-perspective.c
@@ -0,0 +1,236 @@
+/* ide-perspective.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-perspective.h"
+
+G_DEFINE_INTERFACE (IdePerspective, ide_perspective, G_TYPE_OBJECT)
+
+static gboolean
+ide_perspective_real_agree_to_shutdown (IdePerspective *self)
+{
+ return TRUE;
+}
+
+static GActionGroup *
+ide_perspective_real_get_actions (IdePerspective *self)
+{
+ return NULL;
+}
+
+static const gchar *
+ide_perspective_real_get_icon_name (IdePerspective *self)
+{
+ return NULL;
+}
+
+static gboolean
+ide_perspective_real_get_needs_attention (IdePerspective *self)
+{
+ return FALSE;
+}
+
+static const gchar *
+ide_perspective_real_get_title (IdePerspective *self)
+{
+ return NULL;
+}
+
+static GtkWidget *
+ide_perspective_real_get_titlebar (IdePerspective *self)
+{
+ return NULL;
+}
+
+static void
+ide_perspective_real_set_fullscreen (IdePerspective *self,
+ gboolean fullscreen)
+{
+}
+
+static void
+ide_perspective_real_views_foreach (IdePerspective *self,
+ GtkCallback callback,
+ gpointer user_data)
+{
+}
+
+static void
+ide_perspective_default_init (IdePerspectiveInterface *iface)
+{
+ iface->agree_to_shutdown = ide_perspective_real_agree_to_shutdown;
+ iface->get_actions = ide_perspective_real_get_actions;
+ iface->get_icon_name = ide_perspective_real_get_icon_name;
+ iface->get_needs_attention = ide_perspective_real_get_needs_attention;
+ iface->get_title = ide_perspective_real_get_title;
+ iface->get_titlebar = ide_perspective_real_get_titlebar;
+ iface->set_fullscreen = ide_perspective_real_set_fullscreen;
+ iface->views_foreach = ide_perspective_real_views_foreach;
+}
+
+/**
+ * ide_perspective_agree_to_shutdown:
+ * @self: An #IdePerspective.
+ *
+ * This interface method is called when the workbench would like to shutdown.
+ * If the perspective needs to focus and ask the user a question, this is the place
+ * to do so. You may run a #GtkDialog using gtk_dialog_run() or simply focus your
+ * perspective and return %FALSE.
+ *
+ * Returns: %TRUE to allow the workbench to continue shutting down.
+ */
+gboolean
+ide_perspective_agree_to_shutdown (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), FALSE);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->agree_to_shutdown (self);
+}
+
+/**
+ * ide_perspective_get_icon_name:
+ * @self: An #IdePerspective.
+ *
+ * This interface methods retrieves the icon name to use when displaying the
+ * perspective selection sidebar.
+ *
+ * If you implement an "icon-name" property, the icon may change at runtime.
+ *
+ * Returns: A named icon as a string which will not be modified or freed.
+ */
+const gchar *
+ide_perspective_get_icon_name (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), NULL);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->get_icon_name (self);
+}
+
+/**
+ * ide_perspective_get_needs_attention:
+ * @self: An #IdePerspective.
+ *
+ * This interface method returns %TRUE if the interface needs attention.
+ *
+ * One such use of this would be to indicate that contents within a perspective have
+ * changed since the user last focused the perspective. This should also be implemented
+ * with a boolean property named "needs-attention". If you call g_object_notify() (or one
+ * of its variants), the notifcation visual will be rendered with your icon.
+ *
+ * Returns: %TRUE if the perspective needs attention.
+ */
+gboolean
+ide_perspective_get_needs_attention (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), FALSE);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->get_needs_attention (self);
+}
+
+/**
+ * ide_perspective_get_title:
+ * @self: An #IdePerspective
+ *
+ * This interface method gets the title of the perspective. This is used for tooltips
+ * in the perspective selector and potentially other UI components.
+ *
+ * Returns: A string which will not be modified or freed.
+ */
+const gchar *
+ide_perspective_get_title (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), NULL);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->get_title (self);
+}
+
+/**
+ * ide_perspective_get_titlebar:
+ * @self: An #IdePerspective.
+ *
+ * This interface method should return a #GtkWidget suitable for being embedded as the
+ * titlebar for the application. If you return %NULL from this method, a suitable titlebar
+ * will be created for you.
+ *
+ * You may use #IdeHeaderBar for a base implementation to save you the trouble of
+ * creating a titlebar similar to other perspectives in Builder.
+ *
+ * Returns: (transfer none) (nullable): A #GtkWidget or %NULL.
+ */
+GtkWidget *
+ide_perspective_get_titlebar (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), NULL);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->get_titlebar (self);
+}
+
+/**
+ * ide_perspective_set_fullscreen:
+ * @self: An #IdePerspective.
+ * @fullscreen: If fullscreen mode should be activated.
+ *
+ * This interface method is used to notify the perspective that it is going into
+ * fullscreen mode. The #IdeWorkbench will notify the perspective before it is displayed.
+ */
+void
+ide_perspective_set_fullscreen (IdePerspective *self,
+ gboolean fullscreen)
+{
+ g_return_if_fail (IDE_IS_PERSPECTIVE (self));
+
+ IDE_PERSPECTIVE_GET_IFACE (self)->set_fullscreen (self, fullscreen);
+}
+
+/**
+ * ide_perspective_views_foreach:
+ * @self: An #IdePerspective.
+ * @callback: (scope call): A #GtkCallback.
+ * @user_data: user data for @callback.
+ *
+ * This interface method is used to iterate all #IdeView's that are descendents of @self.
+ */
+void
+ide_perspective_views_foreach (IdePerspective *self,
+ GtkCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (IDE_IS_PERSPECTIVE (self));
+ g_return_if_fail (callback != NULL);
+
+ IDE_PERSPECTIVE_GET_IFACE (self)->views_foreach (self, callback, user_data);
+}
+
+/**
+ * ide_perspective_get_actions:
+ * @self: An #IdePerspective.
+ *
+ * This interface method should retrieve a #GActionGroup associated with the
+ * perspective, if necessary. The #GActionGroup will automatically be
+ * registered with the "perspective" action prefix while the perspective is
+ * active. A perspective is "active" when it is currently displayed in the
+ * workbench.
+ *
+ * Returns: (nullable) (transfer full): A #GActionGroup or %NULL.
+ */
+GActionGroup *
+ide_perspective_get_actions (IdePerspective *self)
+{
+ g_return_val_if_fail (IDE_IS_PERSPECTIVE (self), NULL);
+
+ return IDE_PERSPECTIVE_GET_IFACE (self)->get_actions (self);
+}
diff --git a/libide/ide-perspective.h b/libide/ide-perspective.h
new file mode 100644
index 0000000..b5c5901
--- /dev/null
+++ b/libide/ide-perspective.h
@@ -0,0 +1,61 @@
+/* ide-perspective.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_PERSPECTIVE_H
+#define IDE_PERSPECTIVE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PERSPECTIVE (ide_perspective_get_type())
+
+G_DECLARE_INTERFACE (IdePerspective, ide_perspective, IDE, PERSPECTIVE, GtkWidget)
+
+struct _IdePerspectiveInterface
+{
+ GTypeInterface parent;
+
+ gboolean (*agree_to_shutdown) (IdePerspective *self);
+ GActionGroup *(*get_actions) (IdePerspective *self);
+ const gchar *(*get_icon_name) (IdePerspective *self);
+ gboolean (*get_needs_attention) (IdePerspective *self);
+ const gchar *(*get_title) (IdePerspective *self);
+ GtkWidget *(*get_titlebar) (IdePerspective *self);
+ void (*set_fullscreen) (IdePerspective *self,
+ gboolean fullscreen);
+ void (*views_foreach) (IdePerspective *self,
+ GtkCallback callback,
+ gpointer user_data);
+};
+
+gboolean ide_perspective_agree_to_shutdown (IdePerspective *self);
+GActionGroup *ide_perspective_get_actions (IdePerspective *self);
+const gchar *ide_perspective_get_icon_name (IdePerspective *self);
+const gchar *ide_perspective_get_title (IdePerspective *self);
+GtkWidget *ide_perspective_get_titlebar (IdePerspective *self);
+gboolean ide_perspective_get_needs_attention (IdePerspective *self);
+void ide_perspective_set_fullscreen (IdePerspective *self,
+ gboolean fullscreen);
+void ide_perspective_views_foreach (IdePerspective *self,
+ GtkCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* IDE_PERSPECTIVE_H */
diff --git a/libide/ide-preferences-addin.c b/libide/ide-preferences-addin.c
new file mode 100644
index 0000000..2463942
--- /dev/null
+++ b/libide/ide-preferences-addin.c
@@ -0,0 +1,81 @@
+/* ide-preferences-addin.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-preferences-addin.h"
+
+G_DEFINE_INTERFACE (IdePreferencesAddin, ide_preferences_addin, G_TYPE_OBJECT)
+
+static void
+ide_preferences_addin_real_load (IdePreferencesAddin *self,
+ IdePreferences *preferences)
+{
+}
+
+static void
+ide_preferences_addin_real_unload (IdePreferencesAddin *self,
+ IdePreferences *preferences)
+{
+}
+
+static void
+ide_preferences_addin_default_init (IdePreferencesAddinInterface *iface)
+{
+ iface->load = ide_preferences_addin_real_load;
+ iface->unload = ide_preferences_addin_real_unload;
+}
+
+/**
+ * ide_preferences_addin_load:
+ * @self: An #IdePreferencesAddin.
+ * @preferences: The preferences container implementation.
+ *
+ * This interface method is called when a preferences addin is initialized. It could be
+ * initialized from multiple preferences implementations, so consumers should use the
+ * #IdePreferences interface to add their preferences controls to the container.
+ *
+ * Such implementations might include a preferences dialog window, or a preferences
+ * widget which could be rendered as a perspective.
+ */
+void
+ide_preferences_addin_load (IdePreferencesAddin *self,
+ IdePreferences *preferences)
+{
+ g_return_if_fail (IDE_IS_PREFERENCES_ADDIN (self));
+ g_return_if_fail (IDE_IS_PREFERENCES (preferences));
+
+ IDE_PREFERENCES_ADDIN_GET_IFACE (self)->load (self, preferences);
+}
+
+/**
+ * ide_preferences_addin_unload:
+ * @self: An #IdePreferencesAddin.
+ * @preferences: The preferences container implementation.
+ *
+ * This interface method is called when the preferences addin should remove all controls
+ * added to @preferences. This could happen during desctruction of @preferences, or when
+ * the plugin is unloaded.
+ */
+void
+ide_preferences_addin_unload (IdePreferencesAddin *self,
+ IdePreferences *preferences)
+{
+ g_return_if_fail (IDE_IS_PREFERENCES_ADDIN (self));
+ g_return_if_fail (IDE_IS_PREFERENCES (preferences));
+
+ IDE_PREFERENCES_ADDIN_GET_IFACE (self)->unload (self, preferences);
+}
diff --git a/libide/ide-preferences-addin.h b/libide/ide-preferences-addin.h
new file mode 100644
index 0000000..308b7be
--- /dev/null
+++ b/libide/ide-preferences-addin.h
@@ -0,0 +1,49 @@
+/* ide-preferences-addin.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_PREFERENCES_ADDIN_H
+#define IDE_PREFERENCES_ADDIN_H
+
+#include <gtk/gtk.h>
+
+#include "ide-preferences.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PREFERENCES_ADDIN (ide_preferences_addin_get_type())
+
+G_DECLARE_INTERFACE (IdePreferencesAddin, ide_preferences_addin, IDE, PREFERENCES_ADDIN, GObject)
+
+struct _IdePreferencesAddinInterface
+{
+ GTypeInterface parent_interface;
+
+ void (*load) (IdePreferencesAddin *self,
+ IdePreferences *preferences);
+ void (*unload) (IdePreferencesAddin *self,
+ IdePreferences *preferences);
+};
+
+void ide_preferences_addin_load (IdePreferencesAddin *self,
+ IdePreferences *preferences);
+void ide_preferences_addin_unload (IdePreferencesAddin *self,
+ IdePreferences *preferences);
+
+G_END_DECLS
+
+#endif /* IDE_PREFERENCES_ADDIN_H */
diff --git a/libide/ide-preferences.c b/libide/ide-preferences.c
new file mode 100644
index 0000000..eaae59d
--- /dev/null
+++ b/libide/ide-preferences.c
@@ -0,0 +1,116 @@
+/* ide-preferences.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-preferences.h"
+
+G_DEFINE_INTERFACE (IdePreferences, ide_preferences, G_TYPE_OBJECT)
+
+static void
+ide_preferences_default_init (IdePreferencesInterface *iface)
+{
+}
+
+void
+ide_preferences_add_page (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *title,
+ gint priority)
+{
+ g_return_if_fail (IDE_IS_PREFERENCES (self));
+ g_return_if_fail (page_name != NULL);
+ g_return_if_fail (title != NULL);
+
+ IDE_PREFERENCES_GET_IFACE (self)->add_page (self, page_name, title, priority);
+}
+
+void
+ide_preferences_add_group (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *title,
+ gint priority)
+{
+ g_return_if_fail (IDE_IS_PREFERENCES (self));
+ g_return_if_fail (page_name != NULL);
+ g_return_if_fail (group_name != NULL);
+ g_return_if_fail (title != NULL);
+
+ IDE_PREFERENCES_GET_IFACE (self)->add_group (self, page_name, group_name, title, priority);
+}
+
+guint
+ide_preferences_add_switch (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority)
+{
+ g_return_val_if_fail (IDE_IS_PREFERENCES (self), 0);
+ g_return_val_if_fail (page_name != NULL, 0);
+ g_return_val_if_fail (group_name != NULL, 0);
+ g_return_val_if_fail (schema_id != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (title != NULL, 0);
+
+ return IDE_PREFERENCES_GET_IFACE (self)->add_switch (self, page_name, group_name, schema_id, key,
+ title, subtitle, keywords, priority);
+}
+
+guint
+ide_preferences_add_spinbutton (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority)
+{
+ g_return_val_if_fail (IDE_IS_PREFERENCES (self), 0);
+ g_return_val_if_fail (page_name != NULL, 0);
+ g_return_val_if_fail (group_name != NULL, 0);
+ g_return_val_if_fail (schema_id != NULL, 0);
+ g_return_val_if_fail (key != NULL, 0);
+ g_return_val_if_fail (title != NULL, 0);
+
+ return IDE_PREFERENCES_GET_IFACE (self)->add_spinbutton (self, page_name, group_name, schema_id,
+ key, title, subtitle, keywords,
+ priority);
+}
+
+guint
+ide_preferences_add_custom (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ GtkWidget *widget,
+ const gchar *keywords,
+ gint priority)
+{
+ g_return_val_if_fail (IDE_IS_PREFERENCES (self), 0);
+ g_return_val_if_fail (page_name != NULL, 0);
+ g_return_val_if_fail (group_name != NULL, 0);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
+
+ return IDE_PREFERENCES_GET_IFACE (self)->add_custom (self, page_name, group_name, widget,
+ keywords, priority);
+}
diff --git a/libide/ide-preferences.h b/libide/ide-preferences.h
new file mode 100644
index 0000000..bca3d13
--- /dev/null
+++ b/libide/ide-preferences.h
@@ -0,0 +1,105 @@
+/* ide-preferences.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_PREFERENCES_H
+#define IDE_PREFERENCES_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PREFERENCES (ide_preferences_get_type())
+
+G_DECLARE_INTERFACE (IdePreferences, ide_preferences, IDE, PREFERENCES, GObject)
+
+struct _IdePreferencesInterface
+{
+ GTypeInterface parent_interface;
+
+ void (*add_page) (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *title,
+ gint priority);
+ void (*add_group) (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *title,
+ gint priority);
+ guint (*add_switch) (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority);
+ guint (*add_spinbutton) (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority);
+ guint (*add_custom) (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ GtkWidget *widget,
+ const gchar *keywords,
+ gint priority);
+};
+
+void ide_preferences_add_page (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *title,
+ gint priority);
+void ide_preferences_add_group (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *title,
+ gint priority);
+guint ide_preferences_add_switch (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority);
+guint ide_preferences_add_spinbutton (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ const gchar *schema_id,
+ const gchar *key,
+ const gchar *title,
+ const gchar *subtitle,
+ const gchar *keywords,
+ gint priority);
+guint ide_preferences_add_custom (IdePreferences *self,
+ const gchar *page_name,
+ const gchar *group_name,
+ GtkWidget *widget,
+ const gchar *keywords,
+ gint priority);
+
+G_END_DECLS
+
+#endif /* IDE_PREFERENCES_H */
diff --git a/libide/ide-thread-pool.c b/libide/ide-thread-pool.c
index d45c830..4eaa613 100644
--- a/libide/ide-thread-pool.c
+++ b/libide/ide-thread-pool.c
@@ -183,8 +183,19 @@ ide_thread_pool_worker (gpointer data,
}
void
-_ide_thread_pool_init (void)
+_ide_thread_pool_init (gboolean is_worker)
{
+ gint compiler = COMPILER_MAX_THREADS;
+ gint indexer = INDEXER_MAX_THREADS;
+ gboolean shared = FALSE;
+
+ if (is_worker)
+ {
+ compiler = 1;
+ indexer = 1;
+ shared = TRUE;
+ }
+
/*
* Create our thread pool exclusive to compiler tasks (such as those from Clang).
* We don't want to consume threads fro other GTask's such as those regarding IO so we manage
@@ -192,8 +203,8 @@ _ide_thread_pool_init (void)
*/
thread_pools [IDE_THREAD_POOL_COMPILER] = g_thread_pool_new (ide_thread_pool_worker,
NULL,
- COMPILER_MAX_THREADS,
- FALSE,
+ compiler,
+ shared,
NULL);
/*
@@ -202,7 +213,7 @@ _ide_thread_pool_init (void)
*/
thread_pools [IDE_THREAD_POOL_INDEXER] = g_thread_pool_new (ide_thread_pool_worker,
NULL,
- INDEXER_MAX_THREADS,
- FALSE,
+ indexer,
+ shared,
NULL);
}
diff --git a/libide/ide-view.c b/libide/ide-view.c
new file mode 100644
index 0000000..6a7ad9c
--- /dev/null
+++ b/libide/ide-view.c
@@ -0,0 +1,129 @@
+/* ide-view.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-view.h"
+
+G_DEFINE_INTERFACE (IdeView, ide_view, GTK_TYPE_WIDGET)
+
+static const gchar *
+ide_view_real_get_title (IdeView *self)
+{
+ return NULL;
+}
+
+static const gchar *
+ide_view_real_get_icon_name (IdeView *self)
+{
+ return NULL;
+}
+
+static gboolean
+ide_view_real_get_can_save (IdeView *self)
+{
+ return FALSE;
+}
+
+static gboolean
+ide_view_real_get_needs_attention (IdeView *self)
+{
+ return FALSE;
+}
+
+static void
+ide_view_real_save_async (IdeView *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_task_report_new_error (self, callback, user_data, ide_view_real_save_async,
+ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Saving is not supported.");
+}
+
+static gboolean
+ide_view_real_save_finish (IdeView *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+ide_view_default_init (IdeViewInterface *iface)
+{
+ iface->get_title = ide_view_real_get_title;
+ iface->get_icon_name = ide_view_real_get_icon_name;
+ iface->get_can_save = ide_view_real_get_can_save;
+ iface->get_needs_attention = ide_view_real_get_needs_attention;
+ iface->save_async = ide_view_real_save_async;
+ iface->save_finish = ide_view_real_save_finish;
+}
+
+const gchar *
+ide_view_get_title (IdeView *self)
+{
+ g_return_val_if_fail (IDE_IS_VIEW (self), NULL);
+
+ return NULL;
+}
+
+const gchar *
+ide_view_get_icon_name (IdeView *self)
+{
+ g_return_val_if_fail (IDE_IS_VIEW (self), NULL);
+
+ return IDE_VIEW_GET_IFACE (self)->get_icon_name (self);
+}
+
+gboolean
+ide_view_get_can_save (IdeView *self)
+{
+ g_return_val_if_fail (IDE_IS_VIEW (self), FALSE);
+
+ return IDE_VIEW_GET_IFACE (self)->get_can_save (self);
+}
+
+gboolean
+ide_view_get_needs_attention (IdeView *self)
+{
+ g_return_val_if_fail (IDE_IS_VIEW (self), FALSE);
+
+ return IDE_VIEW_GET_IFACE (self)->get_needs_attention (self);
+}
+
+void
+ide_view_save_async (IdeView *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (IDE_IS_VIEW (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ IDE_VIEW_GET_IFACE (self)->save_async (self, cancellable, callback, user_data);
+}
+
+gboolean
+ide_view_save_finish (IdeView *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_VIEW (self), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+ return IDE_VIEW_GET_IFACE (self)->save_finish (self, result, error);
+}
diff --git a/libide/ide-view.h b/libide/ide-view.h
new file mode 100644
index 0000000..d73f462
--- /dev/null
+++ b/libide/ide-view.h
@@ -0,0 +1,61 @@
+/* ide-view.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_VIEW_H
+#define IDE_VIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_VIEW (ide_view_get_type())
+
+G_DECLARE_INTERFACE (IdeView, ide_view, IDE, VIEW, GtkWidget)
+
+struct _IdeViewInterface
+{
+ GTypeInterface parent;
+
+ const gchar *(*get_title) (IdeView *self);
+ const gchar *(*get_icon_name) (IdeView *self);
+ gboolean (*get_can_save) (IdeView *self);
+ gboolean (*get_needs_attention) (IdeView *self);
+ void (*save_async) (IdeView *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*save_finish) (IdeView *self,
+ GAsyncResult *result,
+ GError **error);
+};
+
+const gchar *ide_view_get_title (IdeView *self);
+const gchar *ide_view_get_icon_name (IdeView *self);
+gboolean ide_view_get_can_save (IdeView *self);
+gboolean ide_view_get_needs_attention (IdeView *self);
+void ide_view_save_async (IdeView *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_view_save_finish (IdeView *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* IDE_VIEW_H */
diff --git a/libide/ide-workbench-addin.c b/libide/ide-workbench-addin.c
new file mode 100644
index 0000000..1cf1d61
--- /dev/null
+++ b/libide/ide-workbench-addin.c
@@ -0,0 +1,83 @@
+/* ide-workbench-addin.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-workbench-addin"
+
+#include "ide-workbench-addin.h"
+
+G_DEFINE_INTERFACE (IdeWorkbenchAddin, ide_workbench_addin, G_TYPE_OBJECT)
+
+static void
+ide_workbench_addin_real_load (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench)
+{
+}
+
+static void
+ide_workbench_addin_real_unload (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench)
+{
+}
+
+static void
+ide_workbench_addin_default_init (IdeWorkbenchAddinInterface *iface)
+{
+ iface->load = ide_workbench_addin_real_load;
+ iface->unload = ide_workbench_addin_real_unload;
+}
+
+/**
+ * ide_workbench_addin_load:
+ * @self: An #IdeWorkbenchAddin
+ * @workbench: An #IdeWorkbench
+ *
+ * This interface method is called to load @self. Addin implementations should add any
+ * required UI or actions to @workbench here. You should remove anything you've added
+ * in ide_workbench_addin_unload(), as that will be called when your plugin is deactivated
+ * or the workbench is in the destruction process.
+ */
+void
+ide_workbench_addin_load (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench)
+{
+ g_return_if_fail (IDE_IS_WORKBENCH_ADDIN (self));
+ g_return_if_fail (IDE_IS_WORKBENCH (workbench));
+
+ IDE_WORKBENCH_ADDIN_GET_IFACE (self)->load (self, workbench);
+}
+
+/**
+ * ide_workbench_addin_unload:
+ * @self: An #IdeWorkbenchAddin
+ * @workbench: An #IdeWorkbench
+ *
+ * This interface method should cleanup after anything added to @workbench in
+ * ide_workbench_addin_load().
+ *
+ * This might be called when a plugin is deactivated, or the workbench is in the
+ * destruction process.
+ */
+void
+ide_workbench_addin_unload (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench)
+{
+ g_return_if_fail (IDE_IS_WORKBENCH_ADDIN (self));
+ g_return_if_fail (IDE_IS_WORKBENCH (workbench));
+
+ IDE_WORKBENCH_ADDIN_GET_IFACE (self)->unload (self, workbench);
+}
diff --git a/libide/ide-workbench-addin.h b/libide/ide-workbench-addin.h
new file mode 100644
index 0000000..9897d2b
--- /dev/null
+++ b/libide/ide-workbench-addin.h
@@ -0,0 +1,47 @@
+/* ide-workbench-addin.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_WORKBENCH_ADDIN_H
+#define IDE_WORKBENCH_ADDIN_H
+
+#include "ide-workbench.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_WORKBENCH_ADDIN (ide_workbench_addin_get_type())
+
+G_DECLARE_INTERFACE (IdeWorkbenchAddin, ide_workbench_addin, IDE, WORKBENCH_ADDIN, GObject)
+
+struct _IdeWorkbenchAddinInterface
+{
+ GTypeInterface parent;
+
+ void (*load) (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench);
+ void (*unload) (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench);
+};
+
+void ide_workbench_addin_load (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench);
+void ide_workbench_addin_unload (IdeWorkbenchAddin *self,
+ IdeWorkbench *workbench);
+
+G_END_DECLS
+
+#endif /* IDE_WORKBENCH_ADDIN_H */
diff --git a/libide/ide-workbench-header-bar.c b/libide/ide-workbench-header-bar.c
new file mode 100644
index 0000000..75a159e
--- /dev/null
+++ b/libide/ide-workbench-header-bar.c
@@ -0,0 +1,58 @@
+/* ide-workbench-header-bar.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-workbench-header-bar"
+
+#include "ide-application.h"
+#include "ide-workbench-header-bar.h"
+
+typedef struct
+{
+ GtkMenuButton *menu_button;
+} IdeWorkbenchHeaderBarPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdeWorkbenchHeaderBar, ide_workbench_header_bar, GTK_TYPE_HEADER_BAR)
+
+GtkWidget *
+ide_workbench_header_bar_new (void)
+{
+ return g_object_new (IDE_TYPE_WORKBENCH_HEADER_BAR, NULL);
+}
+
+static void
+ide_workbench_header_bar_class_init (IdeWorkbenchHeaderBarClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/builder/ui/ide-workbench-header-bar.ui");
+ gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, menu_button);
+}
+
+static void
+ide_workbench_header_bar_init (IdeWorkbenchHeaderBar *self)
+{
+ IdeWorkbenchHeaderBarPrivate *priv = ide_workbench_header_bar_get_instance_private (self);
+ GtkWidget *popover;
+ GMenu *model;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ model = gtk_application_get_menu_by_id (GTK_APPLICATION (IDE_APPLICATION_DEFAULT), "gear-menu");
+ popover = gtk_popover_new_from_model (NULL, G_MENU_MODEL (model));
+ gtk_menu_button_set_popover (priv->menu_button, popover);
+}
diff --git a/src/greeter/gb-greeter-pill-box.h b/libide/ide-workbench-header-bar.h
similarity index 53%
rename from src/greeter/gb-greeter-pill-box.h
rename to libide/ide-workbench-header-bar.h
index 394a333..cb91fa9 100644
--- a/src/greeter/gb-greeter-pill-box.h
+++ b/libide/ide-workbench-header-bar.h
@@ -1,6 +1,6 @@
-/* gb-greeter-pill-box.h
+/* ide-workbench-header-bar.h
*
- * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 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
@@ -16,22 +16,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GB_GREETER_PILL_BOX_H
-#define GB_GREETER_PILL_BOX_H
+#ifndef IDE_WORKBENCH_HEADER_BAR_H
+#define IDE_WORKBENCH_HEADER_BAR_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
-#define GB_TYPE_GREETER_PILL_BOX (gb_greeter_pill_box_get_type())
+#define IDE_TYPE_WORKBENCH_HEADER_BAR (ide_workbench_header_bar_get_type())
-G_DECLARE_FINAL_TYPE (GbGreeterPillBox, gb_greeter_pill_box, GB, GREETER_PILL_BOX, GtkEventBox)
+G_DECLARE_DERIVABLE_TYPE (IdeWorkbenchHeaderBar, ide_workbench_header_bar, IDE, WORKBENCH_HEADER_BAR,
GtkHeaderBar)
-GtkWidget *gb_greeter_pill_box_new (const gchar *label);
-const gchar *gb_greeter_pill_box_get_label (GbGreeterPillBox *self);
-void gb_greeter_pill_box_set_label (GbGreeterPillBox *self,
- const gchar *label);
+struct _IdeWorkbenchHeaderBarClass
+{
+ GtkHeaderBarClass parent;
+};
+
+GtkWidget *ide_workbench_header_bar_new (void);
G_END_DECLS
-#endif /* GB_GREETER_PILL_BOX_H */
+#endif /* IDE_WORKBENCH_HEADER_BAR_H */
diff --git a/libide/ide-workbench.c b/libide/ide-workbench.c
new file mode 100644
index 0000000..a9739b6
--- /dev/null
+++ b/libide/ide-workbench.c
@@ -0,0 +1,323 @@
+/* ide-workbench.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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-workbench"
+
+#include <libpeas/peas.h>
+
+#include "ide-macros.h"
+#include "ide-greeter-perspective.h"
+#include "ide-workbench.h"
+#include "ide-workbench-header-bar.h"
+
+struct _IdeWorkbench
+{
+ GtkApplicationWindow parent;
+
+ IdeContext *context;
+
+ IdePerspective *perspective;
+
+ GtkStack *header_bar_stack;
+ IdeGreeterPerspective *greeter_perspective;
+ GtkStack *perspectives_stack;
+ GtkStackSwitcher *perspectives_stack_switcher;
+};
+
+typedef struct
+{
+ GtkCallback callback;
+ gpointer user_data;
+} IdeWorkbenchForeach;
+
+G_DEFINE_TYPE (IdeWorkbench, ide_workbench, GTK_TYPE_APPLICATION_WINDOW)
+
+enum {
+ PROP_0,
+ PROP_PERSPECTIVE,
+ LAST_PROP
+};
+
+static GParamSpec *properties [LAST_PROP];
+
+static void
+ide_workbench_perspective_changed (IdeWorkbench *self,
+ GParamSpec *pspec,
+ GtkStack *stack)
+{
+ IdePerspective *perspective;
+ GtkWidget *titlebar = NULL;
+
+ g_assert (IDE_IS_WORKBENCH (self));
+ g_assert (GTK_IS_STACK (stack));
+ g_assert (stack == self->perspectives_stack);
+
+ perspective = IDE_PERSPECTIVE (gtk_stack_get_visible_child (stack));
+
+ if (perspective != NULL)
+ titlebar = ide_perspective_get_titlebar (perspective);
+
+ if (titlebar == NULL)
+ titlebar = ide_workbench_header_bar_new ();
+
+ g_assert (titlebar != NULL);
+ g_assert (GTK_IS_WIDGET (titlebar));
+
+ gtk_widget_show (GTK_WIDGET (titlebar));
+
+ gtk_window_set_titlebar (GTK_WINDOW (self), titlebar);
+}
+
+static void
+ide_workbench_finalize (GObject *object)
+{
+ IdeWorkbench *self = (IdeWorkbench *)object;
+
+ ide_clear_weak_pointer (&self->perspective);
+ g_clear_object (&self->context);
+
+ G_OBJECT_CLASS (ide_workbench_parent_class)->finalize (object);
+}
+
+static void
+ide_workbench_constructed (GObject *object)
+{
+ IdeWorkbench *self = (IdeWorkbench *)object;
+
+ G_OBJECT_CLASS (ide_workbench_parent_class)->constructed (object);
+}
+
+static void
+ide_workbench_destroy (GtkWidget *widget)
+{
+ IdeWorkbench *self = (IdeWorkbench *)widget;
+
+ g_assert (IDE_IS_WORKBENCH (self));
+
+ GTK_WIDGET_CLASS (ide_workbench_parent_class)->destroy (widget);
+}
+
+static void
+ide_workbench_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeWorkbench *self = IDE_WORKBENCH (object);
+
+ switch (prop_id)
+ {
+ case PROP_PERSPECTIVE:
+ g_value_set_object (value, ide_workbench_get_perspective (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_workbench_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeWorkbench *self = IDE_WORKBENCH (object);
+
+ switch (prop_id)
+ {
+ case PROP_PERSPECTIVE:
+ ide_workbench_set_perspective (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_workbench_class_init (IdeWorkbenchClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->constructed = ide_workbench_constructed;
+ object_class->finalize = ide_workbench_finalize;
+ object_class->get_property = ide_workbench_get_property;
+ object_class->set_property = ide_workbench_set_property;
+
+ widget_class->destroy = ide_workbench_destroy;
+
+ properties [PROP_PERSPECTIVE] =
+ g_param_spec_object ("perspective",
+ "Perspective",
+ "Perspective",
+ IDE_TYPE_PERSPECTIVE,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/builder/ui/ide-workbench.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, header_bar_stack);
+ gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, perspectives_stack);
+ gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, perspectives_stack_switcher);
+}
+
+static void
+ide_workbench_init_greeter (IdeWorkbench *self)
+{
+ g_assert (IDE_IS_WORKBENCH (self));
+
+ self->greeter_perspective = g_object_new (IDE_TYPE_GREETER_PERSPECTIVE,
+ "visible", TRUE,
+ NULL);
+ ide_workbench_add_perspective (self, IDE_PERSPECTIVE (self->greeter_perspective));
+}
+
+static void
+ide_workbench_init (IdeWorkbench *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ g_signal_connect_object (self->perspectives_stack,
+ "notify::visible-child",
+ G_CALLBACK (ide_workbench_perspective_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
+ ide_workbench_init_greeter (self);
+}
+
+static void
+ide_workbench_views_foreach_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ IdeWorkbenchForeach *foreach_data = user_data;
+
+ g_assert (foreach_data);
+ g_assert (foreach_data->callback);
+
+ foreach_data->callback (widget, foreach_data->user_data);
+}
+
+/**
+ * ide_workbench_views_foreach:
+ * @self: An #IdeWorkbench.
+ * @callback: (scope call): The callback to execute
+ * @user_data: user data for @callback.
+ *
+ * Executes @callback for every #IdeView across all perspectives.
+ */
+void
+ide_workbench_views_foreach (IdeWorkbench *self,
+ GtkCallback callback,
+ gpointer user_data)
+{
+ IdeWorkbenchForeach foreach = { callback, user_data };
+
+ g_return_if_fail (IDE_IS_WORKBENCH (self));
+ g_return_if_fail (callback != NULL);
+
+ gtk_container_foreach (GTK_CONTAINER (self->perspectives_stack),
+ ide_workbench_views_foreach_cb,
+ &foreach);
+}
+
+/**
+ * ide_workbench_get_context:
+ * @self: An #IdeWorkbench.
+ *
+ * Gets the context associated with the workbench, or %NULL.
+ *
+ * Returns: (transfer none) (nullable): An #IdeContext or %NULL.
+ */
+IdeContext *
+ide_workbench_get_context (IdeWorkbench *self)
+{
+ g_return_val_if_fail (IDE_IS_WORKBENCH (self), NULL);
+
+ return self->context;
+}
+
+void
+ide_workbench_add_perspective (IdeWorkbench *self,
+ IdePerspective *perspective)
+{
+ const gchar *title;
+ const gchar *icon_name;
+
+ g_assert (IDE_IS_WORKBENCH (self));
+ g_assert (IDE_IS_PERSPECTIVE (perspective));
+
+ title = ide_perspective_get_title (perspective);
+ icon_name = ide_perspective_get_icon_name (perspective);
+
+ gtk_container_add_with_properties (GTK_CONTAINER (self->perspectives_stack),
+ GTK_WIDGET (perspective),
+ "icon-name", icon_name,
+ "needs-attention", FALSE,
+ "title", title,
+ NULL);
+}
+
+void
+ide_workbench_remove_perspective (IdeWorkbench *self,
+ IdePerspective *perspective)
+{
+ g_assert (IDE_IS_WORKBENCH (self));
+ g_assert (IDE_IS_PERSPECTIVE (perspective));
+ g_assert (gtk_widget_get_parent (GTK_WIDGET (perspective)) ==
+ GTK_WIDGET (self->perspectives_stack));
+
+ gtk_container_remove (GTK_CONTAINER (self->perspectives_stack),
+ GTK_WIDGET (perspective));
+}
+
+/**
+ * ide_workbench_get_perspective:
+ * @self: An #IdeWorkbench.
+ *
+ * Gets the current perspective.
+ *
+ * Returns: (transfer none): An #IdePerspective.
+ */
+IdePerspective *
+ide_workbench_get_perspective (IdeWorkbench *self)
+{
+ GtkWidget *visible_child;
+
+ g_return_val_if_fail (IDE_IS_WORKBENCH (self), NULL);
+
+ visible_child = gtk_stack_get_visible_child (self->perspectives_stack);
+
+ return IDE_PERSPECTIVE (visible_child);
+}
+
+void
+ide_workbench_set_perspective (IdeWorkbench *self,
+ IdePerspective *perspective)
+{
+ g_return_if_fail (IDE_IS_WORKBENCH (self));
+ g_return_if_fail (IDE_IS_PERSPECTIVE (perspective));
+ g_return_if_fail (GTK_WIDGET (self->perspectives_stack) ==
+ gtk_widget_get_parent (GTK_WIDGET (perspective)));
+
+ gtk_stack_set_visible_child (self->perspectives_stack, GTK_WIDGET (perspective));
+}
diff --git a/libide/ide-workbench.h b/libide/ide-workbench.h
new file mode 100644
index 0000000..af22553
--- /dev/null
+++ b/libide/ide-workbench.h
@@ -0,0 +1,69 @@
+/* ide-workbench.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_WORKBENCH_H
+#define IDE_WORKBENCH_H
+
+#include <gtk/gtk.h>
+
+#include "ide-context.h"
+#include "ide-perspective.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_WORKBENCH (ide_workbench_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeWorkbench, ide_workbench, IDE, WORKBENCH, GtkApplicationWindow)
+
+void ide_workbench_open_async (IdeWorkbench *self,
+ GFile **files,
+ gint n_files,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_workbench_open_finish (IdeWorkbench *self,
+ GAsyncResult *result,
+ GError **error);
+void ide_workbench_save_all_async (IdeWorkbench *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_workbench_save_all_finish (IdeWorkbench *self,
+ GAsyncResult *result,
+ GError **error);
+void ide_workbench_focus (IdeWorkbench *self,
+ GtkWidget *widget);
+void ide_workbench_close (IdeWorkbench *self);
+IdeContext *ide_workbench_get_context (IdeWorkbench *self);
+void ide_workbench_add_perspective (IdeWorkbench *self,
+ IdePerspective *perspective);
+void ide_workbench_remove_perspective (IdeWorkbench *self,
+ IdePerspective *perspective);
+IdePerspective *ide_workbench_get_perspective (IdeWorkbench *self);
+void ide_workbench_set_perspective (IdeWorkbench *self,
+ IdePerspective *perspective);
+gboolean ide_workbench_get_fullscreen (IdeWorkbench *self);
+void ide_workbench_set_fullscreen (IdeWorkbench *self,
+ gboolean fullscreen);
+void ide_workbench_views_foreach (IdeWorkbench *self,
+ GtkCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* IDE_WORKBENCH_H */
diff --git a/libide/ide.c b/libide/ide.c
index d1ff190..eb84919 100644
--- a/libide/ide.c
+++ b/libide/ide.c
@@ -18,7 +18,6 @@
#include <girepository.h>
#include <glib/gi18n.h>
-#include <libgit2-glib/ggit.h>
#include <stdlib.h>
#include "gconstructor.h"
@@ -30,9 +29,6 @@
#include "ide-git-vcs.h"
#include "ide-gsettings-file-settings.h"
#include "ide-modelines-file-settings.h"
-#include "ide-internal.h"
-#include "ide-project-miner.h"
-#include "ide-search-provider.h"
#ifdef ENABLE_GJS_SCRIPTING
# include "ide-gjs-script.h"
@@ -42,8 +38,6 @@
# include "ide-pygobject-script.h"
#endif
-#include "modeline-parser.h"
-
static gboolean programNameRead;
static const gchar *programName = "libide";
@@ -78,13 +72,6 @@ ide_set_program_name (const gchar *program_name)
static void
ide_init_ctor (void)
{
- GgitFeatureFlags ggit_flags;
-
- g_irepository_prepend_search_path (LIBDIR"/gnome-builder/girepository-1.0");
-
- g_type_ensure (IDE_TYPE_CONTEXT);
- g_type_ensure (IDE_TYPE_VCS);
-
g_io_extension_point_register (IDE_FILE_SETTINGS_EXTENSION_POINT);
g_io_extension_point_register (IDE_SCRIPT_EXTENSION_POINT);
g_io_extension_point_register (IDE_VCS_EXTENSION_POINT);
@@ -124,27 +111,4 @@ ide_init_ctor (void)
IDE_TYPE_DIRECTORY_VCS,
IDE_VCS_EXTENSION_POINT".directory",
-200);
-
- modeline_parser_init ();
-
- ggit_init ();
-
- ggit_flags = ggit_get_features ();
-
- if ((ggit_flags & GGIT_FEATURE_THREADS) == 0)
- {
- g_error (_("Builder requires libgit2-glib with threading support."));
- exit (EXIT_FAILURE);
- }
-
- if ((ggit_flags & GGIT_FEATURE_SSH) == 0)
- {
- g_error (_("Builder requires libgit2-glib with SSH support."));
- exit (EXIT_FAILURE);
- }
-
- /* TODO: tune what we startup here once we have IdeApplication/IdeWorkbench/etc. */
- _ide_thread_pool_init ();
-
- _ide_battery_monitor_init ();
}
diff --git a/libide/ide.h b/libide/ide.h
index b6bd696..f50106c 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -25,6 +25,7 @@ G_BEGIN_DECLS
#define IDE_INSIDE
+#include "ide-application.h"
#include "ide-back-forward-item.h"
#include "ide-back-forward-list.h"
#include "ide-build-result.h"
@@ -56,10 +57,14 @@ G_BEGIN_DECLS
#include "ide-highlight-engine.h"
#include "ide-highlighter.h"
#include "ide-indenter.h"
+#include "ide-layout-manager.h"
#include "ide-log.h"
#include "ide-macros.h"
#include "ide-object.h"
#include "ide-pattern-spec.h"
+#include "ide-perspective.h"
+#include "ide-preferences.h"
+#include "ide-preferences-addin.h"
#include "ide-process.h"
#include "ide-progress.h"
#include "ide-project.h"
@@ -96,6 +101,7 @@ G_BEGIN_DECLS
#include "ide-unsaved-files.h"
#include "ide-vcs.h"
#include "ide-vcs-uri.h"
+#include "ide-workbench.h"
#include "directory/ide-directory-vcs.h"
#include "doap/ide-doap-person.h"
diff --git a/libide/resources/libide.gresource.xml b/libide/resources/libide.gresource.xml
index 647b0ae..a073b1f 100644
--- a/libide/resources/libide.gresource.xml
+++ b/libide/resources/libide.gresource.xml
@@ -18,5 +18,12 @@
<file alias="keybindings/emacs.css">../../data/keybindings/emacs.css</file>
<file alias="keybindings/vim.css">../../data/keybindings/vim.css</file>
+
+ </gresource>
+
+ <gresource prefix="/org/gnome/builder">
+ <file alias="ui/ide-greeter-perspective.ui">../../data/ui/ide-greeter-perspective.ui</file>
+ <file alias="ui/ide-workbench.ui">../../data/ui/ide-workbench.ui</file>
+ <file alias="ui/ide-workbench-header-bar.ui">../../data/ui/ide-workbench-header-bar.ui</file>
</gresource>
</gresources>
diff --git a/src/Makefile.am b/src/Makefile.am
index 4e90e31..e6bb8e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,8 +80,6 @@ libgnome_builder_la_SOURCES = \
editor/gb-editor-view-actions.h \
editor/gb-editor-view-addin-private.h \
editor/gb-editor-view-private.h \
- greeter/gb-greeter-pill-box.c \
- greeter/gb-greeter-pill-box.h \
greeter/gb-greeter-project-row.c \
greeter/gb-greeter-project-row.h \
greeter/gb-greeter-window.c \
diff --git a/src/greeter/gb-greeter-project-row.c b/src/greeter/gb-greeter-project-row.c
index fe353d8..da4459a 100644
--- a/src/greeter/gb-greeter-project-row.c
+++ b/src/greeter/gb-greeter-project-row.c
@@ -22,10 +22,10 @@
#include <ide.h>
#include "egg-binding-group.h"
+#include "egg-pill-box.h"
#include "gb-glib.h"
#include "gb-greeter-project-row.h"
-#include "gb-greeter-pill-box.h"
struct _GbGreeterProjectRow
{
@@ -135,7 +135,7 @@ gb_greeter_project_row_add_languages (GbGreeterProjectRow *self,
const gchar *name = languages [i - 1];
GtkWidget *pill;
- pill = g_object_new (GB_TYPE_GREETER_PILL_BOX,
+ pill = g_object_new (EGG_TYPE_PILL_BOX,
"visible", TRUE,
"label", name,
NULL);
diff --git a/src/main.c b/src/main.c
index fc04523..175851b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,7 +28,6 @@
#include <ide.h>
#include <locale.h>
-#include "gb-application.h"
#include "gb-icons-resources.h"
int
@@ -58,7 +57,7 @@ main (int argc,
g_resources_register (gb_icons_get_resource ());
- app = g_object_new (GB_TYPE_APPLICATION,
+ app = g_object_new (IDE_TYPE_APPLICATION,
"application-id", "org.gnome.Builder",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
diff --git a/src/resources/gnome-builder.gresource.xml b/src/resources/gnome-builder.gresource.xml
index 18862b5..3cf649e 100644
--- a/src/resources/gnome-builder.gresource.xml
+++ b/src/resources/gnome-builder.gresource.xml
@@ -21,7 +21,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-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>
<file alias="ui/gb-html-view.ui">../../data/ui/gb-html-view.ui</file>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]