Updated Spanish translation
[anjuta.git] / plugins / debug-manager / sparse_view.c
blob9ae6a38c0f197123b76dc5c39dd53fc961b6ba2d
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
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.
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.
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
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 *---------------------------------------------------------------------------*/
27 #include "sparse_view.h"
29 /*#define DEBUG*/
30 #include <libanjuta/anjuta-debug.h>
31 #include <libanjuta/interfaces/ianjuta-markable.h>
33 #include <glib/gi18n.h>
35 #include <gdk/gdkkeysyms.h>
37 #include <stdlib.h>
38 #include <string.h>
40 #include <gtk/gtk.h>
42 /* Constants
43 *---------------------------------------------------------------------------*/
45 /* Minimum size left window showing address */
46 #define MIN_NUMBER_WINDOW_WIDTH 20
47 #define GUTTER_PIXMAP 16
48 #define COMPOSITE_ALPHA 225
50 #define MAX_MARKER 32 /* Must be smaller than the number of bits in an int */
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
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"
65 /* Types
66 *---------------------------------------------------------------------------*/
68 enum {
69 PROP_0,
70 PROP_BUFFER,
71 PROP_SHOW_LINE_NUMBERS,
72 PROP_SHOW_LINE_MARKERS,
75 struct _DmaSparseViewPrivate
77 gboolean show_line_numbers;
78 gboolean show_line_markers;
80 DmaSparseBuffer* buffer;
81 DmaSparseIter start;
82 GtkAdjustment *vadjustment;
83 GtkAdjustment *dummy_vadjustment;
85 GtkWidget *goto_window;
86 GtkWidget *goto_entry;
88 gint line_by_page;
89 gint char_by_line;
91 guint stamp;
93 GdkPixbuf *marker_pixbuf[MAX_MARKER];
96 static void dma_sparse_view_init (DmaSparseView *view);
98 G_DEFINE_TYPE (DmaSparseView, dma_sparse_view, GTK_TYPE_TEXT_VIEW)
101 /* Helper functions
102 *---------------------------------------------------------------------------*/
104 /* Cut and paste from gtkwindow.c */
105 static void
106 send_focus_change (GtkWidget *widget,
107 gboolean in)
109 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
111 #if !GTK_CHECK_VERSION (2,21,0)
112 g_object_ref (widget);
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
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);
126 g_object_notify (G_OBJECT (widget), "has-focus");
128 g_object_unref (widget);
129 #else
130 gtk_widget_send_focus_change (widget, fevent);
131 #endif
133 gdk_event_free (fevent);
136 /* Goto address window
137 *---------------------------------------------------------------------------*/
139 static void
140 dma_sparse_view_goto_window_hide (DmaSparseView *view)
142 gtk_widget_hide (view->priv->goto_window);
145 static gboolean
146 dma_sparse_view_goto_delete_event (GtkWidget *widget,
147 GdkEventAny *event,
148 DmaSparseView *view)
150 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
152 dma_sparse_view_goto_window_hide (view);
154 return TRUE;
157 static gboolean
158 dma_sparse_view_goto_key_press_event (GtkWidget *widget,
159 GdkEventKey *event,
160 DmaSparseView *view)
162 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
163 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
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)
171 dma_sparse_view_goto_window_hide (view);
172 return TRUE;
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)
180 gulong adr;
181 const gchar *text;
182 gchar *end;
184 text = gtk_entry_get_text (GTK_ENTRY (view->priv->goto_entry));
185 adr = strtoul (text, &end, 0);
187 if ((*text != '\0') && (*end == '\0'))
189 /* Valid input goto to address */
190 dma_sparse_view_goto (view, adr);
193 dma_sparse_view_goto_window_hide (view);
194 return TRUE;
197 return FALSE;
200 static void
201 dma_sparse_view_goto_position_func (DmaSparseView *view)
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;
210 monitor_num = gdk_screen_get_monitor_at_window (screen, window);
211 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
213 gtk_widget_realize (view->priv->goto_window);
215 gdk_window_get_origin (window, &win_x, &win_y);
216 x = MAX(12, win_x + 12);
217 y = MAX(12, win_y + 12);
219 gtk_window_move (GTK_WINDOW (view->priv->goto_window), x, y);
222 static void
223 dma_sparse_view_goto_activate (GtkWidget *menu_item,
224 DmaSparseView *view)
226 GtkWidget *toplevel;
227 GtkWidget *frame;
228 GtkWidget *vbox;
229 GtkWindowGroup *toplevel_group, *goto_window_group;
231 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
232 toplevel_group = gtk_window_get_group (GTK_WINDOW (toplevel));
234 if (view->priv->goto_window != NULL)
236 goto_window_group = gtk_window_get_group (GTK_WINDOW (view->priv->goto_window));
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));
246 else
248 view->priv->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
250 if (toplevel_group)
251 gtk_window_group_add_window (toplevel_group,
252 GTK_WINDOW (view->priv->goto_window));
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);
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);
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);
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);
281 gtk_widget_realize (view->priv->goto_entry);
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);
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);
294 /* Properties functions
295 *---------------------------------------------------------------------------*/
298 * dma_sparse_view_get_show_line_numbers:
299 * @view: a #DmaSparseView.
301 * Returns whether line numbers are displayed beside the text.
303 * Return value: %TRUE if the line numbers are displayed.
305 gboolean
306 dma_sparse_view_get_show_line_numbers (DmaSparseView *view)
308 g_return_val_if_fail (view != NULL, FALSE);
309 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
311 return view->priv->show_line_numbers;
315 * dma_sparse_view_set_show_line_numbers:
316 * @view: a #DmaSparseView.
317 * @show: whether line numbers should be displayed.
319 * If %TRUE line numbers will be displayed beside the text.
322 void
323 dma_sparse_view_set_show_line_numbers (DmaSparseView *view, gboolean show)
325 g_return_if_fail (view != NULL);
326 g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
328 show = (show != FALSE);
330 if (show)
332 if (!view->priv->show_line_numbers)
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));
344 view->priv->show_line_numbers = show;
346 g_object_notify (G_OBJECT (view), "show_line_numbers");
349 else
351 if (view->priv->show_line_numbers)
353 view->priv->show_line_numbers = show;
355 /* force expose event, which will adjust margin. */
356 gtk_widget_queue_draw (GTK_WIDGET (view));
358 g_object_notify (G_OBJECT (view), "show_line_numbers");
364 * dma_sparse_view_get_show_line_markers:
365 * @view: a #DmaSparseView.
367 * Returns whether line markers are displayed beside the text.
369 * Return value: %TRUE if the line markers are displayed.
371 gboolean
372 dma_sparse_view_get_show_line_markers (DmaSparseView *view)
374 g_return_val_if_fail (view != NULL, FALSE);
375 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
377 return view->priv->show_line_markers;
381 * dma_sparse_view_set_show_line_markers:
382 * @view: a #DmaSparseView.
383 * @show: whether line markers should be displayed.
385 * If %TRUE line markers will be displayed beside the text.
388 void
389 dma_sparse_view_set_show_line_markers (DmaSparseView *view, gboolean show)
391 g_return_if_fail (view != NULL);
392 g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
394 show = (show != FALSE);
396 if (show)
398 if (!view->priv->show_line_markers)
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));
410 view->priv->show_line_markers = show;
412 g_object_notify (G_OBJECT (view), "show_line_markers");
415 else
417 if (view->priv->show_line_markers)
419 view->priv->show_line_markers = show;
421 /* force expose event, which will adjust margin. */
422 gtk_widget_queue_draw (GTK_WIDGET (view));
424 g_object_notify (G_OBJECT (view), "show_line_markers");
429 /* Markers private functions
430 *---------------------------------------------------------------------------*/
432 static gint
433 marker_ianjuta_to_view (IAnjutaMarkableMarker marker)
435 gint mark;
436 switch (marker)
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;
457 return mark;
460 static void
461 dma_sparse_view_initialize_marker (DmaSparseView *view)
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);
470 static void
471 dma_sparse_view_free_marker (DmaSparseView *view)
473 gint i;
475 for (i = 0; i < MAX_MARKER; i++)
477 if (view->priv->marker_pixbuf[i] != NULL)
479 g_object_unref (view->priv->marker_pixbuf[i]);
480 view->priv->marker_pixbuf[i] = NULL;
485 /* Private functions
486 *---------------------------------------------------------------------------*/
488 static void
489 dma_sparse_view_populate_popup (DmaSparseView *view,
490 GtkMenu *menu,
491 DmaSparseView *user_data)
493 GtkWidget *menu_item;
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);
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);
509 static void
510 dma_sparse_view_move_cursor (GtkTextView *text_view,
511 GtkMovementStep step,
512 gint count,
513 gboolean extend_selection)
515 DmaSparseView *view = DMA_SPARSE_VIEW (text_view);
517 switch (step)
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:
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;
542 GTK_TEXT_VIEW_CLASS (dma_sparse_view_parent_class)->move_cursor (text_view,
543 step, count,
544 extend_selection);
547 static void
548 dma_sparse_view_synchronize_iter (DmaSparseView *view, DmaSparseIter *iter)
550 gdouble dist;
551 gdouble pos;
552 /* Need to change iterator according to adjustment */
554 pos = gtk_adjustment_get_value (view->priv->vadjustment);
555 dist = pos - (gdouble)dma_sparse_iter_get_address (iter);
557 if (dist != 0)
559 gdouble page_size = gtk_adjustment_get_page_size (view->priv->vadjustment);
561 if ((dist < 4.0 * page_size) && (dist > -4.0 * page_size))
563 gint count = (gint) (dist / gtk_adjustment_get_step_increment (view->priv->vadjustment));
565 dma_sparse_iter_forward_lines (iter, count);
567 else
569 dma_sparse_iter_move_at (iter, pos);
570 dma_sparse_iter_round (iter, FALSE);
572 gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (iter));
576 static void
577 draw_line_markers (DmaSparseView *view,
578 gint current_marker,
579 gint x,
580 gint y)
582 GdkPixbuf *composite;
583 gint width, height;
584 gint i;
586 composite = NULL;
587 width = height = 0;
589 /* composite all the pixbufs for the markers present at the line */
590 for (i = 0; i < MAX_MARKER; i++)
592 if (current_marker & (1 << i))
594 GdkPixbuf *pixbuf = view->priv->marker_pixbuf[i];
596 if (pixbuf)
598 if (!composite)
600 composite = gdk_pixbuf_copy (pixbuf);
601 width = gdk_pixbuf_get_width (composite);
602 height = gdk_pixbuf_get_height (composite);
604 else
606 gint pixbuf_w;
607 gint pixbuf_h;
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);
621 //g_object_unref (pixbuf);
623 else
625 g_warning ("Unknown marker %d used", i);
627 current_marker &= ~ (1 << i);
628 if (current_marker == 0) break;
632 /* render the result to the left window */
633 if (composite)
635 GdkWindow *window;
636 cairo_t *cr;
638 window = gtk_text_view_get_window (GTK_TEXT_VIEW (view),
639 GTK_TEXT_WINDOW_LEFT);
641 cr = gdk_cairo_create (window);
643 gdk_cairo_set_source_pixbuf (cr, composite, x, y);
644 cairo_paint (cr);
646 g_object_unref (composite);
647 cairo_destroy (cr);
651 static void
652 dma_sparse_view_paint_margin (DmaSparseView *view,
653 cairo_t *cr)
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;
668 text_view = GTK_TEXT_VIEW (view);
670 if (!view->priv->show_line_numbers && !view->priv->show_line_markers)
672 gtk_text_view_set_border_window_size (text_view,
673 GTK_TEXT_WINDOW_LEFT,
676 return;
680 /* FIXME */
681 y1 = 0;
682 y2 = gtk_widget_get_allocated_height (GTK_WIDGET (view)) + y1;
684 /* get the extents of the line printing */
685 gtk_text_view_window_to_buffer_coords (text_view,
686 GTK_TEXT_WINDOW_LEFT,
689 NULL,
690 &y1);
692 gtk_text_view_window_to_buffer_coords (text_view,
693 GTK_TEXT_WINDOW_LEFT,
696 NULL,
697 &y2);
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);
704 pango_layout_get_pixel_size (layout, &text_width, NULL);
706 pango_layout_set_width (layout, text_width);
707 pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
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;
715 if (view->priv->show_line_markers)
716 margin_width += GUTTER_PIXMAP;
718 g_return_if_fail (margin_width != 0);
720 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
721 GTK_TEXT_WINDOW_LEFT,
722 margin_width);
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);
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)
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);
743 /* Display address */
746 gint pos;
747 guint address;
749 gtk_text_view_buffer_to_window_coords (text_view,
750 GTK_TEXT_WINDOW_LEFT,
753 NULL,
754 &pos);
756 address = dma_sparse_iter_get_address (&buf_iter);
758 if (view->priv->show_line_numbers)
760 g_snprintf (str, sizeof (str),"0x%0*lX", margin_length, (long unsigned int)address);
761 pango_layout_set_markup (layout, str, -1);
763 gtk_render_layout (gtk_widget_get_style_context (GTK_WIDGET (view)),
764 cr, text_width + 2, pos, layout);
767 /* Display marker */
768 if ((prev_address != address) && (view->priv->show_line_markers))
770 gint current_marker = dma_sparse_buffer_get_marks (view->priv->buffer, address);
772 if (current_marker)
774 gint x;
776 if (view->priv->show_line_numbers)
777 x = text_width + 4;
778 else
779 x = 0;
781 draw_line_markers (view, current_marker, x, pos);
782 prev_address = address;
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);
790 } while (y < y2);
792 g_object_unref (G_OBJECT (layout));
795 static void
796 dma_sparse_view_update_adjustement (DmaSparseView *view)
798 PangoLayout *layout;
799 GdkRectangle text_area;
800 int height;
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));
807 view->priv->line_by_page = text_area.height / height;
808 view->priv->char_by_line = 8;
810 if (view->priv->vadjustment != NULL)
812 GtkAdjustment *vadj = view->priv->vadjustment;
813 gdouble step_increment, page_size;
815 step_increment = view->priv->char_by_line;
816 page_size = (view->priv->line_by_page - 1) * step_increment;
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);
825 static void
826 dma_sparse_view_value_changed (GtkAdjustment *adj,
827 DmaSparseView *view)
829 dma_sparse_view_synchronize_iter (view, &view->priv->start);
830 dma_sparse_view_refresh (view);
834 static void
835 dma_sparse_view_notify_vadjustment (DmaSparseView *view,
836 GParamSpec *pspec,
837 gpointer user_data)
839 GtkAdjustment *vadj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(view));
841 g_return_if_fail (vadj == NULL || GTK_IS_ADJUSTMENT (vadj));
843 /* Skip notification if the adjustment has been set by this function below */
844 if (vadj == view->priv->dummy_vadjustment) return;
846 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
848 if (view->priv->vadjustment)
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);
856 if (vadj != NULL)
858 /* Steal the new GtkAdjustment from the GtkTextView widget and
859 * replace it with a dummy adjustment */
860 g_object_ref_sink (vadj);
862 if (view->priv->dummy_vadjustment == NULL)
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));
867 gtk_scrollable_set_vadjustment (GTK_SCROLLABLE (view), view->priv->dummy_vadjustment);
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);
874 if (view->priv->buffer != NULL)
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);
881 view->priv->vadjustment = vadj;
882 dma_sparse_view_update_adjustement (view);
885 /* Public functions
886 *---------------------------------------------------------------------------*/
888 void
889 dma_sparse_view_set_sparse_buffer (DmaSparseView *view, DmaSparseBuffer *buffer)
891 g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
892 g_return_if_fail (DMA_IS_SPARSE_BUFFER (buffer));
894 g_clear_object (&view->priv->buffer);
895 view->priv->buffer = g_object_ref (buffer);
897 if (view->priv->vadjustment != NULL)
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);
904 dma_sparse_buffer_get_iterator_at_address (buffer, &view->priv->start, 0);
905 dma_sparse_view_refresh (view);
908 DmaSparseBuffer *
909 dma_sparse_view_get_sparse_buffer (DmaSparseView *view)
911 return view->priv->buffer;
914 void
915 dma_sparse_view_refresh (DmaSparseView *view)
917 gint offset;
918 GtkTextIter cur;
919 GtkTextMark *mark;
920 GtkTextIter start, end;
921 GtkTextBuffer *buffer;
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);
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);
935 /* Get data */
936 dma_sparse_iter_insert_lines (&view->priv->start, &end, view->priv->line_by_page);
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);
946 /* Markers functions
947 *---------------------------------------------------------------------------*/
949 gint
950 dma_sparse_view_mark (DmaSparseView *view, guint location, gint marker)
952 dma_sparse_buffer_add_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
953 gtk_widget_queue_draw (GTK_WIDGET (view));
955 return (gint)location;
958 void
959 dma_sparse_view_unmark (DmaSparseView *view, guint location, gint marker)
961 dma_sparse_buffer_remove_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
962 gtk_widget_queue_draw (GTK_WIDGET (view));
965 void
966 dma_sparse_view_delete_all_markers (DmaSparseView *view, gint marker)
968 dma_sparse_buffer_remove_all_mark (view->priv->buffer, marker_ianjuta_to_view(marker));
971 void
972 dma_sparse_view_goto (DmaSparseView *view, guint location)
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);
979 guint
980 dma_sparse_view_get_location (DmaSparseView *view)
982 GtkTextMark *mark;
983 GtkTextBuffer *buffer;
984 GtkTextIter iter;
985 DmaSparseIter buf_iter;
986 gint line;
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);
993 dma_sparse_iter_copy (&buf_iter, &view->priv->start);
994 dma_sparse_iter_forward_lines (&buf_iter, line);
996 return dma_sparse_iter_get_address (&buf_iter);
999 /* GtkWidget functions
1000 *---------------------------------------------------------------------------*/
1002 static gint
1003 dma_sparse_view_draw (GtkWidget *widget,
1004 cairo_t *cr)
1006 DmaSparseView *view;
1007 GtkTextView *text_view;
1008 gboolean event_handled;
1010 view = DMA_SPARSE_VIEW (widget);
1011 text_view = GTK_TEXT_VIEW (widget);
1013 event_handled = FALSE;
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)))
1019 dma_sparse_view_paint_margin (view, cr);
1020 event_handled = TRUE;
1022 else
1024 event_handled = GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->draw (widget, cr);
1027 return event_handled;
1030 static void
1031 dma_sparse_view_size_allocate (GtkWidget *widget,
1032 GtkAllocation *allocation)
1034 DmaSparseView *view;
1036 view = DMA_SPARSE_VIEW (widget);
1038 GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->size_allocate (widget, allocation);
1040 dma_sparse_view_update_adjustement (view);
1041 dma_sparse_view_refresh (view);
1044 /* GtkObject functions
1045 *---------------------------------------------------------------------------*/
1047 static void
1048 dma_sparse_view_destroy (GtkWidget *object)
1050 DmaSparseView *view;
1052 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1054 view = DMA_SPARSE_VIEW (object);
1056 if (view->priv->goto_window)
1058 gtk_widget_destroy (view->priv->goto_window);
1059 view->priv->goto_window = NULL;
1060 view->priv->goto_entry = NULL;
1063 if (view->priv->dummy_vadjustment)
1065 g_object_unref (G_OBJECT (view->priv->dummy_vadjustment));
1066 view->priv->dummy_vadjustment = NULL;
1069 GTK_WIDGET_CLASS (dma_sparse_view_parent_class)->destroy (object);
1072 /* GObject functions
1073 *---------------------------------------------------------------------------*/
1075 static void
1076 dma_sparse_view_set_property (GObject *object,guint prop_id, const GValue *value, GParamSpec *pspec)
1078 DmaSparseView *view;
1080 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1082 view = DMA_SPARSE_VIEW (object);
1084 switch (prop_id)
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;
1101 static void
1102 dma_sparse_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1104 DmaSparseView *view;
1106 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1108 view = DMA_SPARSE_VIEW (object);
1110 switch (prop_id)
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;
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.*/
1132 static void
1133 dma_sparse_view_dispose (GObject *object)
1135 DmaSparseView *view = DMA_SPARSE_VIEW (object);
1137 g_clear_object (&view->priv->buffer);
1139 G_OBJECT_CLASS (dma_sparse_view_parent_class)->dispose (object);
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 */
1146 static void
1147 dma_sparse_view_finalize (GObject *object)
1149 DmaSparseView *view;
1151 g_return_if_fail (object != NULL);
1152 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1154 view = DMA_SPARSE_VIEW (object);
1156 dma_sparse_view_free_marker (view);
1158 G_OBJECT_CLASS (dma_sparse_view_parent_class)->finalize (object);
1161 /* instance_init is the constructor. All functions should work after this
1162 * call. */
1164 static void
1165 dma_sparse_view_init (DmaSparseView *view)
1167 PangoFontDescription *font_desc;
1169 view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, DMA_SPARSE_VIEW_TYPE,
1170 DmaSparseViewPrivate);
1172 view->priv->buffer = NULL;
1174 view->priv->goto_window = NULL;
1175 view->priv->goto_entry = NULL;
1177 view->priv->show_line_numbers = TRUE;
1178 view->priv->show_line_markers = TRUE;
1180 view->priv->stamp = 0;
1182 memset (view->priv->marker_pixbuf, 0, sizeof (view->priv->marker_pixbuf));
1184 g_signal_connect (view, "notify::vadjustment",
1185 G_CALLBACK (dma_sparse_view_notify_vadjustment), view);
1187 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 2);
1188 gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 2);
1190 g_signal_connect (view, "populate_popup",
1191 G_CALLBACK (dma_sparse_view_populate_popup), view);
1193 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
1194 GTK_TEXT_WINDOW_LEFT,
1195 MIN_NUMBER_WINDOW_WIDTH);
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);
1201 dma_sparse_view_initialize_marker (view);
1204 /* class_init intialize the class itself not the instance */
1206 static void
1207 dma_sparse_view_class_init (DmaSparseViewClass * klass)
1209 GObjectClass *gobject_class;
1210 GtkWidgetClass *widget_class;
1211 GtkTextViewClass *text_view_class;
1213 g_return_if_fail (klass != NULL);
1215 gobject_class = (GObjectClass *) klass;
1216 widget_class = GTK_WIDGET_CLASS (klass);
1217 text_view_class = GTK_TEXT_VIEW_CLASS (klass);
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;
1224 widget_class->destroy = dma_sparse_view_destroy;
1226 widget_class->size_allocate = dma_sparse_view_size_allocate;
1227 widget_class->draw = dma_sparse_view_draw;
1229 text_view_class->move_cursor = dma_sparse_view_move_cursor;
1231 g_type_class_add_private (klass, sizeof (DmaSparseViewPrivate));
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));
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));
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));
1258 /* Creation and Destruction
1259 *---------------------------------------------------------------------------*/
1261 GtkWidget*
1262 dma_sparse_view_new_with_buffer (DmaSparseBuffer *buffer)
1264 GtkWidget *view;
1266 view = g_object_new (DMA_SPARSE_VIEW_TYPE, "buffer", buffer, NULL);
1267 g_assert (view != NULL);
1269 return view;