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