1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3     sparse_view.c
4     Copyright (C) 2006 Sebastien Granjoux
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20 
21 /*
22  * It is a GtkTextView with an associated GtkAjustment, allowing to put in the
23  * GtkTextView only a part of a big amount of text. Cursor movements are not
24  * limited by the GtkTextView content but by the GtkAjustment.
25  *---------------------------------------------------------------------------*/
26 
27 #include "sparse_view.h"
28 
29 /*#define DEBUG*/
30 #include <libanjuta/anjuta-debug.h>
31 #include <libanjuta/interfaces/ianjuta-markable.h>
32 
33 #include <glib/gi18n.h>
34 
35 #include <gdk/gdkkeysyms.h>
36 
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include <gtk/gtk.h>
41 
42 /* Constants
43  *---------------------------------------------------------------------------*/
44 
45 /* Minimum size left window showing address */
46 #define MIN_NUMBER_WINDOW_WIDTH		20
47 #define GUTTER_PIXMAP 			16
48 #define COMPOSITE_ALPHA                 225
49 
50 #define MAX_MARKER		32	/* Must be smaller than the number of bits in an int */
51 
52 /* Order is important, as marker with the lowest number is drawn first */
53 #define SPARSE_VIEW_BOOKMARK                0
54 #define SPARSE_VIEW_BREAKPOINT_DISABLED     1
55 #define SPARSE_VIEW_BREAKPOINT_ENABLED      2
56 #define SPARSE_VIEW_PROGRAM_COUNTER         3
57 #define SPARSE_VIEW_LINEMARKER              4
58 
59 #define MARKER_PIXMAP_BOOKMARK "anjuta-bookmark-16.png"
60 #define MARKER_PIXMAP_LINEMARKER "anjuta-linemark-16.png"
61 #define MARKER_PIXMAP_PROGRAM_COUNTER "anjuta-pcmark-16.png"
62 #define MARKER_PIXMAP_BREAKPOINT_DISABLED "anjuta-breakpoint-disabled-16.png"
63 #define MARKER_PIXMAP_BREAKPOINT_ENABLED "anjuta-breakpoint-enabled-16.png"
64 
65 /* Types
66  *---------------------------------------------------------------------------*/
67 
68 enum {
69 	PROP_0,
70 	PROP_BUFFER,
71 	PROP_SHOW_LINE_NUMBERS,
72 	PROP_SHOW_LINE_MARKERS,
73 };
74 
75 struct _DmaSparseViewPrivate
76 {
77 	gboolean 	 show_line_numbers;
78 	gboolean	 show_line_markers;
79 
80 	DmaSparseBuffer* buffer;
81 	DmaSparseIter start;
82 	GtkAdjustment *vadjustment;
83 	GtkAdjustment *dummy_vadjustment;
84 
85 	GtkWidget *goto_window;
86 	GtkWidget *goto_entry;
87 
88 	gint line_by_page;
89 	gint char_by_line;
90 
91 	guint stamp;
92 
93 	GdkPixbuf *marker_pixbuf[MAX_MARKER];
94 };
95 
96 static void dma_sparse_view_init (DmaSparseView *view);
97 
G_DEFINE_TYPE(DmaSparseView,dma_sparse_view,GTK_TYPE_TEXT_VIEW)98 G_DEFINE_TYPE (DmaSparseView, dma_sparse_view, GTK_TYPE_TEXT_VIEW)
99 
100 
101 /* Helper functions
102  *---------------------------------------------------------------------------*/
103 
104 /* Cut and paste from gtkwindow.c */
105 static void
106 send_focus_change (GtkWidget *widget,
107                    gboolean   in)
108 {
109         GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
110 
111 #if !GTK_CHECK_VERSION (2,21,0)
112         g_object_ref (widget);
113 
114         if (in)
115                 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
116         else
117                 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
118 #endif
119 
120         fevent->focus_change.type = GDK_FOCUS_CHANGE;
121         fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
122         fevent->focus_change.in = in;
123 #if !GTK_CHECK_VERSION (2,21,0)
124         gtk_widget_event (widget, fevent);
125 
126         g_object_notify (G_OBJECT (widget), "has-focus");
127 
128         g_object_unref (widget);
129 #else
130 	gtk_widget_send_focus_change (widget, fevent);
131 #endif
132 
133         gdk_event_free (fevent);
134 }
135 
136 /* Goto address window
137  *---------------------------------------------------------------------------*/
138 
139 static void
dma_sparse_view_goto_window_hide(DmaSparseView * view)140 dma_sparse_view_goto_window_hide (DmaSparseView *view)
141 {
142   gtk_widget_hide (view->priv->goto_window);
143 }
144 
145 static gboolean
dma_sparse_view_goto_delete_event(GtkWidget * widget,GdkEventAny * event,DmaSparseView * view)146 dma_sparse_view_goto_delete_event (GtkWidget *widget,
147 								 GdkEventAny *event,
148 								 DmaSparseView *view)
149 {
150 	g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
151 
152 	dma_sparse_view_goto_window_hide (view);
153 
154 	return TRUE;
155 }
156 
157 static gboolean
dma_sparse_view_goto_key_press_event(GtkWidget * widget,GdkEventKey * event,DmaSparseView * view)158 dma_sparse_view_goto_key_press_event (GtkWidget *widget,
159 									GdkEventKey *event,
160 									DmaSparseView *view)
161 {
162 	g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
163 	g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
164 
165 	/* Close window */
166 	if (event->keyval == GDK_KEY_Escape ||
167 		event->keyval == GDK_KEY_Tab ||
168 		event->keyval == GDK_KEY_KP_Tab ||
169 		event->keyval == GDK_KEY_ISO_Left_Tab)
170     {
171 		dma_sparse_view_goto_window_hide (view);
172 		return TRUE;
173     }
174 
175 	/* Goto to address and close window */
176 	if (event->keyval == GDK_KEY_Return ||
177 		event->keyval == GDK_KEY_ISO_Enter ||
178 		event->keyval == GDK_KEY_KP_Enter)
179 	{
180 		gulong adr;
181 		const gchar *text;
182 		gchar *end;
183 
184 		text = gtk_entry_get_text (GTK_ENTRY (view->priv->goto_entry));
185 		adr = strtoul (text, &end, 0);
186 
187 		if ((*text != '\0') && (*end == '\0'))
188 		{
189 			/* Valid input goto to address */
190 			dma_sparse_view_goto (view, adr);
191 		}
192 
193 		dma_sparse_view_goto_window_hide (view);
194 		return TRUE;
195 	}
196 
197 	return FALSE;
198 }
199 
200 static void
dma_sparse_view_goto_position_func(DmaSparseView * view)201 dma_sparse_view_goto_position_func (DmaSparseView *view)
202 {
203 	gint x, y;
204 	gint win_x, win_y;
205 	GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (view));
206 	GdkScreen *screen = gdk_window_get_screen (window);
207 	gint monitor_num;
208 	GdkRectangle monitor;
209 
210 	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
211 	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
212 
213 	gtk_widget_realize (view->priv->goto_window);
214 
215 	gdk_window_get_origin (window, &win_x, &win_y);
216 	x = MAX(12, win_x + 12);
217 	y = MAX(12, win_y + 12);
218 
219 	gtk_window_move (GTK_WINDOW (view->priv->goto_window), x, y);
220 }
221 
222 static void
dma_sparse_view_goto_activate(GtkWidget * menu_item,DmaSparseView * view)223 dma_sparse_view_goto_activate (GtkWidget   *menu_item,
224 		       DmaSparseView *view)
225 {
226 	GtkWidget *toplevel;
227 	GtkWidget *frame;
228 	GtkWidget *vbox;
229 	GtkWindowGroup *toplevel_group, *goto_window_group;
230 
231 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
232 	toplevel_group = gtk_window_get_group (GTK_WINDOW (toplevel));
233 
234 	if (view->priv->goto_window != NULL)
235 	{
236 		goto_window_group = gtk_window_get_group (GTK_WINDOW (view->priv->goto_window));
237 
238 		if (toplevel_group)
239 			gtk_window_group_add_window (toplevel_group,
240 						     GTK_WINDOW (view->priv->goto_window));
241 		else if (goto_window_group)
242 			gtk_window_group_remove_window (goto_window_group,
243 							GTK_WINDOW (view->priv->goto_window));
244 
245 	}
246 	else
247 	{
248 		view->priv->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
249 
250 		if (toplevel_group)
251 			gtk_window_group_add_window (toplevel_group,
252 						     GTK_WINDOW (view->priv->goto_window));
253 
254 		gtk_window_set_modal (GTK_WINDOW (view->priv->goto_window), TRUE);
255 		g_signal_connect (view->priv->goto_window, "delete_event",
256 				  G_CALLBACK (dma_sparse_view_goto_delete_event),
257 				  view);
258 		g_signal_connect (view->priv->goto_window, "key_press_event",
259 				  G_CALLBACK (dma_sparse_view_goto_key_press_event),
260 				  view);
261 
262 		frame = gtk_frame_new (NULL);
263 		gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
264 		gtk_widget_show (frame);
265 		gtk_container_add (GTK_CONTAINER (view->priv->goto_window), frame);
266 
267 		vbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
268 		gtk_widget_show (vbox);
269 		gtk_container_add (GTK_CONTAINER (frame), vbox);
270 		gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
271 
272 		/* add entry */
273 		view->priv->goto_entry = gtk_entry_new ();
274 		gtk_entry_set_icon_from_stock (GTK_ENTRY (view->priv->goto_entry),
275 									   GTK_ENTRY_ICON_PRIMARY,
276 									   GTK_STOCK_JUMP_TO);
277 		gtk_widget_show (view->priv->goto_entry);
278 		gtk_container_add (GTK_CONTAINER (vbox),
279 				   view->priv->goto_entry);
280 
281 		gtk_widget_realize (view->priv->goto_entry);
282 	}
283 
284 	dma_sparse_view_goto_position_func (view);
285 	gtk_entry_set_text (GTK_ENTRY (view->priv->goto_entry), "0x");
286 	gtk_widget_show (view->priv->goto_window);
287 
288 	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
289 	gtk_widget_grab_focus (view->priv->goto_entry);
290 	send_focus_change (view->priv->goto_entry, TRUE);
291 	gtk_editable_set_position (GTK_EDITABLE (view->priv->goto_entry), -1);
292 }
293 
294 /* Properties functions
295  *---------------------------------------------------------------------------*/
296 
297 /**
298  * dma_sparse_view_get_show_line_numbers:
299  * @view: a #DmaSparseView.
300  *
301  * Returns whether line numbers are displayed beside the text.
302  *
303  * Return value: %TRUE if the line numbers are displayed.
304  **/
305 gboolean
dma_sparse_view_get_show_line_numbers(DmaSparseView * view)306 dma_sparse_view_get_show_line_numbers (DmaSparseView *view)
307 {
308 	g_return_val_if_fail (view != NULL, FALSE);
309 	g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
310 
311 	return view->priv->show_line_numbers;
312 }
313 
314 /**
315  * dma_sparse_view_set_show_line_numbers:
316  * @view: a #DmaSparseView.
317  * @show: whether line numbers should be displayed.
318  *
319  * If %TRUE line numbers will be displayed beside the text.
320  *
321  **/
322 void
dma_sparse_view_set_show_line_numbers(DmaSparseView * view,gboolean show)323 dma_sparse_view_set_show_line_numbers (DmaSparseView *view, gboolean show)
324 {
325 	g_return_if_fail (view != NULL);
326 	g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
327 
328 	show = (show != FALSE);
329 
330 	if (show)
331 	{
332 		if (!view->priv->show_line_numbers)
333 		{
334 			/* Set left margin to minimum width if no margin is
335 			   visible yet. Otherwise, just queue a redraw, so the
336 			   expose handler will automatically adjust the margin. */
337 			if (!view->priv->show_line_markers)
338 				gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
339 								      GTK_TEXT_WINDOW_LEFT,
340 								      MIN_NUMBER_WINDOW_WIDTH);
341 			else
342 				gtk_widget_queue_draw (GTK_WIDGET (view));
343 
344 			view->priv->show_line_numbers = show;
345 
346 			g_object_notify (G_OBJECT (view), "show_line_numbers");
347 		}
348 	}
349 	else
350 	{
351 		if (view->priv->show_line_numbers)
352 		{
353 			view->priv->show_line_numbers = show;
354 
355 			/* force expose event, which will adjust margin. */
356 			gtk_widget_queue_draw (GTK_WIDGET (view));
357 
358 			g_object_notify (G_OBJECT (view), "show_line_numbers");
359 		}
360 	}
361 }
362 
363 /**
364  * dma_sparse_view_get_show_line_markers:
365  * @view: a #DmaSparseView.
366  *
367  * Returns whether line markers are displayed beside the text.
368  *
369  * Return value: %TRUE if the line markers are displayed.
370  **/
371 gboolean
dma_sparse_view_get_show_line_markers(DmaSparseView * view)372 dma_sparse_view_get_show_line_markers (DmaSparseView *view)
373 {
374 	g_return_val_if_fail (view != NULL, FALSE);
375 	g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
376 
377 	return view->priv->show_line_markers;
378 }
379 
380 /**
381  * dma_sparse_view_set_show_line_markers:
382  * @view: a #DmaSparseView.
383  * @show: whether line markers should be displayed.
384  *
385  * If %TRUE line markers will be displayed beside the text.
386  *
387  **/
388 void
dma_sparse_view_set_show_line_markers(DmaSparseView * view,gboolean show)389 dma_sparse_view_set_show_line_markers (DmaSparseView *view, gboolean show)
390 {
391 	g_return_if_fail (view != NULL);
392 	g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
393 
394 	show = (show != FALSE);
395 
396 	if (show)
397 	{
398 		if (!view->priv->show_line_markers)
399 		{
400 			/* Set left margin to minimum width if no margin is
401 			   visible yet. Otherwise, just queue a redraw, so the
402 			   expose handler will automatically adjust the margin. */
403 			if (!view->priv->show_line_numbers)
404 				gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
405 								      GTK_TEXT_WINDOW_LEFT,
406 								      MIN_NUMBER_WINDOW_WIDTH);
407 			else
408 				gtk_widget_queue_draw (GTK_WIDGET (view));
409 
410 			view->priv->show_line_markers = show;
411 
412 			g_object_notify (G_OBJECT (view), "show_line_markers");
413 		}
414 	}
415 	else
416 	{
417 		if (view->priv->show_line_markers)
418 		{
419 			view->priv->show_line_markers = show;
420 
421 			/* force expose event, which will adjust margin. */
422 			gtk_widget_queue_draw (GTK_WIDGET (view));
423 
424 			g_object_notify (G_OBJECT (view), "show_line_markers");
425 		}
426 	}
427 }
428 
429 /* Markers private functions
430  *---------------------------------------------------------------------------*/
431 
432 static gint
marker_ianjuta_to_view(IAnjutaMarkableMarker marker)433 marker_ianjuta_to_view (IAnjutaMarkableMarker marker)
434 {
435         gint mark;
436         switch (marker)
437         {
438                 case IANJUTA_MARKABLE_LINEMARKER:
439                         mark = SPARSE_VIEW_LINEMARKER;
440                         break;
441                 case IANJUTA_MARKABLE_BOOKMARK:
442                         mark = SPARSE_VIEW_BOOKMARK;
443                         break;
444                 case IANJUTA_MARKABLE_BREAKPOINT_DISABLED:
445                         mark = SPARSE_VIEW_BREAKPOINT_DISABLED;
446                         break;
447                 case IANJUTA_MARKABLE_BREAKPOINT_ENABLED:
448                         mark = SPARSE_VIEW_BREAKPOINT_ENABLED;
449                         break;
450                 case IANJUTA_MARKABLE_PROGRAM_COUNTER:
451                         mark = SPARSE_VIEW_PROGRAM_COUNTER;
452                         break;
453                 default:
454                         mark = SPARSE_VIEW_LINEMARKER;
455         }
456 
457         return mark;
458 }
459 
460 static void
dma_sparse_view_initialize_marker(DmaSparseView * view)461 dma_sparse_view_initialize_marker (DmaSparseView *view)
462 {
463 	view->priv->marker_pixbuf[SPARSE_VIEW_BOOKMARK] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR "/" MARKER_PIXMAP_BOOKMARK, NULL);
464 	view->priv->marker_pixbuf[SPARSE_VIEW_BREAKPOINT_DISABLED] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR "/" MARKER_PIXMAP_BREAKPOINT_DISABLED, NULL);
465 	view->priv->marker_pixbuf[SPARSE_VIEW_BREAKPOINT_ENABLED] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR "/" MARKER_PIXMAP_BREAKPOINT_ENABLED, NULL);
466 	view->priv->marker_pixbuf[SPARSE_VIEW_PROGRAM_COUNTER] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR "/" MARKER_PIXMAP_PROGRAM_COUNTER, NULL);
467 	view->priv->marker_pixbuf[SPARSE_VIEW_LINEMARKER] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR "/" MARKER_PIXMAP_LINEMARKER, NULL);
468 }
469 
470 static void
dma_sparse_view_free_marker(DmaSparseView * view)471 dma_sparse_view_free_marker (DmaSparseView *view)
472 {
473 	gint i;
474 
475 	for (i = 0; i < MAX_MARKER; i++)
476 	{
477 		if (view->priv->marker_pixbuf[i] != NULL)
478 		{
479 			g_object_unref (view->priv->marker_pixbuf[i]);
480 			view->priv->marker_pixbuf[i] = NULL;
481 		}
482 	}
483 }
484 
485 /* Private functions
486  *---------------------------------------------------------------------------*/
487 
488 static void
dma_sparse_view_populate_popup(DmaSparseView * view,GtkMenu * menu,DmaSparseView * user_data)489 dma_sparse_view_populate_popup (DmaSparseView *view,
490 							  GtkMenu *menu,
491 							  DmaSparseView *user_data)
492 {
493 	GtkWidget *menu_item;
494 
495 	/* separator */
496 	menu_item = gtk_menu_item_new ();
497 	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
498 	gtk_widget_show (menu_item);
499 
500 	/* create goto menu_item. */
501 	menu_item = gtk_menu_item_new_with_mnemonic (_("_Go to address"));
502 	g_signal_connect (G_OBJECT (menu_item), "activate",
503 			  G_CALLBACK (dma_sparse_view_goto_activate), view);
504 	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
505 	gtk_widget_show (menu_item);
506 }
507 
508 
509 static void
dma_sparse_view_move_cursor(GtkTextView * text_view,GtkMovementStep step,gint count,gboolean extend_selection)510 dma_sparse_view_move_cursor (GtkTextView *text_view,
511 			     GtkMovementStep step,
512 			     gint            count,
513 			     gboolean        extend_selection)
514 {
515 	DmaSparseView *view = DMA_SPARSE_VIEW (text_view);
516 
517 	switch (step)
518     {
519     case GTK_MOVEMENT_LOGICAL_POSITIONS:
520     case GTK_MOVEMENT_VISUAL_POSITIONS:
521 	case GTK_MOVEMENT_WORDS:
522     case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
523     case GTK_MOVEMENT_HORIZONTAL_PAGES:
524 		break;
525     case GTK_MOVEMENT_DISPLAY_LINES:
526     case GTK_MOVEMENT_PARAGRAPHS:
527     case GTK_MOVEMENT_PARAGRAPH_ENDS:
528 
529        	dma_sparse_iter_forward_lines (&view->priv->start, count);
530 		gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (&view->priv->start));
531 		return;
532 	case GTK_MOVEMENT_PAGES:
533        	dma_sparse_iter_forward_lines (&view->priv->start, count * (view->priv->line_by_page > 1 ? view->priv->line_by_page - 1 : view->priv->line_by_page));
534 		gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (&view->priv->start));
535 		return;
536 	case GTK_MOVEMENT_BUFFER_ENDS:
537 		break;
538     default:
539         break;
540     }
541 
542 	GTK_TEXT_VIEW_CLASS (dma_sparse_view_parent_class)->move_cursor (text_view,
543 								 step, count,
544 								 extend_selection);
545 }
546 
547 static void
dma_sparse_view_synchronize_iter(DmaSparseView * view,DmaSparseIter * iter)548 dma_sparse_view_synchronize_iter (DmaSparseView *view, DmaSparseIter *iter)
549 {
550 	gdouble dist;
551 	gdouble pos;
552 	/* Need to change iterator according to adjustment */
553 
554 	pos = gtk_adjustment_get_value (view->priv->vadjustment);
555 	dist = pos - (gdouble)dma_sparse_iter_get_address (iter);
556 
557 	if (dist != 0)
558 	{
559 		gdouble page_size = gtk_adjustment_get_page_size (view->priv->vadjustment);
560 
561 		if ((dist < 4.0 * page_size) && (dist > -4.0 * page_size))
562 		{
563 			gint count = (gint) (dist / gtk_adjustment_get_step_increment (view->priv->vadjustment));
564 
565 			dma_sparse_iter_forward_lines (iter, count);
566 		}
567 		else
568 		{
569 			dma_sparse_iter_move_at (iter, pos);
570 			dma_sparse_iter_round (iter, FALSE);
571 		}
572 		gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (iter));
573 	}
574 }
575 
576 static void
draw_line_markers(DmaSparseView * view,gint current_marker,gint x,gint y)577 draw_line_markers (DmaSparseView *view,
578 		   gint		current_marker,
579 		   gint     x,
580 		   gint     y)
581 {
582 	GdkPixbuf *composite;
583 	gint width, height;
584 	gint i;
585 
586 	composite = NULL;
587 	width = height = 0;
588 
589 	/* composite all the pixbufs for the markers present at the line */
590 	for (i = 0; i < MAX_MARKER; i++)
591 	{
592 		if (current_marker & (1 << i))
593 		{
594 			GdkPixbuf *pixbuf = view->priv->marker_pixbuf[i];
595 
596 			if (pixbuf)
597 			{
598 				if (!composite)
599 				{
600 					composite = gdk_pixbuf_copy (pixbuf);
601 					width = gdk_pixbuf_get_width (composite);
602 					height = gdk_pixbuf_get_height (composite);
603 				}
604 				else
605 				{
606 					gint pixbuf_w;
607 					gint pixbuf_h;
608 
609 					pixbuf_w = gdk_pixbuf_get_width (pixbuf);
610 					pixbuf_h = gdk_pixbuf_get_height (pixbuf);
611 					gdk_pixbuf_composite (pixbuf,
612 							      composite,
613 							      0, 0,
614 						    	  width, height,
615 							      	0, 0,
616 							      	(double) pixbuf_w / width,
617 							      (double) pixbuf_h / height,
618 							      GDK_INTERP_BILINEAR,
619 							      COMPOSITE_ALPHA);
620 				}
621 				//g_object_unref (pixbuf);
622 			}
623 			else
624 			{
625 				g_warning ("Unknown marker %d used", i);
626 			}
627 			current_marker &= ~ (1 << i);
628 			if (current_marker == 0) break;
629 		}
630 	}
631 
632 	/* render the result to the left window */
633 	if (composite)
634 	{
635 		GdkWindow *window;
636 		cairo_t *cr;
637 
638 		window = gtk_text_view_get_window (GTK_TEXT_VIEW (view),
639 						   GTK_TEXT_WINDOW_LEFT);
640 
641 		cr = gdk_cairo_create (window);
642 
643 		gdk_cairo_set_source_pixbuf (cr, composite, x, y);
644 		cairo_paint (cr);
645 
646 		g_object_unref (composite);
647 		cairo_destroy (cr);
648 	}
649 }
650 
651 static void
dma_sparse_view_paint_margin(DmaSparseView * view,cairo_t * cr)652 dma_sparse_view_paint_margin (DmaSparseView *view,
653 			  				  cairo_t *cr)
654 {
655 	GtkTextView *text_view;
656 	PangoLayout *layout;
657 	gint y1, y2;
658 	gint y, height;
659 	gchar str [16];
660 	gint margin_width;
661 	gint margin_length;
662 	gint text_width;
663 	DmaSparseIter buf_iter;
664 	GtkTextIter text_iter;
665 	guint prev_address = G_MAXUINT;
666 
667 
668 	text_view = GTK_TEXT_VIEW (view);
669 
670 	if (!view->priv->show_line_numbers && !view->priv->show_line_markers)
671 	{
672 		gtk_text_view_set_border_window_size (text_view,
673 						      GTK_TEXT_WINDOW_LEFT,
674 						      0);
675 
676 		return;
677 	}
678 
679 
680 	/* FIXME */
681 	y1 = 0;
682 	y2 = gtk_widget_get_allocated_height (GTK_WIDGET (view)) + y1;
683 
684 	/* get the extents of the line printing */
685 	gtk_text_view_window_to_buffer_coords (text_view,
686 					       GTK_TEXT_WINDOW_LEFT,
687 					       0,
688 					       y1,
689 					       NULL,
690 					       &y1);
691 
692 	gtk_text_view_window_to_buffer_coords (text_view,
693 					       GTK_TEXT_WINDOW_LEFT,
694 					       0,
695 					       y2,
696 					       NULL,
697 					       &y2);
698 
699 	/* set size. */
700 	g_snprintf (str, sizeof (str), "0x%X", G_MAXUINT);
701 	margin_length = strlen(str) - 2;
702 	layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), str);
703 
704 	pango_layout_get_pixel_size (layout, &text_width, NULL);
705 
706 	pango_layout_set_width (layout, text_width);
707 	pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
708 
709 	/* determine the width of the left margin. */
710 	if (view->priv->show_line_numbers)
711 		margin_width = text_width + 4;
712 	else
713 		margin_width = 0;
714 
715 	if (view->priv->show_line_markers)
716 		margin_width += GUTTER_PIXMAP;
717 
718 	g_return_if_fail (margin_width != 0);
719 
720 	gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
721 					      GTK_TEXT_WINDOW_LEFT,
722 					      margin_width);
723 
724 	/* Display all addresses */
725 	dma_sparse_iter_copy (&buf_iter, &view->priv->start);
726 	gtk_text_buffer_get_start_iter (gtk_text_view_get_buffer (text_view), &text_iter);
727 
728 
729 
730 	/* Skip line while position doesn't need to be repaint */
731 	gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
732 	if (y < y1)
733 	{
734 		do
735 		{
736 			if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return;
737 			if (!gtk_text_iter_forward_line (&text_iter)) return;
738 			gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
739 		} while (y < y1);
740 	}
741 
742 
743 	/* Display address */
744 	do
745 	{
746 		gint pos;
747 		guint address;
748 
749 		gtk_text_view_buffer_to_window_coords (text_view,
750 						       GTK_TEXT_WINDOW_LEFT,
751 						       0,
752 						       y,
753 						       NULL,
754 						       &pos);
755 
756 		address = dma_sparse_iter_get_address (&buf_iter);
757 
758 		if (view->priv->show_line_numbers)
759 		{
760 			g_snprintf (str, sizeof (str),"0x%0*lX", margin_length, (long unsigned int)address);
761 			pango_layout_set_markup (layout, str, -1);
762 
763 			gtk_render_layout (gtk_widget_get_style_context (GTK_WIDGET (view)),
764 			                   cr, text_width + 2, pos, layout);
765 		}
766 
767 		/* Display marker */
768 		if ((prev_address != address) && (view->priv->show_line_markers))
769 		{
770 			gint current_marker = dma_sparse_buffer_get_marks (view->priv->buffer, address);
771 
772 			if (current_marker)
773 			{
774 				gint x;
775 
776 				if (view->priv->show_line_numbers)
777 					x = text_width + 4;
778 				else
779 					x = 0;
780 
781 				draw_line_markers (view, current_marker, x, pos);
782 				prev_address = address;
783 			}
784 		}
785 
786 		if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return;
787 		if (!gtk_text_iter_forward_line (&text_iter)) return;
788 		gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
789 
790 	} while (y < y2);
791 
792 	g_object_unref (G_OBJECT (layout));
793 }
794 
795 static void
dma_sparse_view_update_adjustement(DmaSparseView * view)796 dma_sparse_view_update_adjustement (DmaSparseView *view)
797 {
798 	PangoLayout *layout;
799 	GdkRectangle text_area;
800 	int height;
801 
802 	gtk_text_view_get_visible_rect(GTK_TEXT_VIEW (view), &text_area);
803 	layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), "0123456789ABCDEFGHIJKLMNOPQRSTUVWWYZ,");
804 	pango_layout_get_pixel_size(layout, NULL, &height);
805 	g_object_unref (G_OBJECT (layout));
806 
807 	view->priv->line_by_page = text_area.height / height;
808 	view->priv->char_by_line = 8;
809 
810 	if (view->priv->vadjustment != NULL)
811 	{
812 		GtkAdjustment *vadj = view->priv->vadjustment;
813 		gdouble step_increment, page_size;
814 
815 		step_increment = view->priv->char_by_line;
816 		page_size = (view->priv->line_by_page - 1) * step_increment;
817 
818 		gtk_adjustment_set_step_increment (vadj, step_increment);
819 		gtk_adjustment_set_page_size (vadj, page_size);
820 		gtk_adjustment_set_page_increment (vadj, page_size * 0.9);
821 		gtk_adjustment_changed (vadj);
822 	}
823 }
824 
825 static void
dma_sparse_view_value_changed(GtkAdjustment * adj,DmaSparseView * view)826 dma_sparse_view_value_changed (GtkAdjustment *adj,
827                                DmaSparseView *view)
828 {
829 	dma_sparse_view_synchronize_iter (view, &view->priv->start);
830 	dma_sparse_view_refresh (view);
831 }
832 
833 
834 static void
dma_sparse_view_notify_vadjustment(DmaSparseView * view,GParamSpec * pspec,gpointer user_data)835 dma_sparse_view_notify_vadjustment (DmaSparseView *view,
836                                     GParamSpec *pspec,
837                                     gpointer    user_data)
838 {
839 	GtkAdjustment *vadj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(view));
840 
841 	g_return_if_fail (vadj == NULL || GTK_IS_ADJUSTMENT (vadj));
842 
843 	/* Skip notification if the adjustment has been set by this function below */
844 	if (vadj == view->priv->dummy_vadjustment) return;
845 
846 	g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
847 
848 	if (view->priv->vadjustment)
849 	{
850 		g_signal_handlers_disconnect_by_func (view->priv->vadjustment,
851 		                                      dma_sparse_view_value_changed,
852 		                                      view);
853 		g_object_unref (view->priv->vadjustment);
854 	}
855 
856 	if (vadj != NULL)
857 	{
858 		/* Steal the new GtkAdjustment from the GtkTextView widget and
859 		 * replace it with a dummy adjustment */
860 		g_object_ref_sink (vadj);
861 
862 		if (view->priv->dummy_vadjustment == NULL)
863 		{
864 			/* Create a dummy adjustment */
865 			view->priv->dummy_vadjustment = g_object_ref_sink (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
866 		}
867 		gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (view), view->priv->dummy_vadjustment);
868 
869 		/* Connect to the real adjustment and configure it as we need */
870 		g_signal_connect (vadj, "value_changed",
871 		                  G_CALLBACK (dma_sparse_view_value_changed),
872 		                  view);
873 
874 		if (view->priv->buffer != NULL)
875 		{
876 			gtk_adjustment_set_upper (vadj, dma_sparse_buffer_get_upper (view->priv->buffer));
877 			gtk_adjustment_set_lower (vadj, dma_sparse_buffer_get_lower (view->priv->buffer));
878 			gtk_adjustment_set_value (vadj, 0);
879 		}
880 	}
881 	view->priv->vadjustment = vadj;
882 	dma_sparse_view_update_adjustement (view);
883 }
884 
885 /* Public functions
886  *---------------------------------------------------------------------------*/
887 
888 void
dma_sparse_view_set_sparse_buffer(DmaSparseView * view,DmaSparseBuffer * buffer)889 dma_sparse_view_set_sparse_buffer (DmaSparseView *view, DmaSparseBuffer *buffer)
890 {
891 	g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
892 	g_return_if_fail (DMA_IS_SPARSE_BUFFER (buffer));
893 
894 	g_clear_object (&view->priv->buffer);
895 	view->priv->buffer = g_object_ref (buffer);
896 
897 	if (view->priv->vadjustment != NULL)
898 	{
899 		gtk_adjustment_set_upper (view->priv->vadjustment, dma_sparse_buffer_get_upper (view->priv->buffer));
900 		gtk_adjustment_set_lower (view->priv->vadjustment, dma_sparse_buffer_get_lower (view->priv->buffer));
901 		gtk_adjustment_set_value (view->priv->vadjustment, 0);
902 		dma_sparse_view_update_adjustement (view);
903 	}
904 	dma_sparse_buffer_get_iterator_at_address (buffer, &view->priv->start, 0);
905 	dma_sparse_view_refresh (view);
906 }
907 
908 DmaSparseBuffer *
dma_sparse_view_get_sparse_buffer(DmaSparseView * view)909 dma_sparse_view_get_sparse_buffer (DmaSparseView *view)
910 {
911 	return view->priv->buffer;
912 }
913 
914 void
dma_sparse_view_refresh(DmaSparseView * view)915 dma_sparse_view_refresh (DmaSparseView *view)
916 {
917 	gint offset;
918 	GtkTextIter cur;
919 	GtkTextMark *mark;
920 	GtkTextIter start, end;
921 	GtkTextBuffer *buffer;
922 
923 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
924 	/* Save all cursor offset */
925     mark = gtk_text_buffer_get_insert (buffer);
926     gtk_text_buffer_get_iter_at_mark (buffer, &cur, mark);
927     offset = gtk_text_iter_get_offset (&cur);
928 
929 	/* Remove old data */
930 	view->priv->stamp++;
931 	gtk_text_buffer_get_bounds (buffer, &start, &end);
932 	gtk_text_buffer_delete (buffer, &start, &end);
933 	gtk_text_buffer_get_iter_at_offset (buffer, &end, 0);
934 
935 	/* Get data */
936 	dma_sparse_iter_insert_lines (&view->priv->start, &end, view->priv->line_by_page);
937 
938 	/* Restore cursor */
939     mark = gtk_text_buffer_get_insert (buffer);
940     gtk_text_buffer_get_iter_at_mark(buffer, &cur, mark);
941 	gtk_text_iter_set_offset (&cur, offset);
942 	gtk_text_buffer_move_mark_by_name (buffer, "insert", &cur);
943 	gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cur);
944 }
945 
946 /* Markers functions
947  *---------------------------------------------------------------------------*/
948 
949 gint
dma_sparse_view_mark(DmaSparseView * view,guint location,gint marker)950 dma_sparse_view_mark (DmaSparseView *view, guint location, gint marker)
951 {
952 	dma_sparse_buffer_add_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
953 	gtk_widget_queue_draw (GTK_WIDGET (view));
954 
955 	return (gint)location;
956 }
957 
958 void
dma_sparse_view_unmark(DmaSparseView * view,guint location,gint marker)959 dma_sparse_view_unmark (DmaSparseView *view, guint location, gint marker)
960 {
961 	dma_sparse_buffer_remove_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
962 	gtk_widget_queue_draw (GTK_WIDGET (view));
963 }
964 
965 void
dma_sparse_view_delete_all_markers(DmaSparseView * view,gint marker)966 dma_sparse_view_delete_all_markers (DmaSparseView *view, gint marker)
967 {
968 	dma_sparse_buffer_remove_all_mark (view->priv->buffer, marker_ianjuta_to_view(marker));
969 }
970 
971 void
dma_sparse_view_goto(DmaSparseView * view,guint location)972 dma_sparse_view_goto (DmaSparseView *view, guint location)
973 {
974 	dma_sparse_iter_move_at (&view->priv->start, location);
975 	gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)location);
976 	gtk_adjustment_value_changed (view->priv->vadjustment);
977 }
978 
979 guint
dma_sparse_view_get_location(DmaSparseView * view)980 dma_sparse_view_get_location (DmaSparseView *view)
981 {
982 	GtkTextMark *mark;
983 	GtkTextBuffer *buffer;
984 	GtkTextIter iter;
985 	DmaSparseIter buf_iter;
986 	gint line;
987 
988 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
989 	mark = gtk_text_buffer_get_insert (buffer);
990 	gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
991 	line = gtk_text_iter_get_line (&iter);
992 
993 	dma_sparse_iter_copy (&buf_iter, &view->priv->start);
994 	dma_sparse_iter_forward_lines (&buf_iter, line);
995 
996 	return dma_sparse_iter_get_address (&buf_iter);
997 }
998 
999 /* GtkWidget functions
1000  *---------------------------------------------------------------------------*/
1001 
1002 static gint
dma_sparse_view_draw(GtkWidget * widget,cairo_t * cr)1003 dma_sparse_view_draw (GtkWidget      *widget,
1004                       cairo_t *cr)
1005 {
1006 	DmaSparseView *view;
1007 	GtkTextView *text_view;
1008 	gboolean event_handled;
1009 
1010 	view = DMA_SPARSE_VIEW (widget);
1011 	text_view = GTK_TEXT_VIEW (widget);
1012 
1013 	event_handled = FALSE;
1014 
1015 	/* now check for the left window, which contains the margin */
1016 	if (gtk_cairo_should_draw_window (cr, gtk_text_view_get_window (text_view,
1017 	                                                                GTK_TEXT_WINDOW_LEFT)))
1018 	{
1019 		dma_sparse_view_paint_margin (view, cr);
1020 		event_handled = TRUE;
1021 	}
1022 	else
1023 	{
1024 		event_handled = GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->draw (widget, cr);
1025 	}
1026 
1027 	return event_handled;
1028 }
1029 
1030 static void
dma_sparse_view_size_allocate(GtkWidget * widget,GtkAllocation * allocation)1031 dma_sparse_view_size_allocate (GtkWidget *widget,
1032                              GtkAllocation *allocation)
1033 {
1034 	DmaSparseView *view;
1035 
1036 	view = DMA_SPARSE_VIEW (widget);
1037 
1038 	GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->size_allocate (widget, allocation);
1039 
1040 	dma_sparse_view_update_adjustement (view);
1041 	dma_sparse_view_refresh (view);
1042 }
1043 
1044 /* GtkObject functions
1045  *---------------------------------------------------------------------------*/
1046 
1047 static void
dma_sparse_view_destroy(GtkWidget * object)1048 dma_sparse_view_destroy (GtkWidget *object)
1049 {
1050 	DmaSparseView *view;
1051 
1052 	g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1053 
1054 	view = DMA_SPARSE_VIEW (object);
1055 
1056 	if (view->priv->goto_window)
1057 	{
1058 		gtk_widget_destroy (view->priv->goto_window);
1059 		view->priv->goto_window = NULL;
1060 		view->priv->goto_entry = NULL;
1061 	}
1062 
1063 	if (view->priv->dummy_vadjustment)
1064 	{
1065 		g_object_unref (G_OBJECT (view->priv->dummy_vadjustment));
1066 		view->priv->dummy_vadjustment = NULL;
1067 	}
1068 
1069 	GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->destroy (object);
1070 }
1071 
1072 /* GObject functions
1073  *---------------------------------------------------------------------------*/
1074 
1075 static void
dma_sparse_view_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1076 dma_sparse_view_set_property (GObject *object,guint prop_id, const GValue *value, GParamSpec *pspec)
1077 {
1078 	DmaSparseView *view;
1079 
1080 	g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1081 
1082 	view = DMA_SPARSE_VIEW (object);
1083 
1084 	switch (prop_id)
1085 	{
1086 		case PROP_BUFFER:
1087 			dma_sparse_view_set_sparse_buffer (view, g_value_get_object (value));
1088 			break;
1089 		case PROP_SHOW_LINE_NUMBERS:
1090 			dma_sparse_view_set_show_line_numbers (view, g_value_get_boolean (value));
1091 			break;
1092 		case PROP_SHOW_LINE_MARKERS:
1093 			dma_sparse_view_set_show_line_markers (view, g_value_get_boolean (value));
1094 			break;
1095 		default:
1096 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1097 			break;
1098 	}
1099 }
1100 
1101 static void
dma_sparse_view_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1102 dma_sparse_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1103 {
1104 	DmaSparseView *view;
1105 
1106 	g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1107 
1108 	view = DMA_SPARSE_VIEW (object);
1109 
1110 	switch (prop_id)
1111 	{
1112 		case PROP_BUFFER:
1113 			g_value_set_object (value, view->priv->buffer);
1114 			break;
1115 		case PROP_SHOW_LINE_NUMBERS:
1116 			g_value_set_boolean (value, dma_sparse_view_get_show_line_numbers (view));
1117 			break;
1118 		case PROP_SHOW_LINE_MARKERS:
1119 			g_value_set_boolean (value, dma_sparse_view_get_show_line_markers (view));
1120 			break;
1121 		default:
1122 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1123 			break;
1124 	}
1125 }
1126 
1127 /* dispose is the first destruction step. It is used to unref object created
1128  * with instance_init in order to break reference counting cycles. This
1129  * function could be called several times. All function should still work
1130  * after this call. It has to called its parents.*/
1131 
1132 static void
dma_sparse_view_dispose(GObject * object)1133 dma_sparse_view_dispose (GObject *object)
1134 {
1135 	DmaSparseView *view = DMA_SPARSE_VIEW (object);
1136 
1137 	g_clear_object (&view->priv->buffer);
1138 
1139 	G_OBJECT_CLASS (dma_sparse_view_parent_class)->dispose (object);
1140 }
1141 
1142 /* finalize is the last destruction step. It must free all memory allocated
1143  * with instance_init. It is called only one time just before releasing all
1144  * memory */
1145 
1146 static void
dma_sparse_view_finalize(GObject * object)1147 dma_sparse_view_finalize (GObject *object)
1148 {
1149 	DmaSparseView *view;
1150 
1151 	g_return_if_fail (object != NULL);
1152 	g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1153 
1154 	view = DMA_SPARSE_VIEW (object);
1155 
1156 	dma_sparse_view_free_marker (view);
1157 
1158 	G_OBJECT_CLASS (dma_sparse_view_parent_class)->finalize (object);
1159 }
1160 
1161 /* instance_init is the constructor. All functions should work after this
1162  * call. */
1163 
1164 static void
dma_sparse_view_init(DmaSparseView * view)1165 dma_sparse_view_init (DmaSparseView *view)
1166 {
1167 	PangoFontDescription *font_desc;
1168 
1169 	view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, DMA_SPARSE_VIEW_TYPE,
1170 	                                          DmaSparseViewPrivate);
1171 
1172 	view->priv->buffer = NULL;
1173 
1174 	view->priv->goto_window = NULL;
1175 	view->priv->goto_entry = NULL;
1176 
1177 	view->priv->show_line_numbers = TRUE;
1178 	view->priv->show_line_markers = TRUE;
1179 
1180 	view->priv->stamp = 0;
1181 
1182 	memset (view->priv->marker_pixbuf, 0, sizeof (view->priv->marker_pixbuf));
1183 
1184 	g_signal_connect (view, "notify::vadjustment",
1185 	                  G_CALLBACK (dma_sparse_view_notify_vadjustment), view);
1186 
1187 	gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 2);
1188 	gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 2);
1189 
1190 	g_signal_connect (view, "populate_popup",
1191                         G_CALLBACK (dma_sparse_view_populate_popup), view);
1192 
1193 	gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
1194 								      GTK_TEXT_WINDOW_LEFT,
1195 								      MIN_NUMBER_WINDOW_WIDTH);
1196 
1197 	font_desc = pango_font_description_from_string ("Monospace 10");
1198 	gtk_widget_override_font (GTK_WIDGET (view), font_desc);
1199 	pango_font_description_free (font_desc);
1200 
1201 	dma_sparse_view_initialize_marker (view);
1202 }
1203 
1204 /* class_init intialize the class itself not the instance */
1205 
1206 static void
dma_sparse_view_class_init(DmaSparseViewClass * klass)1207 dma_sparse_view_class_init (DmaSparseViewClass * klass)
1208 {
1209 	GObjectClass *gobject_class;
1210 	GtkWidgetClass   *widget_class;
1211 	GtkTextViewClass *text_view_class;
1212 
1213 	g_return_if_fail (klass != NULL);
1214 
1215 	gobject_class = (GObjectClass *) klass;
1216 	widget_class = GTK_WIDGET_CLASS (klass);
1217 	text_view_class = GTK_TEXT_VIEW_CLASS (klass);
1218 
1219 	gobject_class->dispose = dma_sparse_view_dispose;
1220 	gobject_class->finalize = dma_sparse_view_finalize;
1221 	gobject_class->get_property = dma_sparse_view_get_property;
1222 	gobject_class->set_property = dma_sparse_view_set_property;
1223 
1224 	widget_class->destroy = dma_sparse_view_destroy;
1225 
1226 	widget_class->size_allocate = dma_sparse_view_size_allocate;
1227 	widget_class->draw = dma_sparse_view_draw;
1228 
1229 	text_view_class->move_cursor = dma_sparse_view_move_cursor;
1230 
1231 	g_type_class_add_private (klass, sizeof (DmaSparseViewPrivate));
1232 
1233 	g_object_class_install_property (gobject_class,
1234 					 PROP_BUFFER,
1235 					 g_param_spec_object ("buffer",
1236 							       "Buffer",
1237 							       "The DmaSparseBuffer that is displayed",
1238 					               DMA_SPARSE_BUFFER_TYPE,
1239 							       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1240 
1241 	g_object_class_install_property (gobject_class,
1242 					 PROP_SHOW_LINE_NUMBERS,
1243 					 g_param_spec_boolean ("show_line_numbers",
1244 							       _("Show Line Numbers"),
1245 							       _("Whether to display line numbers"),
1246 							       FALSE,
1247 							       G_PARAM_READWRITE));
1248 
1249 	g_object_class_install_property (gobject_class,
1250 					 PROP_SHOW_LINE_MARKERS,
1251 					 g_param_spec_boolean ("show_line_markers",
1252 							       _("Show Line Markers"),
1253 							       _("Whether to display line marker pixbufs"),
1254 							       FALSE,
1255 							       G_PARAM_READWRITE));
1256 }
1257 
1258 /* Creation and Destruction
1259  *---------------------------------------------------------------------------*/
1260 
1261 GtkWidget*
dma_sparse_view_new_with_buffer(DmaSparseBuffer * buffer)1262 dma_sparse_view_new_with_buffer (DmaSparseBuffer *buffer)
1263 {
1264 	GtkWidget *view;
1265 
1266 	view = g_object_new (DMA_SPARSE_VIEW_TYPE, "buffer", buffer, NULL);
1267 	g_assert (view != NULL);
1268 
1269 	return view;
1270 }
1271