1639 lines
50 KiB
C
1639 lines
50 KiB
C
/*
|
|
* Copyright © 2001 Havoc Pennington
|
|
* Copyright © 2002 Mathias Hasselmann
|
|
* Copyright © 2008 Christian Persch
|
|
*
|
|
* Mate-terminal 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.
|
|
*
|
|
* Mate-terminal 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 <config.h>
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "terminal-app.h"
|
|
#include "terminal-debug.h"
|
|
#include "terminal-intl.h"
|
|
#include "terminal-profile.h"
|
|
#include "terminal-screen.h"
|
|
#include "terminal-type-builtins.h"
|
|
|
|
/* To add a new key, you need to:
|
|
*
|
|
* - add an entry to the enum below
|
|
* - add a #define with its name in terminal-profile.h
|
|
* - add a gobject property for it in terminal_profile_class_init
|
|
* - if the property's type needs special casing, add that to
|
|
* terminal_profile_gsettings_notify_cb and
|
|
* terminal_profile_gsettings_changeset_add
|
|
* - if necessary the default value cannot be handled via the paramspec,
|
|
* handle that in terminal_profile_reset_property_internal
|
|
*/
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_ALLOW_BOLD,
|
|
PROP_BACKGROUND_COLOR,
|
|
PROP_BACKGROUND_DARKNESS,
|
|
PROP_BACKGROUND_IMAGE,
|
|
PROP_BACKGROUND_IMAGE_FILE,
|
|
PROP_BACKGROUND_TYPE,
|
|
PROP_BACKSPACE_BINDING,
|
|
PROP_BOLD_COLOR,
|
|
PROP_BOLD_COLOR_SAME_AS_FG,
|
|
PROP_CURSOR_BLINK_MODE,
|
|
PROP_CURSOR_SHAPE,
|
|
PROP_CUSTOM_COMMAND,
|
|
PROP_DEFAULT_SIZE_COLUMNS,
|
|
PROP_DEFAULT_SIZE_ROWS,
|
|
PROP_DEFAULT_SHOW_MENUBAR,
|
|
PROP_DELETE_BINDING,
|
|
PROP_EXIT_ACTION,
|
|
PROP_FONT,
|
|
PROP_FOREGROUND_COLOR,
|
|
PROP_LOGIN_SHELL,
|
|
PROP_NAME,
|
|
PROP_PALETTE,
|
|
PROP_SCROLL_BACKGROUND,
|
|
PROP_SCROLLBACK_LINES,
|
|
PROP_SCROLLBACK_UNLIMITED,
|
|
PROP_SCROLLBAR_POSITION,
|
|
PROP_SCROLL_ON_KEYSTROKE,
|
|
PROP_SCROLL_ON_OUTPUT,
|
|
PROP_SILENT_BELL,
|
|
PROP_TITLE,
|
|
PROP_TITLE_MODE,
|
|
PROP_UPDATE_RECORDS,
|
|
PROP_USE_CUSTOM_COMMAND,
|
|
PROP_USE_CUSTOM_DEFAULT_SIZE,
|
|
PROP_USE_SKEY,
|
|
PROP_USE_SYSTEM_FONT,
|
|
PROP_USE_THEME_COLORS,
|
|
PROP_VISIBLE_NAME,
|
|
PROP_WORD_CHARS,
|
|
PROP_COPY_SELECTION,
|
|
LAST_PROP
|
|
};
|
|
|
|
#define KEY_ALLOW_BOLD "allow-bold"
|
|
#define KEY_BACKGROUND_COLOR "background-color"
|
|
#define KEY_BACKGROUND_DARKNESS "background-darkness"
|
|
#define KEY_BACKGROUND_IMAGE_FILE "background-image"
|
|
#define KEY_BACKGROUND_TYPE "background-type"
|
|
#define KEY_BACKSPACE_BINDING "backspace-binding"
|
|
#define KEY_BOLD_COLOR "bold-color"
|
|
#define KEY_BOLD_COLOR_SAME_AS_FG "bold-color-same-as-fg"
|
|
#define KEY_CURSOR_BLINK_MODE "cursor-blink-mode"
|
|
#define KEY_CURSOR_SHAPE "cursor-shape"
|
|
#define KEY_CUSTOM_COMMAND "custom-command"
|
|
#define KEY_DEFAULT_SHOW_MENUBAR "default-show-menubar"
|
|
#define KEY_DEFAULT_SIZE_COLUMNS "default-size-columns"
|
|
#define KEY_DEFAULT_SIZE_ROWS "default-size-rows"
|
|
#define KEY_DELETE_BINDING "delete-binding"
|
|
#define KEY_EXIT_ACTION "exit-action"
|
|
#define KEY_FONT "font"
|
|
#define KEY_FOREGROUND_COLOR "foreground-color"
|
|
#define KEY_LOGIN_SHELL "login-shell"
|
|
#define KEY_PALETTE "palette"
|
|
#define KEY_SCROLL_BACKGROUND "scroll-background"
|
|
#define KEY_SCROLLBACK_LINES "scrollback-lines"
|
|
#define KEY_SCROLLBACK_UNLIMITED "scrollback-unlimited"
|
|
#define KEY_SCROLLBAR_POSITION "scrollbar-position"
|
|
#define KEY_SCROLL_ON_KEYSTROKE "scroll-on-keystroke"
|
|
#define KEY_SCROLL_ON_OUTPUT "scroll-on-output"
|
|
#define KEY_SILENT_BELL "silent-bell"
|
|
#define KEY_COPY_SELECTION "copy-selection"
|
|
#define KEY_TITLE_MODE "title-mode"
|
|
#define KEY_TITLE "title"
|
|
#define KEY_UPDATE_RECORDS "update-records"
|
|
#define KEY_USE_CUSTOM_COMMAND "use-custom-command"
|
|
#define KEY_USE_CUSTOM_DEFAULT_SIZE "use-custom-default-size"
|
|
#define KEY_USE_SKEY "use-skey"
|
|
#define KEY_USE_SYSTEM_FONT "use-system-font"
|
|
#define KEY_USE_THEME_COLORS "use-theme-colors"
|
|
#define KEY_VISIBLE_NAME "visible-name"
|
|
#define KEY_WORD_CHARS "word-chars"
|
|
|
|
/* Keep these in sync with the GSettings schema! */
|
|
#define DEFAULT_ALLOW_BOLD (TRUE)
|
|
#define DEFAULT_BACKGROUND_COLOR ("#FFFFDD")
|
|
#define DEFAULT_BOLD_COLOR_SAME_AS_FG (TRUE)
|
|
#define DEFAULT_BACKGROUND_DARKNESS (0.5)
|
|
#define DEFAULT_BACKGROUND_IMAGE_FILE ("")
|
|
#define DEFAULT_BACKGROUND_IMAGE (NULL)
|
|
#define DEFAULT_BACKGROUND_TYPE (TERMINAL_BACKGROUND_SOLID)
|
|
#define DEFAULT_BACKSPACE_BINDING (VTE_ERASE_ASCII_DELETE)
|
|
#define DEFAULT_CURSOR_BLINK_MODE (VTE_CURSOR_BLINK_SYSTEM)
|
|
#define DEFAULT_CURSOR_SHAPE (VTE_CURSOR_SHAPE_BLOCK)
|
|
#define DEFAULT_CUSTOM_COMMAND ("")
|
|
#define DEFAULT_DEFAULT_SHOW_MENUBAR (TRUE)
|
|
#define DEFAULT_DEFAULT_SIZE_COLUMNS (80)
|
|
#define DEFAULT_DEFAULT_SIZE_ROWS (24)
|
|
#define DEFAULT_DELETE_BINDING (VTE_ERASE_DELETE_SEQUENCE)
|
|
#define DEFAULT_EXIT_ACTION (TERMINAL_EXIT_CLOSE)
|
|
#define DEFAULT_FONT ("Monospace 12")
|
|
#define DEFAULT_FOREGROUND_COLOR ("#000000")
|
|
#define DEFAULT_LOGIN_SHELL (FALSE)
|
|
#define DEFAULT_NAME (NULL)
|
|
#define DEFAULT_PALETTE (terminal_palettes[TERMINAL_PALETTE_TANGO])
|
|
#define DEFAULT_SCROLL_BACKGROUND (TRUE)
|
|
#define DEFAULT_SCROLLBACK_LINES (512)
|
|
#define DEFAULT_SCROLLBACK_UNLIMITED (FALSE)
|
|
#define DEFAULT_SCROLLBAR_POSITION (TERMINAL_SCROLLBAR_RIGHT)
|
|
#define DEFAULT_SCROLL_ON_KEYSTROKE (TRUE)
|
|
#define DEFAULT_SCROLL_ON_OUTPUT (FALSE)
|
|
#define DEFAULT_SILENT_BELL (FALSE)
|
|
#define DEFAULT_COPY_SELECTION (FALSE)
|
|
#define DEFAULT_TITLE_MODE (TERMINAL_TITLE_REPLACE)
|
|
#define DEFAULT_TITLE (N_("Terminal"))
|
|
#define DEFAULT_UPDATE_RECORDS (TRUE)
|
|
#define DEFAULT_USE_CUSTOM_COMMAND (FALSE)
|
|
#define DEFAULT_USE_CUSTOM_DEFAULT_SIZE (FALSE)
|
|
#define DEFAULT_USE_SKEY (TRUE)
|
|
#define DEFAULT_USE_SYSTEM_FONT (TRUE)
|
|
#define DEFAULT_USE_THEME_COLORS (TRUE)
|
|
#define DEFAULT_VISIBLE_NAME (N_("Unnamed"))
|
|
#define DEFAULT_WORD_CHARS ("-A-Za-z0-9,./?%&#:_=+@~")
|
|
|
|
struct _TerminalProfilePrivate
|
|
{
|
|
GValueArray *properties;
|
|
gboolean *locked;
|
|
|
|
GSettings *settings;
|
|
char *profile_dir;
|
|
|
|
GSList *dirty_pspecs;
|
|
guint save_idle_id;
|
|
|
|
GParamSpec *gsettings_notification_pspec;
|
|
|
|
gboolean background_load_failed;
|
|
|
|
guint forgotten : 1;
|
|
};
|
|
|
|
static const GdkColor terminal_palettes[TERMINAL_PALETTE_N_BUILTINS][TERMINAL_PALETTE_SIZE] =
|
|
{
|
|
/* Tango palette */
|
|
{
|
|
{ 0, 0x0000, 0x0000, 0x0000 },
|
|
{ 0, 0xcccc, 0x0000, 0x0000 },
|
|
{ 0, 0x4e4e, 0x9a9a, 0x0606 },
|
|
{ 0, 0xc4c4, 0xa0a0, 0x0000 },
|
|
{ 0, 0x3434, 0x6565, 0xa4a4 },
|
|
{ 0, 0x7575, 0x5050, 0x7b7b },
|
|
{ 0, 0x0606, 0x9820, 0x9a9a },
|
|
{ 0, 0xd3d3, 0xd7d7, 0xcfcf },
|
|
{ 0, 0x5555, 0x5757, 0x5353 },
|
|
{ 0, 0xefef, 0x2929, 0x2929 },
|
|
{ 0, 0x8a8a, 0xe2e2, 0x3434 },
|
|
{ 0, 0xfcfc, 0xe9e9, 0x4f4f },
|
|
{ 0, 0x7272, 0x9f9f, 0xcfcf },
|
|
{ 0, 0xadad, 0x7f7f, 0xa8a8 },
|
|
{ 0, 0x3434, 0xe2e2, 0xe2e2 },
|
|
{ 0, 0xeeee, 0xeeee, 0xecec }
|
|
},
|
|
|
|
/* Linux palette */
|
|
{
|
|
{ 0, 0x0000, 0x0000, 0x0000 },
|
|
{ 0, 0xaaaa, 0x0000, 0x0000 },
|
|
{ 0, 0x0000, 0xaaaa, 0x0000 },
|
|
{ 0, 0xaaaa, 0x5555, 0x0000 },
|
|
{ 0, 0x0000, 0x0000, 0xaaaa },
|
|
{ 0, 0xaaaa, 0x0000, 0xaaaa },
|
|
{ 0, 0x0000, 0xaaaa, 0xaaaa },
|
|
{ 0, 0xaaaa, 0xaaaa, 0xaaaa },
|
|
{ 0, 0x5555, 0x5555, 0x5555 },
|
|
{ 0, 0xffff, 0x5555, 0x5555 },
|
|
{ 0, 0x5555, 0xffff, 0x5555 },
|
|
{ 0, 0xffff, 0xffff, 0x5555 },
|
|
{ 0, 0x5555, 0x5555, 0xffff },
|
|
{ 0, 0xffff, 0x5555, 0xffff },
|
|
{ 0, 0x5555, 0xffff, 0xffff },
|
|
{ 0, 0xffff, 0xffff, 0xffff }
|
|
},
|
|
|
|
/* XTerm palette */
|
|
{
|
|
{ 0, 0x0000, 0x0000, 0x0000 },
|
|
{ 0, 0xcdcb, 0x0000, 0x0000 },
|
|
{ 0, 0x0000, 0xcdcb, 0x0000 },
|
|
{ 0, 0xcdcb, 0xcdcb, 0x0000 },
|
|
{ 0, 0x1e1a, 0x908f, 0xffff },
|
|
{ 0, 0xcdcb, 0x0000, 0xcdcb },
|
|
{ 0, 0x0000, 0xcdcb, 0xcdcb },
|
|
{ 0, 0xe5e2, 0xe5e2, 0xe5e2 },
|
|
{ 0, 0x4ccc, 0x4ccc, 0x4ccc },
|
|
{ 0, 0xffff, 0x0000, 0x0000 },
|
|
{ 0, 0x0000, 0xffff, 0x0000 },
|
|
{ 0, 0xffff, 0xffff, 0x0000 },
|
|
{ 0, 0x4645, 0x8281, 0xb4ae },
|
|
{ 0, 0xffff, 0x0000, 0xffff },
|
|
{ 0, 0x0000, 0xffff, 0xffff },
|
|
{ 0, 0xffff, 0xffff, 0xffff }
|
|
},
|
|
|
|
/* RXVT palette */
|
|
{
|
|
{ 0, 0x0000, 0x0000, 0x0000 },
|
|
{ 0, 0xcdcd, 0x0000, 0x0000 },
|
|
{ 0, 0x0000, 0xcdcd, 0x0000 },
|
|
{ 0, 0xcdcd, 0xcdcd, 0x0000 },
|
|
{ 0, 0x0000, 0x0000, 0xcdcd },
|
|
{ 0, 0xcdcd, 0x0000, 0xcdcd },
|
|
{ 0, 0x0000, 0xcdcd, 0xcdcd },
|
|
{ 0, 0xfafa, 0xebeb, 0xd7d7 },
|
|
{ 0, 0x4040, 0x4040, 0x4040 },
|
|
{ 0, 0xffff, 0x0000, 0x0000 },
|
|
{ 0, 0x0000, 0xffff, 0x0000 },
|
|
{ 0, 0xffff, 0xffff, 0x0000 },
|
|
{ 0, 0x0000, 0x0000, 0xffff },
|
|
{ 0, 0xffff, 0x0000, 0xffff },
|
|
{ 0, 0x0000, 0xffff, 0xffff },
|
|
{ 0, 0xffff, 0xffff, 0xffff }
|
|
}
|
|
};
|
|
|
|
static const GdkColor default_fg_color = { 0, 0, 0, 0 };
|
|
static const GdkColor default_bg_color = { 0, 0xffff, 0xffff, 0xdddd };
|
|
|
|
enum
|
|
{
|
|
FORGOTTEN,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static void terminal_profile_finalize (GObject *object);
|
|
static void terminal_profile_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void ensure_pixbuf_property (TerminalProfile *profile,
|
|
guint path_prop_id,
|
|
guint pixbuf_prop_id,
|
|
gboolean *load_failed);
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
static GQuark gsettings_key_quark;
|
|
|
|
G_DEFINE_TYPE (TerminalProfile, terminal_profile, G_TYPE_OBJECT);
|
|
|
|
static gboolean
|
|
palette_cmp (const GdkColor *ca,
|
|
const GdkColor *cb)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < TERMINAL_PALETTE_SIZE; ++i)
|
|
if (!gdk_color_equal (&ca[i], &cb[i]))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GParamSpec *
|
|
get_pspec_from_name (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
TerminalProfileClass *klass = TERMINAL_PROFILE_GET_CLASS (profile);
|
|
GParamSpec *pspec;
|
|
|
|
pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), prop_name);
|
|
if (pspec &&
|
|
pspec->owner_type != TERMINAL_TYPE_PROFILE)
|
|
pspec = NULL;
|
|
|
|
return pspec;
|
|
}
|
|
|
|
static const GValue *
|
|
get_prop_value_from_prop_name (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GParamSpec *pspec;
|
|
|
|
pspec = get_pspec_from_name (profile, prop_name);
|
|
if (!pspec)
|
|
return NULL;
|
|
|
|
if (G_UNLIKELY (pspec->param_id == PROP_BACKGROUND_IMAGE))
|
|
ensure_pixbuf_property (profile, PROP_BACKGROUND_IMAGE_FILE, PROP_BACKGROUND_IMAGE, &priv->background_load_failed);
|
|
|
|
return g_value_array_get_nth (priv->properties, pspec->param_id);
|
|
}
|
|
|
|
static void
|
|
set_value_from_palette (GValue *ret_value,
|
|
const GdkColor *colors,
|
|
guint n_colors)
|
|
{
|
|
GValueArray *array;
|
|
guint i, max_n_colors;
|
|
|
|
max_n_colors = MAX (n_colors, TERMINAL_PALETTE_SIZE);
|
|
array = g_value_array_new (max_n_colors);
|
|
for (i = 0; i < max_n_colors; ++i)
|
|
g_value_array_append (array, NULL);
|
|
|
|
for (i = 0; i < n_colors; ++i)
|
|
{
|
|
GValue *value = g_value_array_get_nth (array, i);
|
|
|
|
g_value_init (value, GDK_TYPE_COLOR);
|
|
g_value_set_boxed (value, &colors[i]);
|
|
}
|
|
|
|
/* If we haven't enough colours yet, fill up with the default palette */
|
|
for (i = n_colors; i < TERMINAL_PALETTE_SIZE; ++i)
|
|
{
|
|
GValue *value = g_value_array_get_nth (array, i);
|
|
|
|
g_value_init (value, GDK_TYPE_COLOR);
|
|
g_value_set_boxed (value, &DEFAULT_PALETTE[i]);
|
|
}
|
|
|
|
g_value_take_boxed (ret_value, array);
|
|
}
|
|
|
|
static int
|
|
values_equal (GParamSpec *pspec,
|
|
const GValue *va,
|
|
const GValue *vb)
|
|
{
|
|
/* g_param_values_cmp isn't good enough for some types, since e.g.
|
|
* it compares colours and font descriptions by pointer value, not
|
|
* with the correct compare functions. Providing extra
|
|
* PangoParamSpecFontDescription and GdkParamSpecColor wouldn't
|
|
* have fixed this either, since it's unclear how to _order_ them.
|
|
* Luckily we only need to check them for equality here.
|
|
*/
|
|
|
|
if (g_param_values_cmp (pspec, va, vb) == 0)
|
|
return TRUE;
|
|
|
|
if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
|
|
return gdk_color_equal (g_value_get_boxed (va), g_value_get_boxed (vb));
|
|
|
|
if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
|
|
return pango_font_description_equal (g_value_get_boxed (va), g_value_get_boxed (vb));
|
|
|
|
if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
|
|
G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
|
|
{
|
|
GValueArray *ara, *arb;
|
|
guint i;
|
|
|
|
ara = g_value_get_boxed (va);
|
|
arb = g_value_get_boxed (vb);
|
|
|
|
if (!ara || !arb || ara->n_values != arb->n_values)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < ara->n_values; ++i)
|
|
if (!gdk_color_equal (g_value_get_boxed (g_value_array_get_nth (ara, i)),
|
|
g_value_get_boxed (g_value_array_get_nth (arb, i))))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
ensure_pixbuf_property (TerminalProfile *profile,
|
|
guint path_prop_id,
|
|
guint pixbuf_prop_id,
|
|
gboolean *load_failed)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GValue *path_value, *pixbuf_value;
|
|
GdkPixbuf *pixbuf;
|
|
const char *path_utf8;
|
|
char *path;
|
|
GError *error = NULL;
|
|
|
|
pixbuf_value = g_value_array_get_nth (priv->properties, pixbuf_prop_id);
|
|
|
|
pixbuf = g_value_get_object (pixbuf_value);
|
|
if (pixbuf)
|
|
return;
|
|
|
|
if (*load_failed)
|
|
return;
|
|
|
|
path_value = g_value_array_get_nth (priv->properties, path_prop_id);
|
|
path_utf8 = g_value_get_string (path_value);
|
|
if (!path_utf8 || !path_utf8[0])
|
|
goto failed;
|
|
|
|
path = g_filename_from_utf8 (path_utf8, -1, NULL, NULL, NULL);
|
|
if (!path)
|
|
goto failed;
|
|
|
|
pixbuf = gdk_pixbuf_new_from_file (path, &error);
|
|
if (!pixbuf)
|
|
{
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"Failed to load image \"%s\": %s\n",
|
|
path, error->message);
|
|
|
|
g_error_free (error);
|
|
g_free (path);
|
|
goto failed;
|
|
}
|
|
|
|
g_value_take_object (pixbuf_value, pixbuf);
|
|
g_free (path);
|
|
return;
|
|
|
|
failed:
|
|
*load_failed = TRUE;
|
|
}
|
|
|
|
static void
|
|
terminal_profile_reset_property_internal (TerminalProfile *profile,
|
|
GParamSpec *pspec,
|
|
gboolean notify)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GValue value_ = { 0, };
|
|
GValue *value;
|
|
|
|
if (notify)
|
|
{
|
|
value = &value_;
|
|
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
|
}
|
|
else
|
|
value = g_value_array_get_nth (priv->properties, pspec->param_id);
|
|
g_assert (value != NULL);
|
|
|
|
/* A few properties don't have defaults via the param spec; set them explicitly */
|
|
switch (pspec->param_id)
|
|
{
|
|
case PROP_FOREGROUND_COLOR:
|
|
case PROP_BOLD_COLOR:
|
|
g_value_set_boxed (value, &DEFAULT_FOREGROUND_COLOR);
|
|
break;
|
|
|
|
case PROP_BACKGROUND_COLOR:
|
|
g_value_set_boxed (value, &DEFAULT_BACKGROUND_COLOR);
|
|
break;
|
|
|
|
case PROP_FONT:
|
|
g_value_take_boxed (value, pango_font_description_from_string (DEFAULT_FONT));
|
|
break;
|
|
|
|
case PROP_PALETTE:
|
|
set_value_from_palette (value, DEFAULT_PALETTE, TERMINAL_PALETTE_SIZE);
|
|
break;
|
|
|
|
default:
|
|
g_param_value_set_default (pspec, value);
|
|
break;
|
|
}
|
|
|
|
if (notify)
|
|
{
|
|
g_object_set_property (G_OBJECT (profile), pspec->name, value);
|
|
g_value_unset (value);
|
|
}
|
|
}
|
|
|
|
static void
|
|
terminal_profile_gsettings_notify_cb (GSettings *settings,
|
|
gchar *key,
|
|
gpointer user_data)
|
|
{
|
|
TerminalProfile *profile = TERMINAL_PROFILE (user_data);
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
TerminalProfileClass *klass;
|
|
GVariant *settings_value;
|
|
GParamSpec *pspec;
|
|
GValue value = { 0, };
|
|
gboolean equal;
|
|
gboolean force_set = FALSE;
|
|
|
|
if (!key) return;
|
|
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"GSettings notification for key %s [%s]\n",
|
|
key,
|
|
g_settings_is_writable (settings, key) ? "writable" : "LOCKED");
|
|
|
|
klass = TERMINAL_PROFILE_GET_CLASS (profile);
|
|
pspec = g_hash_table_lookup (klass->gsettings_keys, key);
|
|
if (!pspec)
|
|
return; /* ignore unknown keys, for future extensibility */
|
|
|
|
priv->locked[pspec->param_id] = !g_settings_is_writable (settings, key);
|
|
|
|
settings_value = g_settings_get_value (settings, key);
|
|
if (!settings_value)
|
|
return;
|
|
|
|
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
|
|
|
if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
|
|
{
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_BOOLEAN))
|
|
goto out;
|
|
|
|
g_value_set_boolean (&value, g_variant_get_boolean (settings_value));
|
|
}
|
|
else if (G_IS_PARAM_SPEC_STRING (pspec))
|
|
{
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING))
|
|
goto out;
|
|
|
|
g_value_set_string (&value, g_variant_get_string (settings_value, NULL));
|
|
}
|
|
else if (G_IS_PARAM_SPEC_ENUM (pspec))
|
|
{
|
|
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING))
|
|
goto out;
|
|
|
|
g_value_set_enum (&value, g_settings_get_enum (settings, key));
|
|
}
|
|
else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
|
|
{
|
|
GdkColor color;
|
|
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING))
|
|
goto out;
|
|
|
|
if (!gdk_color_parse (g_variant_get_string (settings_value, NULL), &color))
|
|
goto out;
|
|
|
|
g_value_set_boxed (&value, &color);
|
|
}
|
|
else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
|
|
{
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING))
|
|
goto out;
|
|
|
|
g_value_take_boxed (&value, pango_font_description_from_string (g_variant_get_string (settings_value, NULL)));
|
|
}
|
|
else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
|
|
{
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_DOUBLE))
|
|
goto out;
|
|
|
|
g_value_set_double (&value, g_variant_get_double (settings_value));
|
|
}
|
|
else if (G_IS_PARAM_SPEC_INT (pspec))
|
|
{
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT16) &&
|
|
!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT32) &&
|
|
!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT64))
|
|
goto out;
|
|
|
|
g_value_set_int (&value, g_settings_get_int(settings, key));
|
|
}
|
|
else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
|
|
G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
|
|
{
|
|
char **color_strings;
|
|
GdkColor *colors;
|
|
int n_colors, i;
|
|
|
|
if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING))
|
|
goto out;
|
|
|
|
color_strings = g_strsplit (g_variant_get_string (settings_value, NULL), ":", -1);
|
|
if (!color_strings)
|
|
goto out;
|
|
|
|
n_colors = g_strv_length (color_strings);
|
|
colors = g_new0 (GdkColor, n_colors);
|
|
for (i = 0; i < n_colors; ++i)
|
|
{
|
|
if (!gdk_color_parse (color_strings[i], &colors[i]))
|
|
continue; /* ignore errors */
|
|
}
|
|
g_strfreev (color_strings);
|
|
|
|
/* We continue even with a palette size != TERMINAL_PALETTE_SIZE,
|
|
* so we can change the palette size in future versions without
|
|
* causing too many issues.
|
|
*/
|
|
set_value_from_palette (&value, colors, n_colors);
|
|
g_free (colors);
|
|
}
|
|
else
|
|
{
|
|
g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name);
|
|
goto out;
|
|
}
|
|
|
|
if (g_param_value_validate (pspec, &value))
|
|
{
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"Invalid value in GSettings for key %s was changed to comply with pspec %s\n",
|
|
key, pspec->name);
|
|
|
|
force_set = TRUE;
|
|
}
|
|
|
|
/* Only set the property if the value is different than our current value,
|
|
* so we don't go into an infinite loop.
|
|
*/
|
|
equal = values_equal (pspec, &value, g_value_array_get_nth (priv->properties, pspec->param_id));
|
|
#ifdef MATE_ENABLE_DEBUG
|
|
_TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROFILE)
|
|
{
|
|
if (!equal)
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"Setting property %s to a different value\n"
|
|
" now: %s\n"
|
|
" new: %s\n",
|
|
pspec->name,
|
|
g_strdup_value_contents (g_value_array_get_nth (priv->properties, pspec->param_id)),
|
|
g_strdup_value_contents (&value));
|
|
}
|
|
#endif
|
|
|
|
if (!equal || force_set)
|
|
{
|
|
priv->gsettings_notification_pspec = pspec;
|
|
g_object_set_property (G_OBJECT (profile), pspec->name, &value);
|
|
priv->gsettings_notification_pspec = NULL;
|
|
}
|
|
|
|
out:
|
|
/* FIXME: if we arrive here through goto in the error cases,
|
|
* should we maybe reset the property to its default value?
|
|
*/
|
|
|
|
g_value_unset (&value);
|
|
g_variant_unref (settings_value);
|
|
}
|
|
|
|
static void
|
|
terminal_profile_gsettings_changeset_add (TerminalProfile *profile,
|
|
GSettings *changeset,
|
|
GParamSpec *pspec)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
char *key;
|
|
const GValue *value;
|
|
|
|
/* FIXME: do this? */
|
|
#if 0
|
|
if (priv->locked[pspec->param_id])
|
|
return;
|
|
|
|
if (!g_settings_is_writable (priv->settings, gsettings_key, NULL))
|
|
return;
|
|
#endif
|
|
|
|
key = g_param_spec_get_qdata (pspec, gsettings_key_quark);
|
|
if (!key)
|
|
return;
|
|
|
|
value = g_value_array_get_nth (priv->properties, pspec->param_id);
|
|
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"Adding pspec %s with value %s to the GSettings changeset\n",
|
|
pspec->name, g_strdup_value_contents (value));
|
|
|
|
if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
|
|
g_settings_set_boolean (changeset, key, g_value_get_boolean (value));
|
|
else if (G_IS_PARAM_SPEC_STRING (pspec))
|
|
{
|
|
const char *str;
|
|
|
|
str = g_value_get_string (value);
|
|
g_settings_set_string (changeset, key, str ? str : "");
|
|
}
|
|
else if (G_IS_PARAM_SPEC_ENUM (pspec))
|
|
{
|
|
const GEnumValue *eval;
|
|
|
|
eval = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, g_value_get_enum (value));
|
|
|
|
g_settings_set_enum (changeset, key, eval->value);
|
|
}
|
|
else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
|
|
{
|
|
GdkColor *color;
|
|
char str[16];
|
|
|
|
color = g_value_get_boxed (value);
|
|
if (!color)
|
|
goto cleanup;
|
|
|
|
g_snprintf (str, sizeof (str),
|
|
"#%04X%04X%04X",
|
|
color->red,
|
|
color->green,
|
|
color->blue);
|
|
|
|
g_settings_set_string (changeset, key, str);
|
|
}
|
|
else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
|
|
{
|
|
PangoFontDescription *font_desc;
|
|
char *font;
|
|
|
|
font_desc = g_value_get_boxed (value);
|
|
if (!font_desc)
|
|
goto cleanup;
|
|
|
|
font = pango_font_description_to_string (font_desc);
|
|
g_settings_set_string (changeset, key, font);
|
|
g_free (font);
|
|
}
|
|
else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
|
|
g_settings_set_double (changeset, key, g_value_get_double (value));
|
|
else if (G_IS_PARAM_SPEC_INT (pspec))
|
|
g_settings_set_int (changeset, key, g_value_get_int (value));
|
|
else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
|
|
G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
|
|
{
|
|
GValueArray *array;
|
|
GString *string;
|
|
guint n_colors, i;
|
|
|
|
/* We need to do this ourselves, because the gtk_color_selection_palette_to_string
|
|
* does not carry all the bytes, and xterm's palette is messed up...
|
|
*/
|
|
|
|
array = g_value_get_boxed (value);
|
|
if (!array)
|
|
goto cleanup;
|
|
|
|
n_colors = array->n_values;
|
|
string = g_string_sized_new (n_colors * (1 /* # */ + 3 * 4) + n_colors /* : separators and terminating \0 */);
|
|
for (i = 0; i < n_colors; ++i)
|
|
{
|
|
GdkColor *color;
|
|
|
|
if (i > 0)
|
|
g_string_append_c (string, ':');
|
|
|
|
color = g_value_get_boxed (g_value_array_get_nth (array, i));
|
|
if (!color)
|
|
continue;
|
|
|
|
g_string_append_printf (string,
|
|
"#%04X%04X%04X",
|
|
color->red,
|
|
color->green,
|
|
color->blue);
|
|
}
|
|
|
|
g_settings_set_string (changeset, key, string->str);
|
|
g_string_free (string, TRUE);
|
|
}
|
|
else
|
|
g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name);
|
|
|
|
cleanup:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
terminal_profile_save (TerminalProfile *profile)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GSettings *changeset;
|
|
GSList *l;
|
|
|
|
priv->save_idle_id = 0;
|
|
changeset = g_settings_new_with_path (CONF_PROFILE_SCHEMA,
|
|
g_strconcat (CONF_PROFILE_PREFIX, priv->profile_dir,"/", NULL));
|
|
g_settings_delay (changeset);
|
|
|
|
for (l = priv->dirty_pspecs; l != NULL; l = l->next)
|
|
{
|
|
GParamSpec *pspec = (GParamSpec *) l->data;
|
|
|
|
if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
|
|
continue;
|
|
|
|
if ((pspec->flags & G_PARAM_WRITABLE) == 0)
|
|
continue;
|
|
|
|
terminal_profile_gsettings_changeset_add (profile, changeset, pspec);
|
|
}
|
|
|
|
g_slist_free (priv->dirty_pspecs);
|
|
priv->dirty_pspecs = NULL;
|
|
|
|
g_settings_apply (changeset);
|
|
g_object_unref (changeset);
|
|
}
|
|
|
|
static gboolean
|
|
terminal_profile_save_idle_cb (TerminalProfile *profile)
|
|
{
|
|
terminal_profile_save (profile);
|
|
|
|
/* don't run again */
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
terminal_profile_schedule_save (TerminalProfile *profile,
|
|
GParamSpec *pspec)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
|
|
g_assert (pspec != NULL);
|
|
|
|
if (!g_slist_find (priv->dirty_pspecs, pspec))
|
|
priv->dirty_pspecs = g_slist_prepend (priv->dirty_pspecs, pspec);
|
|
|
|
if (priv->save_idle_id != 0)
|
|
return;
|
|
|
|
priv->save_idle_id = g_idle_add ((GSourceFunc) terminal_profile_save_idle_cb, profile);
|
|
}
|
|
|
|
static void
|
|
terminal_profile_init (TerminalProfile *profile)
|
|
{
|
|
TerminalProfilePrivate *priv;
|
|
GObjectClass *object_class;
|
|
GParamSpec **pspecs;
|
|
guint n_pspecs, i;
|
|
|
|
priv = profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile, TERMINAL_TYPE_PROFILE, TerminalProfilePrivate);
|
|
|
|
priv->gsettings_notification_pspec = NULL;
|
|
priv->locked = g_new0 (gboolean, LAST_PROP);
|
|
|
|
priv->properties = g_value_array_new (LAST_PROP);
|
|
for (i = 0; i < LAST_PROP; ++i)
|
|
g_value_array_append (priv->properties, NULL);
|
|
|
|
pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile)), &n_pspecs);
|
|
for (i = 0; i < n_pspecs; ++i)
|
|
{
|
|
GParamSpec *pspec = pspecs[i];
|
|
GValue *value;
|
|
|
|
if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
|
|
continue;
|
|
|
|
g_assert (pspec->param_id < LAST_PROP);
|
|
value = g_value_array_get_nth (priv->properties, pspec->param_id);
|
|
g_value_init (value, pspec->value_type);
|
|
g_param_value_set_default (pspec, value);
|
|
}
|
|
|
|
g_free (pspecs);
|
|
|
|
/* A few properties don't have defaults via the param spec; set them explicitly */
|
|
object_class = G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile));
|
|
terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_FOREGROUND_COLOR), FALSE);
|
|
terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_BOLD_COLOR), FALSE);
|
|
terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_BACKGROUND_COLOR), FALSE);
|
|
terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_FONT), FALSE);
|
|
terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_PALETTE), FALSE);
|
|
}
|
|
|
|
static GObject *
|
|
terminal_profile_constructor (GType type,
|
|
guint n_construct_properties,
|
|
GObjectConstructParam *construct_params)
|
|
{
|
|
GObject *object;
|
|
TerminalProfile *profile;
|
|
TerminalProfilePrivate *priv;
|
|
const char *name;
|
|
GParamSpec **pspecs;
|
|
guint n_pspecs, i;
|
|
|
|
object = G_OBJECT_CLASS (terminal_profile_parent_class)->constructor
|
|
(type, n_construct_properties, construct_params);
|
|
|
|
profile = TERMINAL_PROFILE (object);
|
|
priv = profile->priv;
|
|
|
|
name = g_value_get_string (g_value_array_get_nth (priv->properties, PROP_NAME));
|
|
g_assert (name != NULL);
|
|
|
|
priv->settings = g_settings_new_with_path (CONF_PROFILE_SCHEMA,
|
|
g_strconcat (CONF_PROFILE_PREFIX, name, "/", NULL));
|
|
g_assert (priv->settings != NULL);
|
|
g_signal_connect (priv->settings,
|
|
g_strconcat("changed::", priv->profile_dir, "/", NULL),
|
|
G_CALLBACK(terminal_profile_gsettings_notify_cb),
|
|
profile);
|
|
|
|
/* Now load those properties from GSettings that were not set as construction params */
|
|
pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile)), &n_pspecs);
|
|
for (i = 0; i < n_pspecs; ++i)
|
|
{
|
|
GParamSpec *pspec = pspecs[i];
|
|
guint j;
|
|
gboolean is_construct = FALSE;
|
|
char *key;
|
|
|
|
if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
|
|
continue;
|
|
|
|
if ((pspec->flags & G_PARAM_WRITABLE) == 0 ||
|
|
(pspec->flags & G_PARAM_CONSTRUCT_ONLY) != 0)
|
|
continue;
|
|
|
|
for (j = 0; j < n_construct_properties; ++j)
|
|
if (pspec == construct_params[j].pspec)
|
|
{
|
|
is_construct = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (is_construct)
|
|
continue;
|
|
|
|
key = g_param_spec_get_qdata (pspec, gsettings_key_quark);
|
|
if (!key)
|
|
continue;
|
|
|
|
terminal_profile_gsettings_notify_cb (priv->settings, key, profile);
|
|
}
|
|
|
|
g_free (pspecs);
|
|
|
|
return object;
|
|
}
|
|
|
|
static void
|
|
terminal_profile_finalize (GObject *object)
|
|
{
|
|
TerminalProfile *profile = TERMINAL_PROFILE (object);
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->settings,
|
|
G_CALLBACK(terminal_profile_gsettings_notify_cb),
|
|
profile);
|
|
|
|
if (priv->save_idle_id)
|
|
{
|
|
g_source_remove (priv->save_idle_id);
|
|
|
|
/* Save now */
|
|
terminal_profile_save (profile);
|
|
}
|
|
|
|
_terminal_profile_forget (profile);
|
|
|
|
g_object_unref (priv->settings);
|
|
|
|
g_free (priv->profile_dir);
|
|
g_free (priv->locked);
|
|
g_value_array_free (priv->properties);
|
|
|
|
G_OBJECT_CLASS (terminal_profile_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
terminal_profile_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
TerminalProfile *profile = TERMINAL_PROFILE (object);
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
|
|
if (prop_id == 0 || prop_id >= LAST_PROP)
|
|
{
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
return;
|
|
}
|
|
|
|
/* Note: When adding things here, do the same in get_prop_value_from_prop_name! */
|
|
switch (prop_id)
|
|
{
|
|
case PROP_BACKGROUND_IMAGE:
|
|
ensure_pixbuf_property (profile, PROP_BACKGROUND_IMAGE_FILE, PROP_BACKGROUND_IMAGE, &priv->background_load_failed);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
g_value_copy (g_value_array_get_nth (priv->properties, prop_id), value);
|
|
}
|
|
|
|
static void
|
|
terminal_profile_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
TerminalProfile *profile = TERMINAL_PROFILE (object);
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GValue *prop_value;
|
|
|
|
if (prop_id == 0 || prop_id >= LAST_PROP)
|
|
{
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
return;
|
|
}
|
|
|
|
prop_value = g_value_array_get_nth (priv->properties, prop_id);
|
|
|
|
/* Preprocessing */
|
|
switch (prop_id)
|
|
{
|
|
#if 0
|
|
case PROP_FONT:
|
|
{
|
|
PangoFontDescription *font_desc, *new_font_desc;
|
|
|
|
font_desc = g_value_get_boxed (prop_value);
|
|
new_font_desc = g_value_get_boxed (value);
|
|
|
|
if (font_desc && new_font_desc)
|
|
{
|
|
/* Merge in case the new string isn't complete enough to load a font */
|
|
pango_font_description_merge (font_desc, new_font_desc, TRUE);
|
|
pango_font_description_free (new_font_desc);
|
|
break;
|
|
}
|
|
|
|
/* fall-through */
|
|
}
|
|
#endif
|
|
default:
|
|
g_value_copy (value, prop_value);
|
|
break;
|
|
}
|
|
|
|
/* Postprocessing */
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
{
|
|
const char *name = g_value_get_string (value);
|
|
|
|
g_assert (name != NULL);
|
|
priv->profile_dir = g_strdup (name);
|
|
if (priv->settings != NULL) {
|
|
g_signal_handlers_disconnect_by_func (priv->settings,
|
|
G_CALLBACK(terminal_profile_gsettings_notify_cb),
|
|
profile);
|
|
g_object_unref (priv->settings);
|
|
priv->settings = g_settings_new_with_path (CONF_PROFILE_SCHEMA,
|
|
g_strconcat (CONF_PROFILE_PREFIX, priv->profile_dir, "/", NULL));
|
|
g_signal_connect (priv->settings,
|
|
g_strconcat("changed::", priv->profile_dir, "/", NULL),
|
|
G_CALLBACK(terminal_profile_gsettings_notify_cb),
|
|
profile);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PROP_BACKGROUND_IMAGE_FILE:
|
|
/* Clear the cached image */
|
|
g_value_set_object (g_value_array_get_nth (priv->properties, PROP_BACKGROUND_IMAGE), NULL);
|
|
priv->background_load_failed = FALSE;
|
|
g_object_notify (object, TERMINAL_PROFILE_BACKGROUND_IMAGE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
terminal_profile_notify (GObject *object,
|
|
GParamSpec *pspec)
|
|
{
|
|
TerminalProfilePrivate *priv = TERMINAL_PROFILE (object)->priv;
|
|
void (* notify) (GObject *, GParamSpec *) = G_OBJECT_CLASS (terminal_profile_parent_class)->notify;
|
|
|
|
_terminal_debug_print (TERMINAL_DEBUG_PROFILE,
|
|
"Property notification for prop %s\n",
|
|
pspec->name);
|
|
|
|
if (notify)
|
|
notify (object, pspec);
|
|
|
|
if (pspec->owner_type == TERMINAL_TYPE_PROFILE &&
|
|
(pspec->flags & G_PARAM_WRITABLE) &&
|
|
g_param_spec_get_qdata (pspec, gsettings_key_quark) != NULL &&
|
|
pspec != priv->gsettings_notification_pspec)
|
|
terminal_profile_schedule_save (TERMINAL_PROFILE (object), pspec);
|
|
}
|
|
|
|
static void
|
|
terminal_profile_class_init (TerminalProfileClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
gsettings_key_quark = g_quark_from_static_string ("GT::GSettingsKey");
|
|
|
|
g_type_class_add_private (object_class, sizeof (TerminalProfilePrivate));
|
|
|
|
object_class->constructor = terminal_profile_constructor;
|
|
object_class->finalize = terminal_profile_finalize;
|
|
object_class->get_property = terminal_profile_get_property;
|
|
object_class->set_property = terminal_profile_set_property;
|
|
object_class->notify = terminal_profile_notify;
|
|
|
|
signals[FORGOTTEN] =
|
|
g_signal_new ("forgotten",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (TerminalProfileClass, forgotten),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
/* gsettings_key -> pspec hash */
|
|
klass->gsettings_keys = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
|
#define TERMINAL_PROFILE_PSPEC_STATIC (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY(propId, propSpec, propGSettings) \
|
|
{\
|
|
GParamSpec *pspec = propSpec;\
|
|
g_object_class_install_property (object_class, propId, pspec);\
|
|
\
|
|
if (propGSettings)\
|
|
{\
|
|
g_param_spec_set_qdata (pspec, gsettings_key_quark, (gpointer) propGSettings);\
|
|
g_hash_table_insert (klass->gsettings_keys, (gpointer) propGSettings, pspec);\
|
|
}\
|
|
}
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_BOOLEAN(prop, propDefault, propGSettings) \
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_boolean (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propDefault,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_BOXED(prop, propType, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_boxed (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propType,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_DOUBLE(prop, propMin, propMax, propDefault, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_double (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propMin, propMax, propDefault,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_ENUM(prop, propType, propDefault, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_enum (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propType, propDefault,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_INT(prop, propMin, propMax, propDefault, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_int (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propMin, propMax, propDefault,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
/* these are all read-only */
|
|
#define TERMINAL_PROFILE_PROPERTY_OBJECT(prop, propType, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_object (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propType,\
|
|
G_PARAM_READABLE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_STRING(prop, propDefault, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_string (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propDefault,\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_STRING_CO(prop, propDefault, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_string (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
propDefault,\
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
#define TERMINAL_PROFILE_PROPERTY_VALUE_ARRAY_BOXED(prop, propElementName, propElementType, propGSettings)\
|
|
TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
|
|
g_param_spec_value_array (TERMINAL_PROFILE_##prop, NULL, NULL,\
|
|
g_param_spec_boxed (propElementName, NULL, NULL,\
|
|
propElementType, \
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
|
|
propGSettings)
|
|
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (ALLOW_BOLD, DEFAULT_ALLOW_BOLD, KEY_ALLOW_BOLD);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (BOLD_COLOR_SAME_AS_FG, DEFAULT_BOLD_COLOR_SAME_AS_FG, KEY_BOLD_COLOR_SAME_AS_FG);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (DEFAULT_SHOW_MENUBAR, DEFAULT_DEFAULT_SHOW_MENUBAR, KEY_DEFAULT_SHOW_MENUBAR);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (LOGIN_SHELL, DEFAULT_LOGIN_SHELL, KEY_LOGIN_SHELL);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_BACKGROUND, DEFAULT_SCROLL_BACKGROUND, KEY_SCROLL_BACKGROUND);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLLBACK_UNLIMITED, DEFAULT_SCROLLBACK_UNLIMITED, KEY_SCROLLBACK_UNLIMITED);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_ON_KEYSTROKE, DEFAULT_SCROLL_ON_KEYSTROKE, KEY_SCROLL_ON_KEYSTROKE);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_ON_OUTPUT, DEFAULT_SCROLL_ON_OUTPUT, KEY_SCROLL_ON_OUTPUT);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (SILENT_BELL, DEFAULT_SILENT_BELL, KEY_SILENT_BELL);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (COPY_SELECTION, DEFAULT_COPY_SELECTION, KEY_COPY_SELECTION);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (UPDATE_RECORDS, DEFAULT_UPDATE_RECORDS, KEY_UPDATE_RECORDS);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_CUSTOM_COMMAND, DEFAULT_USE_CUSTOM_COMMAND, KEY_USE_CUSTOM_COMMAND);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_CUSTOM_DEFAULT_SIZE, DEFAULT_USE_CUSTOM_DEFAULT_SIZE, KEY_USE_CUSTOM_DEFAULT_SIZE);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_SKEY, DEFAULT_USE_SKEY, KEY_USE_SKEY);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_SYSTEM_FONT, DEFAULT_USE_SYSTEM_FONT, KEY_USE_SYSTEM_FONT);
|
|
TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_THEME_COLORS, DEFAULT_USE_THEME_COLORS, KEY_USE_THEME_COLORS);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_BOXED (BACKGROUND_COLOR, GDK_TYPE_COLOR, KEY_BACKGROUND_COLOR);
|
|
TERMINAL_PROFILE_PROPERTY_BOXED (BOLD_COLOR, GDK_TYPE_COLOR, KEY_BOLD_COLOR);
|
|
TERMINAL_PROFILE_PROPERTY_BOXED (FONT, PANGO_TYPE_FONT_DESCRIPTION, KEY_FONT);
|
|
TERMINAL_PROFILE_PROPERTY_BOXED (FOREGROUND_COLOR, GDK_TYPE_COLOR, KEY_FOREGROUND_COLOR);
|
|
|
|
/* 0.0 = normal bg, 1.0 = all black bg, 0.5 = half darkened */
|
|
TERMINAL_PROFILE_PROPERTY_DOUBLE (BACKGROUND_DARKNESS, 0.0, 1.0, DEFAULT_BACKGROUND_DARKNESS, KEY_BACKGROUND_DARKNESS);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (BACKGROUND_TYPE, TERMINAL_TYPE_BACKGROUND_TYPE, DEFAULT_BACKGROUND_TYPE, KEY_BACKGROUND_TYPE);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (BACKSPACE_BINDING, VTE_TYPE_TERMINAL_ERASE_BINDING, DEFAULT_BACKSPACE_BINDING, KEY_BACKSPACE_BINDING);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (CURSOR_BLINK_MODE, VTE_TYPE_TERMINAL_CURSOR_BLINK_MODE, DEFAULT_CURSOR_BLINK_MODE, KEY_CURSOR_BLINK_MODE);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (CURSOR_SHAPE, VTE_TYPE_TERMINAL_CURSOR_SHAPE, DEFAULT_CURSOR_SHAPE, KEY_CURSOR_SHAPE);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (DELETE_BINDING, VTE_TYPE_TERMINAL_ERASE_BINDING, DEFAULT_DELETE_BINDING, KEY_DELETE_BINDING);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (EXIT_ACTION, TERMINAL_TYPE_EXIT_ACTION, DEFAULT_EXIT_ACTION, KEY_EXIT_ACTION);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (SCROLLBAR_POSITION, TERMINAL_TYPE_SCROLLBAR_POSITION, DEFAULT_SCROLLBAR_POSITION, KEY_SCROLLBAR_POSITION);
|
|
TERMINAL_PROFILE_PROPERTY_ENUM (TITLE_MODE, TERMINAL_TYPE_TITLE_MODE, DEFAULT_TITLE_MODE, KEY_TITLE_MODE);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_INT (DEFAULT_SIZE_COLUMNS, 1, 1024, DEFAULT_DEFAULT_SIZE_COLUMNS, KEY_DEFAULT_SIZE_COLUMNS);
|
|
TERMINAL_PROFILE_PROPERTY_INT (DEFAULT_SIZE_ROWS, 1, 1024, DEFAULT_DEFAULT_SIZE_ROWS, KEY_DEFAULT_SIZE_ROWS);
|
|
TERMINAL_PROFILE_PROPERTY_INT (SCROLLBACK_LINES, 1, G_MAXINT, DEFAULT_SCROLLBACK_LINES, KEY_SCROLLBACK_LINES);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_OBJECT (BACKGROUND_IMAGE, GDK_TYPE_PIXBUF, NULL);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_STRING_CO (NAME, DEFAULT_NAME, NULL);
|
|
TERMINAL_PROFILE_PROPERTY_STRING (BACKGROUND_IMAGE_FILE, DEFAULT_BACKGROUND_IMAGE_FILE, KEY_BACKGROUND_IMAGE_FILE);
|
|
TERMINAL_PROFILE_PROPERTY_STRING (CUSTOM_COMMAND, DEFAULT_CUSTOM_COMMAND, KEY_CUSTOM_COMMAND);
|
|
TERMINAL_PROFILE_PROPERTY_STRING (TITLE, _(DEFAULT_TITLE), KEY_TITLE);
|
|
TERMINAL_PROFILE_PROPERTY_STRING (VISIBLE_NAME, _(DEFAULT_VISIBLE_NAME), KEY_VISIBLE_NAME);
|
|
TERMINAL_PROFILE_PROPERTY_STRING (WORD_CHARS, DEFAULT_WORD_CHARS, KEY_WORD_CHARS);
|
|
|
|
TERMINAL_PROFILE_PROPERTY_VALUE_ARRAY_BOXED (PALETTE, "palette-color", GDK_TYPE_COLOR, KEY_PALETTE);
|
|
}
|
|
|
|
/* Semi-Public API */
|
|
|
|
TerminalProfile*
|
|
_terminal_profile_new (const char *name)
|
|
{
|
|
return g_object_new (TERMINAL_TYPE_PROFILE,
|
|
"name", name,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
_terminal_profile_forget (TerminalProfile *profile)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
|
|
if (!priv->forgotten)
|
|
{
|
|
priv->forgotten = TRUE;
|
|
|
|
g_signal_emit (G_OBJECT (profile), signals[FORGOTTEN], 0);
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
_terminal_profile_get_forgotten (TerminalProfile *profile)
|
|
{
|
|
return profile->priv->forgotten;
|
|
}
|
|
|
|
TerminalProfile *
|
|
_terminal_profile_clone (TerminalProfile *base_profile,
|
|
const char *visible_name)
|
|
{
|
|
TerminalApp *app = terminal_app_get ();
|
|
GObject *base_object = G_OBJECT (base_profile);
|
|
TerminalProfilePrivate *new_priv;
|
|
char profile_name[32];
|
|
GParameter *params;
|
|
GParamSpec **pspecs;
|
|
guint n_pspecs, i, n_params, profile_num;
|
|
TerminalProfile *new_profile;
|
|
|
|
g_object_ref (base_profile);
|
|
|
|
profile_num = 0;
|
|
do
|
|
{
|
|
g_snprintf (profile_name, sizeof (profile_name), "profile%u", profile_num++);
|
|
}
|
|
while (terminal_app_get_profile_by_name (app, profile_name) != NULL);
|
|
|
|
/* Now we have an unused profile name */
|
|
pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (base_profile)), &n_pspecs);
|
|
|
|
params = g_newa (GParameter, n_pspecs);
|
|
n_params = 0;
|
|
|
|
for (i = 0; i < n_pspecs; ++i)
|
|
{
|
|
GParamSpec *pspec = pspecs[i];
|
|
GValue *value;
|
|
|
|
if (pspec->owner_type != TERMINAL_TYPE_PROFILE ||
|
|
(pspec->flags & G_PARAM_WRITABLE) == 0)
|
|
continue;
|
|
|
|
params[n_params].name = pspec->name;
|
|
|
|
value = ¶ms[n_params].value;
|
|
G_VALUE_TYPE (value) = 0;
|
|
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
|
|
|
if (pspec->name == I_(TERMINAL_PROFILE_NAME))
|
|
g_value_set_static_string (value, profile_name);
|
|
else if (pspec->name == I_(TERMINAL_PROFILE_VISIBLE_NAME))
|
|
g_value_set_static_string (value, visible_name);
|
|
else
|
|
g_object_get_property (base_object, pspec->name, value);
|
|
|
|
++n_params;
|
|
}
|
|
|
|
new_profile = g_object_newv (TERMINAL_TYPE_PROFILE, n_params, params);
|
|
|
|
g_object_unref (base_profile);
|
|
|
|
for (i = 0; i < n_params; ++i)
|
|
g_value_unset (¶ms[i].value);
|
|
|
|
/* Flush the new profile to GSettings */
|
|
new_priv = new_profile->priv;
|
|
|
|
g_slist_free (new_priv->dirty_pspecs);
|
|
new_priv->dirty_pspecs = NULL;
|
|
if (new_priv->save_idle_id != 0)
|
|
{
|
|
g_source_remove (new_priv->save_idle_id);
|
|
new_priv->save_idle_id = 0;
|
|
}
|
|
|
|
for (i = 0; i < n_pspecs; ++i)
|
|
{
|
|
GParamSpec *pspec = pspecs[i];
|
|
|
|
if (pspec->owner_type != TERMINAL_TYPE_PROFILE ||
|
|
(pspec->flags & G_PARAM_WRITABLE) == 0)
|
|
continue;
|
|
|
|
new_priv->dirty_pspecs = g_slist_prepend (new_priv->dirty_pspecs, pspec);
|
|
}
|
|
g_free (pspecs);
|
|
|
|
terminal_profile_save (new_profile);
|
|
|
|
return new_profile;
|
|
}
|
|
|
|
/* Public API */
|
|
|
|
gboolean
|
|
terminal_profile_get_property_boolean (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_BOOLEAN (value), FALSE);
|
|
if (!value || !G_VALUE_HOLDS_BOOLEAN (value))
|
|
return FALSE;
|
|
|
|
return g_value_get_boolean (value);
|
|
}
|
|
|
|
gconstpointer
|
|
terminal_profile_get_property_boxed (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_BOXED (value), NULL);
|
|
if (!value || !G_VALUE_HOLDS_BOXED (value))
|
|
return NULL;
|
|
|
|
return g_value_get_boxed (value);
|
|
}
|
|
|
|
double
|
|
terminal_profile_get_property_double (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_DOUBLE (value), 0.0);
|
|
if (!value || !G_VALUE_HOLDS_DOUBLE (value))
|
|
return 0.0;
|
|
|
|
return g_value_get_double (value);
|
|
}
|
|
|
|
int
|
|
terminal_profile_get_property_enum (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_ENUM (value), 0);
|
|
if (!value || !G_VALUE_HOLDS_ENUM (value))
|
|
return 0;
|
|
|
|
return g_value_get_enum (value);
|
|
}
|
|
|
|
int
|
|
terminal_profile_get_property_int (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_INT (value), 0);
|
|
if (!value || !G_VALUE_HOLDS_INT (value))
|
|
return 0;
|
|
|
|
return g_value_get_int (value);
|
|
}
|
|
|
|
gpointer
|
|
terminal_profile_get_property_object (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_OBJECT (value), NULL);
|
|
if (!value || !G_VALUE_HOLDS_OBJECT (value))
|
|
return NULL;
|
|
|
|
return g_value_get_object (value);
|
|
}
|
|
|
|
const char*
|
|
terminal_profile_get_property_string (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
const GValue *value;
|
|
|
|
value = get_prop_value_from_prop_name (profile, prop_name);
|
|
g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_STRING (value), NULL);
|
|
if (!value || !G_VALUE_HOLDS_STRING (value))
|
|
return NULL;
|
|
|
|
return g_value_get_string (value);
|
|
}
|
|
|
|
gboolean
|
|
terminal_profile_property_locked (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GParamSpec *pspec;
|
|
|
|
pspec = get_pspec_from_name (profile, prop_name);
|
|
g_return_val_if_fail (pspec != NULL, FALSE);
|
|
if (!pspec)
|
|
return FALSE;
|
|
|
|
return priv->locked[pspec->param_id];
|
|
}
|
|
|
|
void
|
|
terminal_profile_reset_property (TerminalProfile *profile,
|
|
const char *prop_name)
|
|
{
|
|
GParamSpec *pspec;
|
|
|
|
pspec = get_pspec_from_name (profile, prop_name);
|
|
g_return_if_fail (pspec != NULL);
|
|
if (!pspec ||
|
|
(pspec->flags & G_PARAM_WRITABLE) == 0)
|
|
return;
|
|
|
|
terminal_profile_reset_property_internal (profile, pspec, TRUE);
|
|
}
|
|
|
|
gboolean
|
|
terminal_profile_get_palette (TerminalProfile *profile,
|
|
GdkColor *colors,
|
|
guint *n_colors)
|
|
{
|
|
TerminalProfilePrivate *priv;
|
|
GValueArray *array;
|
|
guint i, n;
|
|
|
|
g_return_val_if_fail (TERMINAL_IS_PROFILE (profile), FALSE);
|
|
g_return_val_if_fail (colors != NULL && n_colors != NULL, FALSE);
|
|
|
|
priv = profile->priv;
|
|
array = g_value_get_boxed (g_value_array_get_nth (priv->properties, PROP_PALETTE));
|
|
if (!array)
|
|
return FALSE;
|
|
|
|
n = MIN (array->n_values, *n_colors);
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
GdkColor *color = g_value_get_boxed (g_value_array_get_nth (array, i));
|
|
if (!color)
|
|
continue; /* shouldn't happen!! */
|
|
|
|
colors[i] = *color;
|
|
}
|
|
|
|
*n_colors = n;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
terminal_profile_get_palette_is_builtin (TerminalProfile *profile,
|
|
guint *n)
|
|
{
|
|
GdkColor colors[TERMINAL_PALETTE_SIZE];
|
|
guint n_colors;
|
|
guint i;
|
|
|
|
n_colors = G_N_ELEMENTS (colors);
|
|
if (!terminal_profile_get_palette (profile, colors, &n_colors) ||
|
|
n_colors != TERMINAL_PALETTE_SIZE)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < TERMINAL_PALETTE_N_BUILTINS; ++i)
|
|
if (palette_cmp (colors, terminal_palettes[i]))
|
|
{
|
|
*n = i;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
terminal_profile_set_palette_builtin (TerminalProfile *profile,
|
|
guint n)
|
|
{
|
|
GValue value = { 0, };
|
|
|
|
g_return_if_fail (n < TERMINAL_PALETTE_N_BUILTINS);
|
|
|
|
g_value_init (&value, G_TYPE_VALUE_ARRAY);
|
|
set_value_from_palette (&value, terminal_palettes[n], TERMINAL_PALETTE_SIZE);
|
|
g_object_set_property (G_OBJECT (profile), TERMINAL_PROFILE_PALETTE, &value);
|
|
g_value_unset (&value);
|
|
}
|
|
|
|
gboolean
|
|
terminal_profile_modify_palette_entry (TerminalProfile *profile,
|
|
guint i,
|
|
const GdkColor *color)
|
|
{
|
|
TerminalProfilePrivate *priv = profile->priv;
|
|
GValueArray *array;
|
|
GValue *value;
|
|
GdkColor *old_color;
|
|
|
|
array = g_value_get_boxed (g_value_array_get_nth (priv->properties, PROP_PALETTE));
|
|
if (!array ||
|
|
i >= array->n_values)
|
|
return FALSE;
|
|
|
|
value = g_value_array_get_nth (array, i);
|
|
old_color = g_value_get_boxed (value);
|
|
if (!old_color ||
|
|
!gdk_color_equal (old_color, color))
|
|
{
|
|
g_value_set_boxed (value, color);
|
|
g_object_notify (G_OBJECT (profile), TERMINAL_PROFILE_PALETTE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|