1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
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>
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 "bookmark.png"
60 #define MARKER_PIXMAP_LINEMARKER "linemarker.png"
61 #define MARKER_PIXMAP_PROGRAM_COUNTER "program-counter.png"
62 #define MARKER_PIXMAP_BREAKPOINT_DISABLED "breakpoint-disabled.png"
63 #define MARKER_PIXMAP_BREAKPOINT_ENABLED "breakpoint-enabled.png"
66 *---------------------------------------------------------------------------*/
70 PROP_SHOW_LINE_NUMBERS
,
71 PROP_SHOW_LINE_MARKERS
,
74 struct _DmaSparseViewPrivate
78 gboolean show_line_numbers
;
79 gboolean show_line_markers
;
81 DmaSparseBuffer
* buffer
;
83 GtkAdjustment
*vadjustment
;
85 GtkWidget
*goto_window
;
86 GtkWidget
*goto_entry
;
93 GdkPixbuf
*marker_pixbuf
[MAX_MARKER
];
96 /* Used in dispose and finalize */
97 static GtkTextViewClass
*parent_class
= NULL
;
100 *---------------------------------------------------------------------------*/
102 /* Cut and paste from gtkwindow.c */
104 send_focus_change (GtkWidget
*widget
,
107 GdkEvent
*fevent
= gdk_event_new (GDK_FOCUS_CHANGE
);
109 g_object_ref (widget
);
112 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
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 *---------------------------------------------------------------------------*/
132 dma_sparse_view_goto_window_hide (DmaSparseView
*view
)
134 gtk_widget_hide (view
->priv
->goto_window
);
138 dma_sparse_view_goto_delete_event (GtkWidget
*widget
,
142 g_return_val_if_fail (GTK_IS_WIDGET (widget
), FALSE
);
144 dma_sparse_view_goto_window_hide (view
);
150 dma_sparse_view_goto_key_press_event (GtkWidget
*widget
,
154 g_return_val_if_fail (GTK_IS_WIDGET (widget
), FALSE
);
155 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view
), FALSE
);
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
);
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
)
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
);
193 dma_sparse_view_goto_position_func (DmaSparseView
*view
)
197 GdkWindow
*window
= GTK_WIDGET (view
)->window
;
198 GdkScreen
*screen
= gdk_drawable_get_screen (window
);
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
);
215 dma_sparse_view_goto_activate (GtkWidget
*menu_item
,
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
));
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
),
247 g_signal_connect (view
->priv
->goto_window
, "key_press_event",
248 G_CALLBACK (dma_sparse_view_goto_key_press_event
),
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);
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
,
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.
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.
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
);
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
);
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");
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.
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.
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
);
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
);
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");
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 *---------------------------------------------------------------------------*/
423 marker_ianjuta_to_view (IAnjutaMarkableMarker marker
)
428 case IANJUTA_MARKABLE_LINEMARKER
:
429 mark
= SPARSE_VIEW_LINEMARKER
;
431 case IANJUTA_MARKABLE_BOOKMARK
:
432 mark
= SPARSE_VIEW_BOOKMARK
;
434 case IANJUTA_MARKABLE_BREAKPOINT_DISABLED
:
435 mark
= SPARSE_VIEW_BREAKPOINT_DISABLED
;
437 case IANJUTA_MARKABLE_BREAKPOINT_ENABLED
:
438 mark
= SPARSE_VIEW_BREAKPOINT_ENABLED
;
440 case IANJUTA_MARKABLE_PROGRAM_COUNTER
:
441 mark
= SPARSE_VIEW_PROGRAM_COUNTER
;
444 mark
= SPARSE_VIEW_LINEMARKER
;
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
);
461 dma_sparse_view_free_marker (DmaSparseView
*view
)
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
;
476 *---------------------------------------------------------------------------*/
479 dma_sparse_view_populate_popup (DmaSparseView
*view
,
481 DmaSparseView
*user_data
)
483 GtkWidget
*menu_item
;
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
);
500 dma_sparse_view_move_cursor (GtkTextView
*text_view
,
501 GtkMovementStep step
,
503 gboolean extend_selection
)
505 DmaSparseView
*view
= DMA_SPARSE_VIEW (text_view
);
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
:
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
));
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
));
526 case GTK_MOVEMENT_BUFFER_ENDS
:
532 GTK_TEXT_VIEW_CLASS (parent_class
)->move_cursor (text_view
,
538 dma_sparse_view_synchronize_iter (DmaSparseView
*view
, DmaSparseIter
*iter
)
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
);
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
);
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
));
566 draw_line_markers (DmaSparseView
*view
,
571 GdkPixbuf
*composite
;
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
];
589 composite
= gdk_pixbuf_copy (pixbuf
);
590 width
= gdk_pixbuf_get_width (composite
);
591 height
= gdk_pixbuf_get_height (composite
);
598 pixbuf_w
= gdk_pixbuf_get_width (pixbuf
);
599 pixbuf_h
= gdk_pixbuf_get_height (pixbuf
);
600 gdk_pixbuf_composite (pixbuf
,
605 (double) pixbuf_w
/ width
,
606 (double) pixbuf_h
/ height
,
610 //g_object_unref (pixbuf);
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 */
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
,
632 GDK_RGB_DITHER_NORMAL
, 0, 0);
633 g_object_unref (composite
);
638 dma_sparse_view_paint_margin (DmaSparseView
*view
,
639 GdkEventExpose
*event
)
641 GtkTextView
*text_view
;
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
,
666 win
= gtk_text_view_get_window (text_view
,
667 GTK_TEXT_WINDOW_LEFT
);
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
,
680 gtk_text_view_window_to_buffer_coords (text_view
,
681 GTK_TEXT_WINDOW_LEFT
,
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;
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
,
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
);
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
);
731 /* Display address */
737 gtk_text_view_buffer_to_window_coords (text_view
,
738 GTK_TEXT_WINDOW_LEFT
,
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
,
753 GTK_WIDGET_STATE (view
),
764 if ((prev_address
!= address
) && (view
->priv
->show_line_markers
))
766 gint current_marker
= dma_sparse_buffer_get_marks (view
->priv
->buffer
, address
);
772 if (view
->priv
->show_line_numbers
)
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
);
788 g_object_unref (G_OBJECT (layout
));
792 dma_sparse_view_update_adjustement (DmaSparseView
*view
)
795 GdkRectangle text_area
;
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
);
818 dma_sparse_view_value_changed (GtkAdjustment
*adj
,
821 dma_sparse_view_synchronize_iter (view
, &view
->priv
->start
);
822 dma_sparse_view_refresh (view
);
826 dma_sparse_view_set_scroll_adjustments (GtkTextView
*text_view
,
830 DmaSparseView
*view
= DMA_SPARSE_VIEW (text_view
);
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
,
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
);
850 g_object_ref_sink (vadj
);
852 g_signal_connect (vadj
, "value_changed",
853 G_CALLBACK (dma_sparse_view_value_changed
),
856 vadj
->upper
= dma_sparse_buffer_get_upper (view
->priv
->buffer
);
857 vadj
->lower
= dma_sparse_buffer_get_lower (view
->priv
->buffer
);
860 view
->priv
->vadjustment
= vadj
;
861 dma_sparse_view_update_adjustement (view
);
866 *---------------------------------------------------------------------------*/
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
);
877 dma_sparse_view_get_sparse_buffer (DmaSparseView
*view
)
879 return view
->priv
->buffer
;
883 dma_sparse_view_refresh (DmaSparseView
*view
)
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 */
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);
904 dma_sparse_iter_insert_lines (&view
->priv
->start
, &end
, view
->priv
->line_by_page
);
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
);
915 *---------------------------------------------------------------------------*/
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
;
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
));
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
));
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 /* GtkWidget functions
948 *---------------------------------------------------------------------------*/
951 dma_sparse_view_expose (GtkWidget
*widget
,
952 GdkEventExpose
*event
)
955 GtkTextView
*text_view
;
956 gboolean event_handled
;
958 view
= DMA_SPARSE_VIEW (widget
);
959 text_view
= GTK_TEXT_VIEW (widget
);
961 event_handled
= FALSE
;
963 /* now check for the left window, which contains the margin */
964 if (event
->window
== gtk_text_view_get_window (text_view
,
965 GTK_TEXT_WINDOW_LEFT
))
967 dma_sparse_view_paint_margin (view
, event
);
968 event_handled
= TRUE
;
972 event_handled
= GTK_WIDGET_CLASS (parent_class
)->expose_event (widget
, event
);
975 return event_handled
;
979 dma_sparse_view_size_allocate (GtkWidget
*widget
,
980 GtkAllocation
*allocation
)
984 view
= DMA_SPARSE_VIEW (widget
);
986 GTK_WIDGET_CLASS (parent_class
)->size_allocate (widget
, allocation
);
988 dma_sparse_view_update_adjustement (view
);
989 dma_sparse_view_refresh (view
);
992 /* GtkObject functions
993 *---------------------------------------------------------------------------*/
996 dma_sparse_view_destroy (GtkObject
*object
)
1000 g_return_if_fail (DMA_IS_SPARSE_VIEW (object
));
1002 view
= DMA_SPARSE_VIEW (object
);
1004 if (view
->priv
->goto_window
)
1006 gtk_widget_destroy (view
->priv
->goto_window
);
1007 view
->priv
->goto_window
= NULL
;
1008 view
->priv
->goto_entry
= NULL
;
1011 GTK_OBJECT_CLASS (parent_class
)->destroy (object
);
1014 /* GObject functions
1015 *---------------------------------------------------------------------------*/
1018 dma_sparse_view_set_property (GObject
*object
,guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
1020 DmaSparseView
*view
;
1022 g_return_if_fail (DMA_IS_SPARSE_VIEW (object
));
1024 view
= DMA_SPARSE_VIEW (object
);
1028 case PROP_SHOW_LINE_NUMBERS
:
1029 dma_sparse_view_set_show_line_numbers (view
, g_value_get_boolean (value
));
1031 case PROP_SHOW_LINE_MARKERS
:
1032 dma_sparse_view_set_show_line_markers (view
, g_value_get_boolean (value
));
1035 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1041 dma_sparse_view_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
1043 DmaSparseView
*view
;
1045 g_return_if_fail (DMA_IS_SPARSE_VIEW (object
));
1047 view
= DMA_SPARSE_VIEW (object
);
1051 case PROP_SHOW_LINE_NUMBERS
:
1052 g_value_set_boolean (value
, dma_sparse_view_get_show_line_numbers (view
));
1054 case PROP_SHOW_LINE_MARKERS
:
1055 g_value_set_boolean (value
, dma_sparse_view_get_show_line_markers (view
));
1058 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
1063 /* dispose is the first destruction step. It is used to unref object created
1064 * with instance_init in order to break reference counting cycles. This
1065 * function could be called several times. All function should still work
1066 * after this call. It has to called its parents.*/
1069 dma_sparse_view_dispose (GObject
*object
)
1071 DmaSparseView
*view
;
1073 g_return_if_fail (object
!= NULL
);
1074 g_return_if_fail (DMA_IS_SPARSE_VIEW (object
));
1076 view
= DMA_SPARSE_VIEW (object
);
1078 G_OBJECT_CLASS (parent_class
)->dispose (object
);
1081 /* finalize is the last destruction step. It must free all memory allocated
1082 * with instance_init. It is called only one time just before releasing all
1086 dma_sparse_view_finalize (GObject
*object
)
1088 DmaSparseView
*view
;
1090 g_return_if_fail (object
!= NULL
);
1091 g_return_if_fail (DMA_IS_SPARSE_VIEW (object
));
1093 view
= DMA_SPARSE_VIEW (object
);
1095 dma_sparse_view_free_marker (view
);
1097 g_free (view
->priv
);
1099 G_OBJECT_CLASS (parent_class
)->finalize (object
);
1102 /* instance_init is the constructor. All functions should work after this
1106 dma_sparse_view_instance_init (DmaSparseView
*view
)
1108 PangoFontDescription
*font_desc
;
1110 view
->priv
= g_new0 (DmaSparseViewPrivate
, 1);
1112 view
->priv
->buffer
= NULL
;
1114 view
->priv
->goto_window
= NULL
;
1115 view
->priv
->goto_entry
= NULL
;
1117 view
->priv
->show_line_numbers
= TRUE
;
1118 view
->priv
->show_line_markers
= TRUE
;
1120 view
->priv
->stamp
= 0;
1122 memset (view
->priv
->marker_pixbuf
, 0, sizeof (view
->priv
->marker_pixbuf
));
1124 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view
), 2);
1125 gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view
), 2);
1127 g_signal_connect (view
, "populate_popup",
1128 G_CALLBACK (dma_sparse_view_populate_popup
), view
);
1130 gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (view
),
1131 GTK_TEXT_WINDOW_LEFT
,
1132 MIN_NUMBER_WINDOW_WIDTH
);
1134 font_desc
= pango_font_description_from_string ("Monospace 10");
1135 gtk_widget_modify_font (GTK_WIDGET (view
), font_desc
);
1136 pango_font_description_free (font_desc
);
1138 dma_sparse_view_initialize_marker (view
);
1141 /* class_init intialize the class itself not the instance */
1144 dma_sparse_view_class_init (DmaSparseViewClass
* klass
)
1146 GObjectClass
*gobject_class
;
1147 GtkObjectClass
*object_class
;
1148 GtkWidgetClass
*widget_class
;
1149 GtkTextViewClass
*text_view_class
;
1151 g_return_if_fail (klass
!= NULL
);
1153 gobject_class
= (GObjectClass
*) klass
;
1154 object_class
= (GtkObjectClass
*) klass
;
1155 widget_class
= GTK_WIDGET_CLASS (klass
);
1156 text_view_class
= GTK_TEXT_VIEW_CLASS (klass
);
1157 parent_class
= (GtkTextViewClass
*) g_type_class_peek_parent (klass
);
1159 gobject_class
->dispose
= dma_sparse_view_dispose
;
1160 gobject_class
->finalize
= dma_sparse_view_finalize
;
1161 gobject_class
->get_property
= dma_sparse_view_get_property
;
1162 gobject_class
->set_property
= dma_sparse_view_set_property
;
1164 object_class
->destroy
= dma_sparse_view_destroy
;
1166 widget_class
->size_allocate
= dma_sparse_view_size_allocate
;
1167 widget_class
->expose_event
= dma_sparse_view_expose
;
1169 text_view_class
->move_cursor
= dma_sparse_view_move_cursor
;
1170 text_view_class
->set_scroll_adjustments
= dma_sparse_view_set_scroll_adjustments
;
1172 g_object_class_install_property (gobject_class
,
1173 PROP_SHOW_LINE_NUMBERS
,
1174 g_param_spec_boolean ("show_line_numbers",
1175 _("Show Line Numbers"),
1176 _("Whether to display line numbers"),
1178 G_PARAM_READWRITE
));
1180 g_object_class_install_property (gobject_class
,
1181 PROP_SHOW_LINE_MARKERS
,
1182 g_param_spec_boolean ("show_line_markers",
1183 _("Show Line Markers"),
1184 _("Whether to display line marker pixbufs"),
1186 G_PARAM_READWRITE
));
1190 dma_sparse_view_get_type (void)
1192 static GType type
= 0;
1196 static const GTypeInfo type_info
=
1198 sizeof (DmaSparseViewClass
),
1199 (GBaseInitFunc
) NULL
,
1200 (GBaseFinalizeFunc
) NULL
,
1201 (GClassInitFunc
) dma_sparse_view_class_init
,
1202 (GClassFinalizeFunc
) NULL
,
1203 NULL
, /* class_data */
1204 sizeof (DmaSparseView
),
1205 0, /* n_preallocs */
1206 (GInstanceInitFunc
) dma_sparse_view_instance_init
,
1207 NULL
/* value_table */
1210 type
= g_type_register_static (GTK_TYPE_TEXT_VIEW
,
1211 "DmaSparseView", &type_info
, 0);
1217 /* Creation and Destruction
1218 *---------------------------------------------------------------------------*/
1221 dma_sparse_view_new_with_buffer (DmaSparseBuffer
*buffer
)
1225 view
= g_object_new (DMA_SPARSE_VIEW_TYPE
, NULL
);
1226 g_assert (view
!= NULL
);
1228 DMA_SPARSE_VIEW(view
)->priv
->buffer
= buffer
;
1229 dma_sparse_buffer_get_iterator_at_address (buffer
, &(DMA_SPARSE_VIEW (view
))->priv
->start
, 0);
1235 dma_sparse_view_free (DmaSparseView
*view
)
1237 g_object_unref (view
);