]> Pileus Git - ~andy/gtk/blob - gtk/gtktextmark.c
1f0da6835bc6cc24b75469a7c9bf0955aaf5357f
[~andy/gtk] / gtk / gtktextmark.c
1 /* gtktextmark.c - mark segments
2  *
3  * Copyright (c) 1994 The Regents of the University of California.
4  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
5  * Copyright (c) 2000      Red Hat, Inc.
6  * Tk -> Gtk port by Havoc Pennington <hp@redhat.com>
7  *
8  * This software is copyrighted by the Regents of the University of
9  * California, Sun Microsystems, Inc., and other parties.  The
10  * following terms apply to all files associated with the software
11  * unless explicitly disclaimed in individual files.
12  *
13  * The authors hereby grant permission to use, copy, modify,
14  * distribute, and license this software and its documentation for any
15  * purpose, provided that existing copyright notices are retained in
16  * all copies and that this notice is included verbatim in any
17  * distributions. No written agreement, license, or royalty fee is
18  * required for any of the authorized uses.  Modifications to this
19  * software may be copyrighted by their authors and need not follow
20  * the licensing terms described here, provided that the new terms are
21  * clearly indicated on the first page of each file where they apply.
22  *
23  * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
24  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
25  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
26  * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
30  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
32  * NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
33  * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
34  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
35  *
36  * GOVERNMENT USE: If you are acquiring this software on behalf of the
37  * U.S. government, the Government shall have only "Restricted Rights"
38  * in the software and related documentation as defined in the Federal
39  * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
40  * are acquiring the software on behalf of the Department of Defense,
41  * the software shall be classified as "Commercial Computer Software"
42  * and the Government shall have only "Restricted Rights" as defined
43  * in Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
44  * foregoing, the authors grant the U.S. Government and others acting
45  * in its behalf permission to use and distribute the software in
46  * accordance with the terms specified in this license.
47  *
48  */
49
50
51 #include "gtktextbtree.h"
52
53 static void gtk_text_mark_init       (GtkTextMark      *mark);
54 static void gtk_text_mark_class_init (GtkTextMarkClass *klass);
55 static void gtk_text_mark_finalize   (GObject          *obj);
56
57
58 static gpointer parent_class = NULL;
59
60 GType
61 gtk_text_mark_get_type (void)
62 {
63   static GType object_type = 0;
64
65   if (!object_type)
66     {
67       static const GTypeInfo object_info =
68       {
69         sizeof (GtkTextMarkClass),
70         (GBaseInitFunc) NULL,
71         (GBaseFinalizeFunc) NULL,
72         (GClassInitFunc) gtk_text_mark_class_init,
73         NULL,           /* class_finalize */
74         NULL,           /* class_data */
75         sizeof (GtkTextMark),
76         0,              /* n_preallocs */
77         (GInstanceInitFunc) gtk_text_mark_init,
78       };
79
80       object_type = g_type_register_static (G_TYPE_OBJECT,
81                                             "GtkTextMark",
82                                             &object_info, 0);
83     }
84
85   return object_type;
86 }
87
88 static void
89 gtk_text_mark_init (GtkTextMark *mark)
90 {
91   mark->segment = NULL;
92 }
93
94 static void
95 gtk_text_mark_class_init (GtkTextMarkClass *klass)
96 {
97   GObjectClass *object_class = G_OBJECT_CLASS (klass);
98
99   parent_class = g_type_class_peek_parent (klass);
100
101   object_class->finalize = gtk_text_mark_finalize;
102 }
103
104 static void
105 gtk_text_mark_finalize (GObject *obj)
106 {
107   GtkTextMark *mark;
108   GtkTextLineSegment *seg;
109
110   mark = GTK_TEXT_MARK (obj);
111
112   seg = mark->segment;
113
114   if (seg)
115     {
116       g_return_if_fail (seg->body.mark.tree == NULL);
117
118       if (seg->body.mark.tree != NULL)
119         g_warning ("GtkTextMark being finalized while still in the buffer; "
120                    "someone removed a reference they didn't own! Crash "
121                    "impending");
122
123       g_free (seg->body.mark.name);
124       g_free (seg);
125
126       mark->segment = NULL;
127     }
128 }
129
130 /**
131  * gtk_text_mark_get_visible:
132  * @mark: a #GtkTextMark
133  * 
134  * Returns %TRUE if the mark is visible (i.e. a cursor is displayed
135  * for it)
136  * 
137  * Return value: %TRUE if visible
138  **/
139 gboolean
140 gtk_text_mark_get_visible (GtkTextMark *mark)
141 {
142   GtkTextLineSegment *seg;
143
144   seg = mark->segment;
145
146   return seg->body.mark.visible;
147 }
148
149 /**
150  * gtk_text_mark_get_name:
151  * @mark: a #GtkTextMark
152  * 
153  * Returns the mark name; returns NULL for anonymous marks.
154  * 
155  * Return value: mark name
156  **/
157 const char *
158 gtk_text_mark_get_name (GtkTextMark *mark)
159 {
160   GtkTextLineSegment *seg;
161
162   seg = mark->segment;
163
164   return seg->body.mark.name;
165 }
166
167 /**
168  * gtk_text_mark_get_deleted:
169  * @mark: a #GtkTextMark
170  * 
171  * Returns %TRUE if the mark has been removed from its buffer
172  * with gtk_text_buffer_delete_mark(). Marks can't be used
173  * once deleted.
174  * 
175  * Return value: whether the mark is deleted
176  **/
177 gboolean
178 gtk_text_mark_get_deleted (GtkTextMark *mark)
179 {
180   GtkTextLineSegment *seg;
181
182   g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
183
184   seg = mark->segment;
185
186   if (seg == NULL)
187     return TRUE;
188
189   return seg->body.mark.tree == NULL;
190 }
191
192 /**
193  * gtk_text_mark_get_buffer:
194  * @mark: a #GtkTextMark
195  * 
196  * Gets the buffer this mark is located inside,
197  * or NULL if the mark is deleted.
198  * 
199  * Return value: the mark's #GtkTextBuffer
200  **/
201 GtkTextBuffer*
202 gtk_text_mark_get_buffer (GtkTextMark *mark)
203 {
204   GtkTextLineSegment *seg;
205
206   g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
207
208   seg = mark->segment;
209
210   if (seg->body.mark.tree == NULL)
211     return NULL;
212   else
213     return _gtk_text_btree_get_buffer (seg->body.mark.tree);
214 }
215
216 /**
217  * gtk_text_mark_get_left_gravity:
218  * @mark: a #GtkTextMark
219  * 
220  * 
221  * 
222  * Return value: %TRUE if the mark has left gravity, %FALSE otherwise
223  **/
224 gboolean
225 gtk_text_mark_get_left_gravity (GtkTextMark *mark)
226 {
227   GtkTextLineSegment *seg;
228
229   g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), FALSE);
230   
231   seg = mark->segment;
232
233   return seg->type == &gtk_text_left_mark_type;
234 }
235
236 /*
237  * Macro that determines the size of a mark segment:
238  */
239
240 #define MSEG_SIZE ((unsigned) (G_STRUCT_OFFSET (GtkTextLineSegment, body) \
241         + sizeof (GtkTextMarkBody)))
242
243
244 GtkTextLineSegment*
245 _gtk_mark_segment_new (GtkTextBTree *tree,
246                        gboolean      left_gravity,
247                        const gchar  *name)
248 {
249   GtkTextLineSegment *mark;
250
251   mark = (GtkTextLineSegment *) g_malloc0 (MSEG_SIZE);
252   mark->body.mark.name = g_strdup (name);
253
254   if (left_gravity)
255     mark->type = &gtk_text_left_mark_type;
256   else
257     mark->type = &gtk_text_right_mark_type;
258
259   mark->byte_count = 0;
260   mark->char_count = 0;
261
262   mark->body.mark.obj = g_object_new (GTK_TYPE_TEXT_MARK, NULL);
263   mark->body.mark.obj->segment = mark;
264
265   mark->body.mark.tree = tree;
266   mark->body.mark.line = NULL;
267   mark->next = NULL;
268
269   mark->body.mark.visible = FALSE;
270   mark->body.mark.not_deleteable = FALSE;
271
272   return mark;
273 }
274
275 static int                 mark_segment_delete_func  (GtkTextLineSegment *segPtr,
276                                                       GtkTextLine        *line,
277                                                       int                 treeGone);
278 static GtkTextLineSegment *mark_segment_cleanup_func (GtkTextLineSegment *segPtr,
279                                                       GtkTextLine        *line);
280 static void                mark_segment_check_func   (GtkTextLineSegment *segPtr,
281                                                       GtkTextLine        *line);
282
283
284 /*
285  * The following structures declare the "mark" segment types.
286  * There are actually two types for marks, one with left gravity
287  * and one with right gravity.  They are identical except for
288  * their gravity property.
289  */
290
291 GtkTextLineSegmentClass gtk_text_right_mark_type = {
292   "mark",                                               /* name */
293   FALSE,                                                /* leftGravity */
294   NULL,                                         /* splitFunc */
295   mark_segment_delete_func,                             /* deleteFunc */
296   mark_segment_cleanup_func,                            /* cleanupFunc */
297   NULL,                                         /* lineChangeFunc */
298   mark_segment_check_func                               /* checkFunc */
299 };
300
301 GtkTextLineSegmentClass gtk_text_left_mark_type = {
302   "mark",                                               /* name */
303   TRUE,                                         /* leftGravity */
304   NULL,                                         /* splitFunc */
305   mark_segment_delete_func,                             /* deleteFunc */
306   mark_segment_cleanup_func,                            /* cleanupFunc */
307   NULL,                                         /* lineChangeFunc */
308   mark_segment_check_func                               /* checkFunc */
309 };
310
311 /*
312  *--------------------------------------------------------------
313  *
314  * mark_segment_delete_func --
315  *
316  *      This procedure is invoked by the text B-tree code whenever
317  *      a mark lies in a range of characters being deleted.
318  *
319  * Results:
320  *      Returns 1 to indicate that deletion has been rejected.
321  *
322  * Side effects:
323  *      None (even if the whole tree is being deleted we don't
324  *      free up the mark;  it will be done elsewhere).
325  *
326  *--------------------------------------------------------------
327  */
328
329 static gboolean
330 mark_segment_delete_func (GtkTextLineSegment *segPtr,
331                           GtkTextLine        *line,
332                           gboolean            tree_gone)
333 {
334   return TRUE;
335 }
336
337 /*
338  *--------------------------------------------------------------
339  *
340  * mark_segment_cleanup_func --
341  *
342  *      This procedure is invoked by the B-tree code whenever a
343  *      mark segment is moved from one line to another.
344  *
345  * Results:
346  *      None.
347  *
348  * Side effects:
349  *      The line field of the segment gets updated.
350  *
351  *--------------------------------------------------------------
352  */
353
354 static GtkTextLineSegment *
355 mark_segment_cleanup_func (GtkTextLineSegment *seg,
356                            GtkTextLine        *line)
357 {
358   /* not sure why Tk did this here and not in LineChangeFunc */
359   seg->body.mark.line = line;
360   return seg;
361 }
362
363 /*
364  *--------------------------------------------------------------
365  *
366  * mark_segment_check_func --
367  *
368  *      This procedure is invoked by the B-tree code to perform
369  *      consistency checks on mark segments.
370  *
371  * Results:
372  *      None.
373  *
374  * Side effects:
375  *      The procedure panics if it detects anything wrong with
376  *      the mark.
377  *
378  *--------------------------------------------------------------
379  */
380
381 static void
382 mark_segment_check_func (GtkTextLineSegment *seg,
383                          GtkTextLine        *line)
384 {
385   if (seg->body.mark.line != line)
386     g_error ("mark_segment_check_func: seg->body.mark.line bogus");
387 }