1 /* ide-buffer-change-monitor.c
2  *
3  * Copyright 2015-2019 Christian Hergert <christian@hergert.me>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * SPDX-License-Identifier: GPL-3.0-or-later
19  */
20 
21 #define G_LOG_DOMAIN "ide-buffer-change-monitor"
22 
23 #include "config.h"
24 
25 #include <glib/gi18n.h>
26 
27 #include "ide-buffer.h"
28 #include "ide-buffer-change-monitor.h"
29 #include "ide-buffer-private.h"
30 
31 typedef struct
32 {
33   IdeBuffer *buffer;
34 } IdeBufferChangeMonitorPrivate;
35 
36 G_DEFINE_TYPE_WITH_PRIVATE (IdeBufferChangeMonitor, ide_buffer_change_monitor, IDE_TYPE_OBJECT)
37 
38 enum {
39   PROP_0,
40   PROP_BUFFER,
41   N_PROPS
42 };
43 
44 enum {
45   CHANGED,
46   N_SIGNALS
47 };
48 
49 static GParamSpec *properties [N_PROPS];
50 static guint signals [N_SIGNALS];
51 
52 IdeBufferLineChange
ide_buffer_change_monitor_get_change(IdeBufferChangeMonitor * self,guint line)53 ide_buffer_change_monitor_get_change (IdeBufferChangeMonitor *self,
54                                       guint                   line)
55 {
56   g_return_val_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self), IDE_BUFFER_LINE_CHANGE_NONE);
57 
58   if G_LIKELY (IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->get_change)
59     return IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->get_change (self, line);
60   else
61     return IDE_BUFFER_LINE_CHANGE_NONE;
62 }
63 
64 static void
ide_buffer_change_monitor_set_buffer(IdeBufferChangeMonitor * self,IdeBuffer * buffer)65 ide_buffer_change_monitor_set_buffer (IdeBufferChangeMonitor *self,
66                                       IdeBuffer              *buffer)
67 {
68   IdeBufferChangeMonitorPrivate *priv = ide_buffer_change_monitor_get_instance_private (self);
69 
70   g_return_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self));
71   g_return_if_fail (IDE_IS_BUFFER (buffer));
72 
73   priv->buffer = g_object_ref (buffer);
74 
75   if (IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->load)
76     IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->load (self, buffer);
77 }
78 
79 void
ide_buffer_change_monitor_emit_changed(IdeBufferChangeMonitor * self)80 ide_buffer_change_monitor_emit_changed (IdeBufferChangeMonitor *self)
81 {
82   IdeBufferChangeMonitorPrivate *priv = ide_buffer_change_monitor_get_instance_private (self);
83 
84   g_return_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self));
85 
86   g_signal_emit (self, signals [CHANGED], 0);
87 
88   if (priv->buffer)
89     _ide_buffer_line_flags_changed (priv->buffer);
90 }
91 
92 static void
ide_buffer_change_monitor_destroy(IdeObject * object)93 ide_buffer_change_monitor_destroy (IdeObject *object)
94 {
95   IdeBufferChangeMonitor *self = (IdeBufferChangeMonitor *)object;
96   IdeBufferChangeMonitorPrivate *priv = ide_buffer_change_monitor_get_instance_private (self);
97 
98   g_assert (IDE_IS_MAIN_THREAD ());
99   g_assert (IDE_IS_BUFFER_CHANGE_MONITOR (self));
100 
101   g_clear_object (&priv->buffer);
102 
103   IDE_OBJECT_CLASS (ide_buffer_change_monitor_parent_class)->destroy (object);
104 }
105 
106 static void
ide_buffer_change_monitor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)107 ide_buffer_change_monitor_get_property (GObject    *object,
108                                         guint       prop_id,
109                                         GValue     *value,
110                                         GParamSpec *pspec)
111 {
112   IdeBufferChangeMonitor *self = IDE_BUFFER_CHANGE_MONITOR (object);
113 
114   switch (prop_id)
115     {
116     case PROP_BUFFER:
117       g_value_set_object (value, ide_buffer_change_monitor_get_buffer (self));
118       break;
119 
120     default:
121       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122     }
123 }
124 
125 static void
ide_buffer_change_monitor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)126 ide_buffer_change_monitor_set_property (GObject      *object,
127                                         guint         prop_id,
128                                         const GValue *value,
129                                         GParamSpec   *pspec)
130 {
131   IdeBufferChangeMonitor *self = IDE_BUFFER_CHANGE_MONITOR (object);
132 
133   switch (prop_id)
134     {
135     case PROP_BUFFER:
136       ide_buffer_change_monitor_set_buffer (self, g_value_get_object (value));
137       break;
138 
139     default:
140       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
141     }
142 }
143 
144 static void
ide_buffer_change_monitor_class_init(IdeBufferChangeMonitorClass * klass)145 ide_buffer_change_monitor_class_init (IdeBufferChangeMonitorClass *klass)
146 {
147   GObjectClass *object_class = G_OBJECT_CLASS (klass);
148   IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
149 
150   object_class->get_property = ide_buffer_change_monitor_get_property;
151   object_class->set_property = ide_buffer_change_monitor_set_property;
152 
153   i_object_class->destroy = ide_buffer_change_monitor_destroy;
154 
155   properties [PROP_BUFFER] =
156     g_param_spec_object ("buffer",
157                          "Buffer",
158                          "The IdeBuffer to be monitored.",
159                          IDE_TYPE_BUFFER,
160                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
161 
162   g_object_class_install_properties (object_class, N_PROPS, properties);
163 
164   signals [CHANGED] = g_signal_new ("changed",
165                                     G_TYPE_FROM_CLASS (klass),
166                                     G_SIGNAL_RUN_LAST,
167                                     0,
168                                     NULL, NULL, NULL,
169                                     G_TYPE_NONE,
170                                     0);
171 }
172 
173 static void
ide_buffer_change_monitor_init(IdeBufferChangeMonitor * self)174 ide_buffer_change_monitor_init (IdeBufferChangeMonitor *self)
175 {
176 }
177 
178 void
ide_buffer_change_monitor_reload(IdeBufferChangeMonitor * self)179 ide_buffer_change_monitor_reload (IdeBufferChangeMonitor *self)
180 {
181   g_return_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self));
182 
183   if (IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->reload)
184     IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->reload (self);
185 }
186 
187 /**
188  * ide_buffer_change_monitor_foreach_change:
189  * @self: a #IdeBufferChangeMonitor
190  * @line_begin: the starting line
191  * @line_end: the end line
192  * @callback: (scope call): a callback
193  * @user_data: user data for @callback
194  *
195  * Calls @callback for every line between @line_begin and @line_end that have
196  * an addition, deletion, or change.
197  *
198  * Since: 3.32
199  */
200 void
ide_buffer_change_monitor_foreach_change(IdeBufferChangeMonitor * self,guint line_begin,guint line_end,IdeBufferChangeMonitorForeachFunc callback,gpointer user_data)201 ide_buffer_change_monitor_foreach_change (IdeBufferChangeMonitor            *self,
202                                           guint                              line_begin,
203                                           guint                              line_end,
204                                           IdeBufferChangeMonitorForeachFunc  callback,
205                                           gpointer                           user_data)
206 {
207   g_return_if_fail (IDE_IS_MAIN_THREAD ());
208   g_return_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self));
209   g_return_if_fail (callback != NULL);
210 
211   if (IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->foreach_change)
212     IDE_BUFFER_CHANGE_MONITOR_GET_CLASS (self)->foreach_change (self, line_begin, line_end, callback, user_data);
213 }
214 
215 /**
216  * ide_buffer_change_monitor_get_buffer:
217  * @self: a #IdeBufferChangeMonitor
218  *
219  * Gets the #IdeBufferChangeMonitor:buffer property.
220  *
221  * Returns: (transfer none): an #IdeBuffer
222  *
223  * Since: 3.32
224  */
225 IdeBuffer *
ide_buffer_change_monitor_get_buffer(IdeBufferChangeMonitor * self)226 ide_buffer_change_monitor_get_buffer (IdeBufferChangeMonitor *self)
227 {
228   IdeBufferChangeMonitorPrivate *priv = ide_buffer_change_monitor_get_instance_private (self);
229 
230   g_return_val_if_fail (IDE_IS_BUFFER_CHANGE_MONITOR (self), NULL);
231 
232   return priv->buffer;
233 }
234