/* * moolinemark.c * * Copyright (C) 2004-2006 by Yevgen Muntyan * * 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 2 of the License, or * (at your option) any later version. * * See COPYING file that comes with this distribution. */ #define MOOEDIT_COMPILATION #include "mooedit/mootext-private.h" #include "mooedit/mootextbuffer.h" #include "mooutils/moomarshals.h" struct _MooLineMarkPrivate { GdkColor background; GdkGC *background_gc; char *stock_id; GdkPixbuf *pixbuf; GtkWidget *widget; char *name; MooTextBuffer *buffer; LineBuffer *line_buf; Line *line; int line_no; guint stamp; MooFold *fold; guint background_set : 1; guint visible : 1; guint realized : 1; guint pretty : 1; }; static void moo_line_mark_finalize (GObject *object); static void moo_line_mark_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void moo_line_mark_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void moo_line_mark_changed (MooLineMark *mark); static void update_background_gc (MooLineMark *mark); static void update_pixbuf (MooLineMark *mark); static void moo_line_mark_deleted_real (MooLineMark *mark); enum { CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; enum { PROP_0, PROP_BACKGROUND, PROP_BACKGROUND_GDK, PROP_BACKGROUND_SET, PROP_PIXBUF, PROP_STOCK_ID, PROP_NAME, PROP_VISIBLE }; /* MOO_TYPE_LINE_MARK */ G_DEFINE_TYPE (MooLineMark, moo_line_mark, G_TYPE_OBJECT) static void moo_line_mark_class_init (MooLineMarkClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = moo_line_mark_set_property; gobject_class->get_property = moo_line_mark_get_property; gobject_class->finalize = moo_line_mark_finalize; klass->deleted = moo_line_mark_deleted_real; g_object_class_install_property (gobject_class, PROP_BACKGROUND, g_param_spec_string ("background", "background", "background", NULL, G_PARAM_WRITABLE)); g_object_class_install_property (gobject_class, PROP_BACKGROUND_GDK, g_param_spec_boxed ("background-gdk", "background-gdk", "background-gdk", GDK_TYPE_COLOR, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_BACKGROUND_SET, g_param_spec_boolean ("background-set", "background-set", "background-set", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "name", "name", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_VISIBLE, g_param_spec_boolean ("visible", "visible", "visible", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_PIXBUF, g_param_spec_object ("pixbuf", "pixbuf", "pixbuf", GDK_TYPE_PIXBUF, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_STOCK_ID, g_param_spec_string ("stock-id", "stock-id", "stock-id", NULL, G_PARAM_READWRITE)); signals[CHANGED] = g_signal_new ("changed", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (MooLineMarkClass, changed), NULL, NULL, _moo_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void moo_line_mark_init (MooLineMark *mark) { mark->priv = g_new0 (MooLineMarkPrivate, 1); mark->priv->line_no = -1; gdk_color_parse ("0xFFF", &mark->priv->background); } static void moo_line_mark_finalize (GObject *object) { MooLineMark *mark = MOO_LINE_MARK (object); if (mark->priv->pixbuf) g_object_unref (mark->priv->pixbuf); if (mark->priv->background_gc) g_object_unref (mark->priv->background_gc); g_free (mark->priv->stock_id); g_free (mark->priv->name); g_free (mark->priv); G_OBJECT_CLASS (moo_line_mark_parent_class)->finalize (object); } static void moo_line_mark_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { MooLineMark *mark = MOO_LINE_MARK (object); switch (prop_id) { case PROP_BACKGROUND_GDK: moo_line_mark_set_background_gdk (mark, g_value_get_boxed (value)); break; case PROP_BACKGROUND: moo_line_mark_set_background (mark, g_value_get_string (value)); break; case PROP_BACKGROUND_SET: mark->priv->background_set = g_value_get_boolean (value) != 0; g_object_notify (object, "background-set"); moo_line_mark_changed (mark); break; case PROP_NAME: moo_line_mark_set_name (mark, g_value_get_string (value)); break; case PROP_VISIBLE: mark->priv->visible = g_value_get_boolean (value) != 0; g_object_notify (object, "visible"); break; case PROP_PIXBUF: moo_line_mark_set_pixbuf (mark, g_value_get_object (value)); break; case PROP_STOCK_ID: moo_line_mark_set_stock_id (mark, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void moo_line_mark_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { MooLineMark *mark = MOO_LINE_MARK (object); switch (prop_id) { case PROP_BACKGROUND_GDK: g_value_set_boxed (value, &mark->priv->background); break; case PROP_BACKGROUND_SET: g_value_set_boolean (value, mark->priv->background_set != 0); break; case PROP_NAME: g_value_set_string (value, mark->priv->name); break; case PROP_VISIBLE: g_value_set_boolean (value, mark->priv->visible != 0); break; case PROP_PIXBUF: g_value_set_object (value, mark->priv->pixbuf); break; case PROP_STOCK_ID: g_value_set_string (value, mark->priv->stock_id); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } void moo_line_mark_set_background_gdk (MooLineMark *mark, const GdkColor *color) { gboolean changed = FALSE, notify_set = FALSE, notify_bg = FALSE; g_return_if_fail (MOO_IS_LINE_MARK (mark)); if (color) { if (!mark->priv->background_set) { mark->priv->background_set = TRUE; notify_set = TRUE; } changed = TRUE; notify_bg = TRUE; mark->priv->background = *color; } else { if (mark->priv->background_set) { mark->priv->background_set = FALSE; notify_set = TRUE; notify_bg = TRUE; changed = TRUE; } } update_background_gc (mark); if (notify_set || notify_bg) { g_object_freeze_notify (G_OBJECT (mark)); if (notify_set) g_object_notify (G_OBJECT (mark), "background-set"); if (notify_bg) { g_object_notify (G_OBJECT (mark), "background"); g_object_notify (G_OBJECT (mark), "background-gdk"); } g_object_thaw_notify (G_OBJECT (mark)); } if (changed) moo_line_mark_changed (mark); } void moo_line_mark_set_background (MooLineMark *mark, const char *color) { GdkColor gdk_color; g_return_if_fail (MOO_IS_LINE_MARK (mark)); if (color) { if (gdk_color_parse (color, &gdk_color)) moo_line_mark_set_background_gdk (mark, &gdk_color); else g_warning ("%s: could not parse color '%s'", G_STRLOC, color); } else { moo_line_mark_set_background_gdk (mark, NULL); } } static void moo_line_mark_changed (MooLineMark *mark) { g_signal_emit (mark, signals[CHANGED], 0); } void moo_line_mark_set_name (MooLineMark *mark, const char *name) { g_return_if_fail (MOO_IS_LINE_MARK (mark)); if (mark->priv->name != name) { g_free (mark->priv->name); mark->priv->name = g_strdup (name); g_object_notify (G_OBJECT (mark), "name"); } } const char * moo_line_mark_get_name (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), NULL); return mark->priv->name; } int moo_line_mark_get_line (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), -1); g_return_val_if_fail (mark->priv->line != NULL, -1); if (_moo_line_buffer_get_stamp (mark->priv->line_buf) != mark->priv->stamp) { mark->priv->line_no = _moo_line_buffer_get_line_index (mark->priv->line_buf, mark->priv->line); mark->priv->stamp = _moo_line_buffer_get_stamp (mark->priv->line_buf); } return mark->priv->line_no; } void _moo_line_mark_set_line (MooLineMark *mark, Line *line, int line_no, guint stamp) { g_assert (MOO_IS_LINE_MARK (mark)); g_assert (!line || mark->priv->buffer != NULL); mark->priv->line = line; mark->priv->line_no = line_no; mark->priv->stamp = stamp; } Line* _moo_line_mark_get_line (MooLineMark *mark) { g_assert (MOO_IS_LINE_MARK (mark)); return mark->priv->line; } void _moo_line_mark_set_buffer (MooLineMark *mark, MooTextBuffer *buffer, LineBuffer *line_buf) { g_assert (MOO_IS_LINE_MARK (mark)); g_assert (!buffer || mark->priv->buffer == NULL); mark->priv->buffer = buffer; mark->priv->line_buf = line_buf; if (!buffer) _moo_line_mark_set_line (mark, NULL, -1, 0); } MooTextBuffer * moo_line_mark_get_buffer (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), NULL); return mark->priv->buffer; } static void moo_line_mark_deleted_real (MooLineMark *mark) { _moo_line_mark_set_buffer (mark, NULL, NULL); } void _moo_line_mark_deleted (MooLineMark *mark) { g_assert (MOO_IS_LINE_MARK (mark)); MOO_LINE_MARK_GET_CLASS (mark)->deleted (mark); } gboolean moo_line_mark_get_deleted (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), TRUE); return mark->priv->buffer == NULL; } gboolean moo_line_mark_get_visible (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), FALSE); return mark->priv->visible != 0; } void moo_line_mark_set_stock_id (MooLineMark *mark, const char *stock_id) { g_return_if_fail (MOO_IS_LINE_MARK (mark)); if (stock_id != mark->priv->stock_id) { if (mark->priv->pixbuf) g_object_unref (mark->priv->pixbuf); mark->priv->pixbuf = NULL; g_free (mark->priv->stock_id); mark->priv->stock_id = g_strdup (stock_id); update_pixbuf (mark); g_signal_emit (mark, signals[CHANGED], 0); } } void moo_line_mark_set_pixbuf (MooLineMark *mark, GdkPixbuf *pixbuf) { g_return_if_fail (MOO_IS_LINE_MARK (mark)); g_return_if_fail (!pixbuf || GDK_IS_PIXBUF (pixbuf)); if (pixbuf != mark->priv->pixbuf) { if (mark->priv->pixbuf) g_object_unref (mark->priv->pixbuf); mark->priv->pixbuf = NULL; g_free (mark->priv->stock_id); mark->priv->stock_id = NULL; mark->priv->pixbuf = g_object_ref (pixbuf); g_signal_emit (mark, signals[CHANGED], 0); } } const char * moo_line_mark_get_stock_id (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), NULL); return mark->priv->stock_id; } GdkPixbuf * moo_line_mark_get_pixbuf (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), NULL); return mark->priv->pixbuf; } static void update_background_gc (MooLineMark *mark) { GHashTable *cache; GdkGC *gc; if (!mark->priv->realized || !mark->priv->background_set) { if (mark->priv->background_gc) g_object_unref (mark->priv->background_gc); mark->priv->background_gc = NULL; return; } g_assert (mark->priv->widget != NULL); g_return_if_fail (GTK_IS_WIDGET (mark->priv->widget)); g_return_if_fail (GTK_WIDGET_REALIZED (mark->priv->widget)); cache = g_object_get_data (G_OBJECT (mark->priv->widget), "moo-line-mark-colors"); if (!cache) { cache = g_hash_table_new_full ((GHashFunc) gdk_color_hash, (GEqualFunc) gdk_color_equal, (GDestroyNotify) gdk_color_free, g_object_unref); g_object_set_data_full (G_OBJECT (mark->priv->widget), "moo-line-mark-colors", cache, (GDestroyNotify) g_hash_table_destroy); } gc = g_hash_table_lookup (cache, &mark->priv->background); if (!gc) { GdkColormap *colormap; colormap = gtk_widget_get_colormap (mark->priv->widget); g_return_if_fail (colormap != NULL); gc = gdk_gc_new (mark->priv->widget->window); gdk_colormap_alloc_color (colormap, &mark->priv->background, TRUE, TRUE); gdk_gc_set_foreground (gc, &mark->priv->background); g_hash_table_insert (cache, gdk_color_copy (&mark->priv->background), gc); } mark->priv->background_gc = g_object_ref (gc); } static void update_pixbuf (MooLineMark *mark) { GHashTable *cache; GdkPixbuf *pixbuf; if (!mark->priv->realized || !mark->priv->stock_id) return; g_assert (mark->priv->widget != NULL); g_return_if_fail (GTK_IS_WIDGET (mark->priv->widget)); g_return_if_fail (GTK_WIDGET_REALIZED (mark->priv->widget)); cache = g_object_get_data (G_OBJECT (mark->priv->widget), "moo-line-mark-icons"); if (!cache) { cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); g_object_set_data_full (G_OBJECT (mark->priv->widget), "moo-line-mark-icons", cache, (GDestroyNotify) g_hash_table_destroy); } pixbuf = g_hash_table_lookup (cache, mark->priv->stock_id); if (!pixbuf) { pixbuf = gtk_widget_render_icon (mark->priv->widget, mark->priv->stock_id, GTK_ICON_SIZE_MENU, NULL); g_return_if_fail (pixbuf != NULL); g_hash_table_insert (cache, g_strdup (mark->priv->stock_id), pixbuf); } mark->priv->pixbuf = g_object_ref (pixbuf); } void _moo_line_mark_realize (MooLineMark *mark, GtkWidget *widget) { g_assert (MOO_IS_LINE_MARK (mark)); g_assert (GTK_IS_WIDGET (widget)); g_assert (GTK_WIDGET_REALIZED (widget)); g_assert (!mark->priv->realized); mark->priv->realized = TRUE; mark->priv->widget = widget; update_background_gc (mark); update_pixbuf (mark); } void _moo_line_mark_unrealize (MooLineMark *mark) { g_assert (MOO_IS_LINE_MARK (mark)); g_assert (mark->priv->realized); mark->priv->realized = FALSE; mark->priv->widget = NULL; if (mark->priv->background_gc) g_object_unref (mark->priv->background_gc); mark->priv->background_gc = NULL; if (mark->priv->pixbuf && mark->priv->stock_id) { g_object_unref (mark->priv->pixbuf); mark->priv->pixbuf = NULL; } } GdkGC * moo_line_mark_get_background_gc (MooLineMark *mark) { g_return_val_if_fail (MOO_IS_LINE_MARK (mark), NULL); return mark->priv->background_gc; } void _moo_line_mark_set_pretty (MooLineMark *mark, gboolean pretty) { g_assert (MOO_IS_LINE_MARK (mark)); mark->priv->pretty = pretty != 0; } gboolean _moo_line_mark_get_pretty (MooLineMark *mark) { g_assert (MOO_IS_LINE_MARK (mark)); return mark->priv->pretty != 0; } void _moo_line_mark_set_fold (MooLineMark *mark, MooFold *fold) { g_assert (MOO_IS_LINE_MARK (mark)); g_assert (!fold || MOO_IS_FOLD (fold)); mark->priv->fold = fold; } MooFold * _moo_line_mark_get_fold (MooLineMark *mark) { g_assert (MOO_IS_LINE_MARK (mark)); return mark->priv->fold; }