* plugins/debug-manager/disassemble.c,
[anjuta-git-plugin.git] / plugins / debug-manager / sparse_view.c
blob1e8989754ac45066af57bb64e8980f8c2d691e71
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 "sexy-icon-entry.h"
35 #include <libgnome/gnome-i18n.h>
37 #include <gdk/gdkkeysyms.h>
39 #include <stdlib.h>
40 #include <string.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_SHOW_LINE_NUMBERS,
71 PROP_SHOW_LINE_MARKERS,
74 struct _DmaSparseViewPrivate
76 GtkTextView parent;
78 gboolean show_line_numbers;
79 gboolean show_line_markers;
81 DmaSparseBuffer* buffer;
82 DmaSparseIter start;
83 GtkAdjustment *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 /* Used in dispose and finalize */
97 static GtkTextViewClass *parent_class = NULL;
99 /* Helper functions
100 *---------------------------------------------------------------------------*/
102 /* Cut and paste from gtkwindow.c */
103 static void
104 send_focus_change (GtkWidget *widget,
105 gboolean in)
107 GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
109 g_object_ref (widget);
111 if (in)
112 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
113 else
114 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
116 fevent->focus_change.type = GDK_FOCUS_CHANGE;
117 fevent->focus_change.window = g_object_ref (widget->window);
118 fevent->focus_change.in = in;
120 gtk_widget_event (widget, fevent);
122 g_object_notify (G_OBJECT (widget), "has-focus");
124 g_object_unref (widget);
125 gdk_event_free (fevent);
128 /* Goto address window
129 *---------------------------------------------------------------------------*/
131 static void
132 dma_sparse_view_goto_window_hide (DmaSparseView *view)
134 gtk_widget_hide (view->priv->goto_window);
137 static gboolean
138 dma_sparse_view_goto_delete_event (GtkWidget *widget,
139 GdkEventAny *event,
140 DmaSparseView *view)
142 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
144 dma_sparse_view_goto_window_hide (view);
146 return TRUE;
149 static gboolean
150 dma_sparse_view_goto_key_press_event (GtkWidget *widget,
151 GdkEventKey *event,
152 DmaSparseView *view)
154 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
155 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
157 /* Close window */
158 if (event->keyval == GDK_Escape ||
159 event->keyval == GDK_Tab ||
160 event->keyval == GDK_KP_Tab ||
161 event->keyval == GDK_ISO_Left_Tab)
163 dma_sparse_view_goto_window_hide (view);
164 return TRUE;
167 /* Goto to address and close window */
168 if (event->keyval == GDK_Return ||
169 event->keyval == GDK_ISO_Enter ||
170 event->keyval == GDK_KP_Enter)
172 gulong adr;
173 const gchar *text;
174 gchar *end;
176 text = gtk_entry_get_text (GTK_ENTRY (view->priv->goto_entry));
177 adr = strtoul (text, &end, 0);
179 if ((*text != '\0') && (*end == '\0'))
181 /* Valid input goto to address */
182 dma_sparse_view_goto (view, adr);
185 dma_sparse_view_goto_window_hide (view);
186 return TRUE;
189 return FALSE;
192 static void
193 dma_sparse_view_goto_position_func (DmaSparseView *view)
195 gint x, y;
196 gint win_x, win_y;
197 GdkWindow *window = GTK_WIDGET (view)->window;
198 GdkScreen *screen = gdk_drawable_get_screen (window);
199 gint monitor_num;
200 GdkRectangle monitor;
202 monitor_num = gdk_screen_get_monitor_at_window (screen, window);
203 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
205 gtk_widget_realize (view->priv->goto_window);
207 gdk_window_get_origin (window, &win_x, &win_y);
208 x = MAX(12, win_x + 12);
209 y = MAX(12, win_y + 12);
211 gtk_window_move (GTK_WINDOW (view->priv->goto_window), x, y);
214 static void
215 dma_sparse_view_goto_activate (GtkWidget *menu_item,
216 DmaSparseView *view)
218 GtkWidget *toplevel;
219 GtkWidget *frame;
220 GtkWidget *vbox;
221 GtkWidget *icon;
223 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
225 if (view->priv->goto_window != NULL)
227 if (GTK_WINDOW (toplevel)->group)
228 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
229 GTK_WINDOW (view->priv->goto_window));
230 else if (GTK_WINDOW (view->priv->goto_window)->group)
231 gtk_window_group_remove_window (GTK_WINDOW (view->priv->goto_window)->group,
232 GTK_WINDOW (view->priv->goto_window));
235 else
237 view->priv->goto_window = gtk_window_new (GTK_WINDOW_POPUP);
239 if (GTK_WINDOW (toplevel)->group)
240 gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
241 GTK_WINDOW (view->priv->goto_window));
243 gtk_window_set_modal (GTK_WINDOW (view->priv->goto_window), TRUE);
244 g_signal_connect (view->priv->goto_window, "delete_event",
245 G_CALLBACK (dma_sparse_view_goto_delete_event),
246 view);
247 g_signal_connect (view->priv->goto_window, "key_press_event",
248 G_CALLBACK (dma_sparse_view_goto_key_press_event),
249 view);
251 frame = gtk_frame_new (NULL);
252 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
253 gtk_widget_show (frame);
254 gtk_container_add (GTK_CONTAINER (view->priv->goto_window), frame);
256 vbox = gtk_vbox_new (FALSE, 0);
257 gtk_widget_show (vbox);
258 gtk_container_add (GTK_CONTAINER (frame), vbox);
259 gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
261 /* add entry */
262 view->priv->goto_entry = sexy_icon_entry_new ();
263 icon = gtk_image_new_from_stock (GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU);
264 sexy_icon_entry_set_icon (SEXY_ICON_ENTRY(view->priv->goto_entry),
265 SEXY_ICON_ENTRY_PRIMARY,
266 GTK_IMAGE (icon));
267 gtk_widget_show (view->priv->goto_entry);
268 gtk_container_add (GTK_CONTAINER (vbox),
269 view->priv->goto_entry);
271 gtk_widget_realize (view->priv->goto_entry);
274 dma_sparse_view_goto_position_func (view);
275 gtk_entry_set_text (GTK_ENTRY (view->priv->goto_entry), "0x");
276 gtk_widget_show (view->priv->goto_window);
278 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
279 gtk_widget_grab_focus (view->priv->goto_entry);
280 send_focus_change (view->priv->goto_entry, TRUE);
281 gtk_editable_set_position (GTK_EDITABLE (view->priv->goto_entry), -1);
284 /* Properties functions
285 *---------------------------------------------------------------------------*/
288 * dma_sparse_view_get_show_line_numbers:
289 * @view: a #DmaSparseView.
291 * Returns whether line numbers are displayed beside the text.
293 * Return value: %TRUE if the line numbers are displayed.
295 gboolean
296 dma_sparse_view_get_show_line_numbers (DmaSparseView *view)
298 g_return_val_if_fail (view != NULL, FALSE);
299 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
301 return view->priv->show_line_numbers;
305 * dma_sparse_view_set_show_line_numbers:
306 * @view: a #DmaSparseView.
307 * @show: whether line numbers should be displayed.
309 * If %TRUE line numbers will be displayed beside the text.
312 void
313 dma_sparse_view_set_show_line_numbers (DmaSparseView *view, gboolean show)
315 g_return_if_fail (view != NULL);
316 g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
318 show = (show != FALSE);
320 if (show)
322 if (!view->priv->show_line_numbers)
324 /* Set left margin to minimum width if no margin is
325 visible yet. Otherwise, just queue a redraw, so the
326 expose handler will automatically adjust the margin. */
327 if (!view->priv->show_line_markers)
328 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
329 GTK_TEXT_WINDOW_LEFT,
330 MIN_NUMBER_WINDOW_WIDTH);
331 else
332 gtk_widget_queue_draw (GTK_WIDGET (view));
334 view->priv->show_line_numbers = show;
336 g_object_notify (G_OBJECT (view), "show_line_numbers");
339 else
341 if (view->priv->show_line_numbers)
343 view->priv->show_line_numbers = show;
345 /* force expose event, which will adjust margin. */
346 gtk_widget_queue_draw (GTK_WIDGET (view));
348 g_object_notify (G_OBJECT (view), "show_line_numbers");
354 * dma_sparse_view_get_show_line_markers:
355 * @view: a #DmaSparseView.
357 * Returns whether line markers are displayed beside the text.
359 * Return value: %TRUE if the line markers are displayed.
361 gboolean
362 dma_sparse_view_get_show_line_markers (DmaSparseView *view)
364 g_return_val_if_fail (view != NULL, FALSE);
365 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view), FALSE);
367 return view->priv->show_line_markers;
371 * dma_sparse_view_set_show_line_markers:
372 * @view: a #DmaSparseView.
373 * @show: whether line markers should be displayed.
375 * If %TRUE line markers will be displayed beside the text.
378 void
379 dma_sparse_view_set_show_line_markers (DmaSparseView *view, gboolean show)
381 g_return_if_fail (view != NULL);
382 g_return_if_fail (DMA_IS_SPARSE_VIEW (view));
384 show = (show != FALSE);
386 if (show)
388 if (!view->priv->show_line_markers)
390 /* Set left margin to minimum width if no margin is
391 visible yet. Otherwise, just queue a redraw, so the
392 expose handler will automatically adjust the margin. */
393 if (!view->priv->show_line_numbers)
394 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
395 GTK_TEXT_WINDOW_LEFT,
396 MIN_NUMBER_WINDOW_WIDTH);
397 else
398 gtk_widget_queue_draw (GTK_WIDGET (view));
400 view->priv->show_line_markers = show;
402 g_object_notify (G_OBJECT (view), "show_line_markers");
405 else
407 if (view->priv->show_line_markers)
409 view->priv->show_line_markers = show;
411 /* force expose event, which will adjust margin. */
412 gtk_widget_queue_draw (GTK_WIDGET (view));
414 g_object_notify (G_OBJECT (view), "show_line_markers");
419 /* Markers private functions
420 *---------------------------------------------------------------------------*/
422 static gint
423 marker_ianjuta_to_view (IAnjutaMarkableMarker marker)
425 gint mark;
426 switch (marker)
428 case IANJUTA_MARKABLE_LINEMARKER:
429 mark = SPARSE_VIEW_LINEMARKER;
430 break;
431 case IANJUTA_MARKABLE_BOOKMARK:
432 mark = SPARSE_VIEW_BOOKMARK;
433 break;
434 case IANJUTA_MARKABLE_BREAKPOINT_DISABLED:
435 mark = SPARSE_VIEW_BREAKPOINT_DISABLED;
436 break;
437 case IANJUTA_MARKABLE_BREAKPOINT_ENABLED:
438 mark = SPARSE_VIEW_BREAKPOINT_ENABLED;
439 break;
440 case IANJUTA_MARKABLE_PROGRAM_COUNTER:
441 mark = SPARSE_VIEW_PROGRAM_COUNTER;
442 break;
443 default:
444 mark = SPARSE_VIEW_LINEMARKER;
447 return mark;
450 static void
451 dma_sparse_view_initialize_marker (DmaSparseView *view)
453 view->priv->marker_pixbuf[SPARSE_VIEW_BOOKMARK] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"MARKER_PIXMAP_BOOKMARK, NULL);
454 view->priv->marker_pixbuf[SPARSE_VIEW_BREAKPOINT_DISABLED] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"MARKER_PIXMAP_BREAKPOINT_DISABLED, NULL);
455 view->priv->marker_pixbuf[SPARSE_VIEW_BREAKPOINT_ENABLED] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"MARKER_PIXMAP_BREAKPOINT_ENABLED, NULL);
456 view->priv->marker_pixbuf[SPARSE_VIEW_PROGRAM_COUNTER] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"MARKER_PIXMAP_PROGRAM_COUNTER, NULL);
457 view->priv->marker_pixbuf[SPARSE_VIEW_LINEMARKER] = gdk_pixbuf_new_from_file (PACKAGE_PIXMAPS_DIR"/"MARKER_PIXMAP_LINEMARKER, NULL);
460 static void
461 dma_sparse_view_free_marker (DmaSparseView *view)
463 gint i;
465 for (i = 0; i < MAX_MARKER; i++)
467 if (view->priv->marker_pixbuf[i] != NULL)
469 g_object_unref (view->priv->marker_pixbuf[i]);
470 view->priv->marker_pixbuf[i] = NULL;
475 /* Private functions
476 *---------------------------------------------------------------------------*/
478 static void
479 dma_sparse_view_populate_popup (DmaSparseView *view,
480 GtkMenu *menu,
481 DmaSparseView *user_data)
483 GtkWidget *menu_item;
485 /* separator */
486 menu_item = gtk_menu_item_new ();
487 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
488 gtk_widget_show (menu_item);
490 /* create goto menu_item. */
491 menu_item = gtk_menu_item_new_with_mnemonic ("_Goto address");
492 g_signal_connect (G_OBJECT (menu_item), "activate",
493 G_CALLBACK (dma_sparse_view_goto_activate), view);
494 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
495 gtk_widget_show (menu_item);
499 static void
500 dma_sparse_view_move_cursor (GtkTextView *text_view,
501 GtkMovementStep step,
502 gint count,
503 gboolean extend_selection)
505 DmaSparseView *view = DMA_SPARSE_VIEW (text_view);
507 switch (step)
509 case GTK_MOVEMENT_LOGICAL_POSITIONS:
510 case GTK_MOVEMENT_VISUAL_POSITIONS:
511 case GTK_MOVEMENT_WORDS:
512 case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
513 case GTK_MOVEMENT_HORIZONTAL_PAGES:
514 break;
515 case GTK_MOVEMENT_DISPLAY_LINES:
516 case GTK_MOVEMENT_PARAGRAPHS:
517 case GTK_MOVEMENT_PARAGRAPH_ENDS:
519 dma_sparse_iter_forward_lines (&view->priv->start, count);
520 gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (&view->priv->start));
521 return;
522 case GTK_MOVEMENT_PAGES:
523 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));
524 gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (&view->priv->start));
525 return;
526 case GTK_MOVEMENT_BUFFER_ENDS:
527 break;
528 default:
529 break;
532 GTK_TEXT_VIEW_CLASS (parent_class)->move_cursor (text_view,
533 step, count,
534 extend_selection);
537 static void
538 dma_sparse_view_synchronize_iter (DmaSparseView *view, DmaSparseIter *iter)
540 gdouble dist;
541 gdouble pos;
542 /* Need to change iterator according to adjustment */
544 pos = gtk_adjustment_get_value (view->priv->vadjustment);
545 dist = pos - (gdouble)dma_sparse_iter_get_address (iter);
547 if (dist != 0)
549 gint count = (gint)(dist / view->priv->vadjustment->step_increment);
551 if ((count < 2.0 * (view->priv->vadjustment->page_size))
552 && (count > -2.0 * (view->priv->vadjustment->page_size)))
554 dma_sparse_iter_forward_lines (iter, count);
556 else
558 dma_sparse_iter_move_at (iter, pos);
559 dma_sparse_iter_round (iter, FALSE);
561 gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)dma_sparse_iter_get_address (iter));
565 static void
566 draw_line_markers (DmaSparseView *view,
567 gint current_marker,
568 gint x,
569 gint y)
571 GdkPixbuf *composite;
572 gint width, height;
573 gint i;
575 composite = NULL;
576 width = height = 0;
578 /* composite all the pixbufs for the markers present at the line */
579 for (i = 0; i < MAX_MARKER; i++)
581 if (current_marker & (1 << i))
583 GdkPixbuf *pixbuf = view->priv->marker_pixbuf[i];
585 if (pixbuf)
587 if (!composite)
589 composite = gdk_pixbuf_copy (pixbuf);
590 width = gdk_pixbuf_get_width (composite);
591 height = gdk_pixbuf_get_height (composite);
593 else
595 gint pixbuf_w;
596 gint pixbuf_h;
598 pixbuf_w = gdk_pixbuf_get_width (pixbuf);
599 pixbuf_h = gdk_pixbuf_get_height (pixbuf);
600 gdk_pixbuf_composite (pixbuf,
601 composite,
602 0, 0,
603 width, height,
604 0, 0,
605 (double) pixbuf_w / width,
606 (double) pixbuf_h / height,
607 GDK_INTERP_BILINEAR,
608 COMPOSITE_ALPHA);
610 //g_object_unref (pixbuf);
612 else
614 g_warning ("Unknown marker %d used", i);
616 current_marker &= ~ (1 << i);
617 if (current_marker == 0) break;
621 /* render the result to the left window */
622 if (composite)
624 GdkWindow *window;
626 window = gtk_text_view_get_window (GTK_TEXT_VIEW (view),
627 GTK_TEXT_WINDOW_LEFT);
629 gdk_draw_pixbuf (GDK_DRAWABLE (window), NULL, composite,
630 0, 0, x, y,
631 width, height,
632 GDK_RGB_DITHER_NORMAL, 0, 0);
633 g_object_unref (composite);
637 static void
638 dma_sparse_view_paint_margin (DmaSparseView *view,
639 GdkEventExpose *event)
641 GtkTextView *text_view;
642 GdkWindow *win;
643 PangoLayout *layout;
644 gint y1, y2;
645 gint y, height;
646 gchar str [16];
647 gint margin_width;
648 gint margin_length;
649 gint text_width;
650 DmaSparseIter buf_iter;
651 GtkTextIter text_iter;
652 guint prev_address = G_MAXUINT;
655 text_view = GTK_TEXT_VIEW (view);
657 if (!view->priv->show_line_numbers && !view->priv->show_line_markers)
659 gtk_text_view_set_border_window_size (text_view,
660 GTK_TEXT_WINDOW_LEFT,
663 return;
666 win = gtk_text_view_get_window (text_view,
667 GTK_TEXT_WINDOW_LEFT);
669 y1 = event->area.y;
670 y2 = y1 + event->area.height;
672 /* get the extents of the line printing */
673 gtk_text_view_window_to_buffer_coords (text_view,
674 GTK_TEXT_WINDOW_LEFT,
677 NULL,
678 &y1);
680 gtk_text_view_window_to_buffer_coords (text_view,
681 GTK_TEXT_WINDOW_LEFT,
684 NULL,
685 &y2);
687 /* set size. */
688 g_snprintf (str, sizeof (str), "0x%X", G_MAXUINT);
689 margin_length = strlen(str) - 2;
690 layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), str);
692 pango_layout_get_pixel_size (layout, &text_width, NULL);
694 pango_layout_set_width (layout, text_width);
695 pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
697 /* determine the width of the left margin. */
698 if (view->priv->show_line_numbers)
699 margin_width = text_width + 4;
700 else
701 margin_width = 0;
703 if (view->priv->show_line_markers)
704 margin_width += GUTTER_PIXMAP;
706 g_return_if_fail (margin_width != 0);
708 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text_view),
709 GTK_TEXT_WINDOW_LEFT,
710 margin_width);
712 /* Display all addresses */
713 dma_sparse_iter_copy (&buf_iter, &view->priv->start);
714 gtk_text_buffer_get_start_iter (gtk_text_view_get_buffer (text_view), &text_iter);
718 /* Skip line while position doesn't need to be repaint */
719 gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
720 if (y < y1)
724 if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return;
725 if (!gtk_text_iter_forward_line (&text_iter)) return;
726 gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
727 } while (y < y1);
731 /* Display address */
734 gint pos;
735 guint address;
737 gtk_text_view_buffer_to_window_coords (text_view,
738 GTK_TEXT_WINDOW_LEFT,
741 NULL,
742 &pos);
744 address = dma_sparse_iter_get_address (&buf_iter);
746 if (view->priv->show_line_numbers)
748 g_snprintf (str, sizeof (str),"0x%0*lX", margin_length, (long unsigned int)address);
749 pango_layout_set_markup (layout, str, -1);
751 gtk_paint_layout (GTK_WIDGET (view)->style,
752 win,
753 GTK_WIDGET_STATE (view),
754 FALSE,
755 NULL,
756 GTK_WIDGET (view),
757 NULL,
758 text_width + 2,
759 pos,
760 layout);
763 /* Display marker */
764 if ((prev_address != address) && (view->priv->show_line_markers))
766 gint current_marker = dma_sparse_buffer_get_marks (view->priv->buffer, address);
768 if (current_marker)
770 gint x;
772 if (view->priv->show_line_numbers)
773 x = text_width + 4;
774 else
775 x = 0;
777 draw_line_markers (view, current_marker, x, pos);
778 prev_address = address;
782 if (!dma_sparse_iter_forward_lines (&buf_iter, 1)) return;
783 if (!gtk_text_iter_forward_line (&text_iter)) return;
784 gtk_text_view_get_line_yrange (text_view, &text_iter, &y, &height);
786 } while (y < y2);
788 g_object_unref (G_OBJECT (layout));
791 static void
792 dma_sparse_view_update_adjustement (DmaSparseView *view)
794 PangoLayout *layout;
795 GdkRectangle text_area;
796 int height;
798 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW (view), &text_area);
799 layout = gtk_widget_create_pango_layout (GTK_WIDGET(view), "0123456789ABCDEFGHIJKLMNOPQRSTUVWWYZ,");
800 pango_layout_get_pixel_size(layout, NULL, &height);
801 g_object_unref (G_OBJECT (layout));
803 view->priv->line_by_page = text_area.height / height;
804 view->priv->char_by_line = 8;
806 if (view->priv->vadjustment != NULL)
808 GtkAdjustment *vadj = view->priv->vadjustment;
810 vadj->step_increment = view->priv->char_by_line;
811 vadj->page_size = (view->priv->line_by_page - 1) * vadj->step_increment;
812 vadj->page_increment = vadj->page_size * 0.9;
813 gtk_adjustment_changed (vadj);
817 static void
818 dma_sparse_view_value_changed (GtkAdjustment *adj,
819 DmaSparseView *view)
821 dma_sparse_view_synchronize_iter (view, &view->priv->start);
822 dma_sparse_view_refresh (view);
825 static void
826 dma_sparse_view_set_scroll_adjustments (GtkTextView *text_view,
827 GtkAdjustment *hadj,
828 GtkAdjustment *vadj)
830 DmaSparseView *view = DMA_SPARSE_VIEW (text_view);
832 if (vadj)
833 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
835 if (view->priv->vadjustment && (view->priv->vadjustment != vadj))
837 g_signal_handlers_disconnect_by_func (view->priv->vadjustment,
838 dma_sparse_view_value_changed,
839 view);
840 g_object_unref (view->priv->vadjustment);
843 if (view->priv->vadjustment != vadj)
846 GTK_TEXT_VIEW_CLASS (parent_class)->set_scroll_adjustments (GTK_TEXT_VIEW (view), hadj, NULL);
848 if (vadj != NULL)
850 g_object_ref_sink (vadj);
852 g_signal_connect (vadj, "value_changed",
853 G_CALLBACK (dma_sparse_view_value_changed),
854 view);
856 vadj->upper = dma_sparse_buffer_get_upper (view->priv->buffer);
857 vadj->lower = dma_sparse_buffer_get_lower (view->priv->buffer);
858 vadj->value = 0;
860 view->priv->vadjustment = vadj;
861 dma_sparse_view_update_adjustement (view);
865 /* Public functions
866 *---------------------------------------------------------------------------*/
868 void
869 dma_sparse_view_set_sparse_buffer (DmaSparseView *view, DmaSparseBuffer *buffer)
871 view->priv->buffer = buffer;
872 dma_sparse_buffer_get_iterator_at_address (buffer, &view->priv->start, 0);
873 dma_sparse_view_refresh (view);
876 DmaSparseBuffer *
877 dma_sparse_view_get_sparse_buffer (DmaSparseView *view)
879 return view->priv->buffer;
882 void
883 dma_sparse_view_refresh (DmaSparseView *view)
885 gint offset;
886 GtkTextIter cur;
887 GtkTextMark *mark;
888 GtkTextIter start, end;
889 GtkTextBuffer *buffer;
891 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
892 /* Save all cursor offset */
893 mark = gtk_text_buffer_get_insert (buffer);
894 gtk_text_buffer_get_iter_at_mark (buffer, &cur, mark);
895 offset = gtk_text_iter_get_offset (&cur);
897 /* Remove old data */
898 view->priv->stamp++;
899 gtk_text_buffer_get_bounds (buffer, &start, &end);
900 gtk_text_buffer_delete (buffer, &start, &end);
901 gtk_text_buffer_get_iter_at_offset (buffer, &end, 0);
903 /* Get data */
904 dma_sparse_iter_insert_lines (&view->priv->start, &end, view->priv->line_by_page);
906 /* Restore cursor */
907 mark = gtk_text_buffer_get_insert (buffer);
908 gtk_text_buffer_get_iter_at_mark(buffer, &cur, mark);
909 gtk_text_iter_set_offset (&cur, offset);
910 gtk_text_buffer_move_mark_by_name (buffer, "insert", &cur);
911 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cur);
914 /* Markers functions
915 *---------------------------------------------------------------------------*/
917 gint
918 dma_sparse_view_mark (DmaSparseView *view, guint location, gint marker)
920 dma_sparse_buffer_add_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
921 gtk_widget_queue_draw (GTK_WIDGET (view));
923 return (gint)location;
926 void
927 dma_sparse_view_unmark (DmaSparseView *view, guint location, gint marker)
929 dma_sparse_buffer_remove_mark (view->priv->buffer, location, marker_ianjuta_to_view (marker));
930 gtk_widget_queue_draw (GTK_WIDGET (view));
933 void
934 dma_sparse_view_delete_all_markers (DmaSparseView *view, gint marker)
936 dma_sparse_buffer_remove_all_mark (view->priv->buffer, marker_ianjuta_to_view(marker));
939 void
940 dma_sparse_view_goto (DmaSparseView *view, guint location)
942 dma_sparse_iter_move_at (&view->priv->start, location);
943 gtk_adjustment_set_value (view->priv->vadjustment, (gdouble)location);
944 gtk_adjustment_value_changed (view->priv->vadjustment);
947 guint
948 dma_sparse_view_get_location (DmaSparseView *view)
950 GtkTextMark *mark;
951 GtkTextBuffer *buffer;
952 GtkTextIter iter;
953 DmaSparseIter buf_iter;
954 gint line;
956 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
957 mark = gtk_text_buffer_get_insert (buffer);
958 gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
959 line = gtk_text_iter_get_line (&iter);
961 dma_sparse_iter_copy (&buf_iter, &view->priv->start);
962 dma_sparse_iter_forward_lines (&buf_iter, line);
964 return dma_sparse_iter_get_address (&buf_iter);
967 /* GtkWidget functions
968 *---------------------------------------------------------------------------*/
970 static gint
971 dma_sparse_view_expose (GtkWidget *widget,
972 GdkEventExpose *event)
974 DmaSparseView *view;
975 GtkTextView *text_view;
976 gboolean event_handled;
978 view = DMA_SPARSE_VIEW (widget);
979 text_view = GTK_TEXT_VIEW (widget);
981 event_handled = FALSE;
983 /* now check for the left window, which contains the margin */
984 if (event->window == gtk_text_view_get_window (text_view,
985 GTK_TEXT_WINDOW_LEFT))
987 dma_sparse_view_paint_margin (view, event);
988 event_handled = TRUE;
990 else
992 event_handled = GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
995 return event_handled;
998 static void
999 dma_sparse_view_size_allocate (GtkWidget *widget,
1000 GtkAllocation *allocation)
1002 DmaSparseView *view;
1004 view = DMA_SPARSE_VIEW (widget);
1006 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
1008 dma_sparse_view_update_adjustement (view);
1009 dma_sparse_view_refresh (view);
1012 /* GtkObject functions
1013 *---------------------------------------------------------------------------*/
1015 static void
1016 dma_sparse_view_destroy (GtkObject *object)
1018 DmaSparseView *view;
1020 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1022 view = DMA_SPARSE_VIEW (object);
1024 if (view->priv->goto_window)
1026 gtk_widget_destroy (view->priv->goto_window);
1027 view->priv->goto_window = NULL;
1028 view->priv->goto_entry = NULL;
1031 GTK_OBJECT_CLASS (parent_class)->destroy (object);
1034 /* GObject functions
1035 *---------------------------------------------------------------------------*/
1037 static void
1038 dma_sparse_view_set_property (GObject *object,guint prop_id, const GValue *value, GParamSpec *pspec)
1040 DmaSparseView *view;
1042 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1044 view = DMA_SPARSE_VIEW (object);
1046 switch (prop_id)
1048 case PROP_SHOW_LINE_NUMBERS:
1049 dma_sparse_view_set_show_line_numbers (view, g_value_get_boolean (value));
1050 break;
1051 case PROP_SHOW_LINE_MARKERS:
1052 dma_sparse_view_set_show_line_markers (view, g_value_get_boolean (value));
1053 break;
1054 default:
1055 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1056 break;
1060 static void
1061 dma_sparse_view_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1063 DmaSparseView *view;
1065 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1067 view = DMA_SPARSE_VIEW (object);
1069 switch (prop_id)
1071 case PROP_SHOW_LINE_NUMBERS:
1072 g_value_set_boolean (value, dma_sparse_view_get_show_line_numbers (view));
1073 break;
1074 case PROP_SHOW_LINE_MARKERS:
1075 g_value_set_boolean (value, dma_sparse_view_get_show_line_markers (view));
1076 break;
1077 default:
1078 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1079 break;
1083 /* dispose is the first destruction step. It is used to unref object created
1084 * with instance_init in order to break reference counting cycles. This
1085 * function could be called several times. All function should still work
1086 * after this call. It has to called its parents.*/
1088 static void
1089 dma_sparse_view_dispose (GObject *object)
1091 DmaSparseView *view;
1093 g_return_if_fail (object != NULL);
1094 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1096 view = DMA_SPARSE_VIEW (object);
1098 G_OBJECT_CLASS (parent_class)->dispose (object);
1101 /* finalize is the last destruction step. It must free all memory allocated
1102 * with instance_init. It is called only one time just before releasing all
1103 * memory */
1105 static void
1106 dma_sparse_view_finalize (GObject *object)
1108 DmaSparseView *view;
1110 g_return_if_fail (object != NULL);
1111 g_return_if_fail (DMA_IS_SPARSE_VIEW (object));
1113 view = DMA_SPARSE_VIEW (object);
1115 dma_sparse_view_free_marker (view);
1117 g_free (view->priv);
1119 G_OBJECT_CLASS (parent_class)->finalize (object);
1122 /* instance_init is the constructor. All functions should work after this
1123 * call. */
1125 static void
1126 dma_sparse_view_instance_init (DmaSparseView *view)
1128 PangoFontDescription *font_desc;
1130 view->priv = g_new0 (DmaSparseViewPrivate, 1);
1132 view->priv->buffer = NULL;
1134 view->priv->goto_window = NULL;
1135 view->priv->goto_entry = NULL;
1137 view->priv->show_line_numbers = TRUE;
1138 view->priv->show_line_markers = TRUE;
1140 view->priv->stamp = 0;
1142 memset (view->priv->marker_pixbuf, 0, sizeof (view->priv->marker_pixbuf));
1144 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 2);
1145 gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 2);
1147 g_signal_connect (view, "populate_popup",
1148 G_CALLBACK (dma_sparse_view_populate_popup), view);
1150 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view),
1151 GTK_TEXT_WINDOW_LEFT,
1152 MIN_NUMBER_WINDOW_WIDTH);
1154 font_desc = pango_font_description_from_string ("Monospace 10");
1155 gtk_widget_modify_font (GTK_WIDGET (view), font_desc);
1156 pango_font_description_free (font_desc);
1158 dma_sparse_view_initialize_marker (view);
1161 /* class_init intialize the class itself not the instance */
1163 static void
1164 dma_sparse_view_class_init (DmaSparseViewClass * klass)
1166 GObjectClass *gobject_class;
1167 GtkObjectClass *object_class;
1168 GtkWidgetClass *widget_class;
1169 GtkTextViewClass *text_view_class;
1171 g_return_if_fail (klass != NULL);
1173 gobject_class = (GObjectClass *) klass;
1174 object_class = (GtkObjectClass *) klass;
1175 widget_class = GTK_WIDGET_CLASS (klass);
1176 text_view_class = GTK_TEXT_VIEW_CLASS (klass);
1177 parent_class = (GtkTextViewClass*) g_type_class_peek_parent (klass);
1179 gobject_class->dispose = dma_sparse_view_dispose;
1180 gobject_class->finalize = dma_sparse_view_finalize;
1181 gobject_class->get_property = dma_sparse_view_get_property;
1182 gobject_class->set_property = dma_sparse_view_set_property;
1184 object_class->destroy = dma_sparse_view_destroy;
1186 widget_class->size_allocate = dma_sparse_view_size_allocate;
1187 widget_class->expose_event = dma_sparse_view_expose;
1189 text_view_class->move_cursor = dma_sparse_view_move_cursor;
1190 text_view_class->set_scroll_adjustments = dma_sparse_view_set_scroll_adjustments;
1192 g_object_class_install_property (gobject_class,
1193 PROP_SHOW_LINE_NUMBERS,
1194 g_param_spec_boolean ("show_line_numbers",
1195 _("Show Line Numbers"),
1196 _("Whether to display line numbers"),
1197 FALSE,
1198 G_PARAM_READWRITE));
1200 g_object_class_install_property (gobject_class,
1201 PROP_SHOW_LINE_MARKERS,
1202 g_param_spec_boolean ("show_line_markers",
1203 _("Show Line Markers"),
1204 _("Whether to display line marker pixbufs"),
1205 FALSE,
1206 G_PARAM_READWRITE));
1209 GType
1210 dma_sparse_view_get_type (void)
1212 static GType type = 0;
1214 if (!type)
1216 static const GTypeInfo type_info =
1218 sizeof (DmaSparseViewClass),
1219 (GBaseInitFunc) NULL,
1220 (GBaseFinalizeFunc) NULL,
1221 (GClassInitFunc) dma_sparse_view_class_init,
1222 (GClassFinalizeFunc) NULL,
1223 NULL, /* class_data */
1224 sizeof (DmaSparseView),
1225 0, /* n_preallocs */
1226 (GInstanceInitFunc) dma_sparse_view_instance_init,
1227 NULL /* value_table */
1230 type = g_type_register_static (GTK_TYPE_TEXT_VIEW,
1231 "DmaSparseView", &type_info, 0);
1234 return type;
1237 /* Creation and Destruction
1238 *---------------------------------------------------------------------------*/
1240 GtkWidget*
1241 dma_sparse_view_new_with_buffer (DmaSparseBuffer *buffer)
1243 GtkWidget *view;
1245 view = g_object_new (DMA_SPARSE_VIEW_TYPE, NULL);
1246 g_assert (view != NULL);
1248 DMA_SPARSE_VIEW(view)->priv->buffer = buffer;
1249 dma_sparse_buffer_get_iterator_at_address (buffer, &(DMA_SPARSE_VIEW (view))->priv->start, 0);
1251 return view;
1254 void
1255 dma_sparse_view_free (DmaSparseView *view)
1257 g_object_unref (view);