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., 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"
30 #include <libanjuta/anjuta-debug.h>
31 #include <libanjuta/interfaces/ianjuta-markable.h>
33 #include <glib/gi18n.h>
35 #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 "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"
66 *---------------------------------------------------------------------------*/
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
;
82 GtkAdjustment
*vadjustment
;
83 GtkAdjustment
*dummy_vadjustment
;
85 GtkWidget
*goto_window
;
86 GtkWidget
*goto_entry
;
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
)
102 *---------------------------------------------------------------------------*/
104 /* Cut and paste from gtkwindow.c */
106 send_focus_change (GtkWidget
*widget
,
109 GdkEvent
*fevent
= gdk_event_new (GDK_FOCUS_CHANGE
);
111 #if !GTK_CHECK_VERSION (2,21,0)
112 g_object_ref (widget
);
115 GTK_WIDGET_SET_FLAGS (widget
, GTK_HAS_FOCUS
);
117 GTK_WIDGET_UNSET_FLAGS (widget
, GTK_HAS_FOCUS
);
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
);
130 gtk_widget_send_focus_change (widget
, fevent
);
133 gdk_event_free (fevent
);
136 /* Goto address window
137 *---------------------------------------------------------------------------*/
140 dma_sparse_view_goto_window_hide (DmaSparseView
*view
)
142 gtk_widget_hide (view
->priv
->goto_window
);
146 dma_sparse_view_goto_delete_event (GtkWidget
*widget
,
150 g_return_val_if_fail (GTK_IS_WIDGET (widget
), FALSE
);
152 dma_sparse_view_goto_window_hide (view
);
158 dma_sparse_view_goto_key_press_event (GtkWidget
*widget
,
162 g_return_val_if_fail (GTK_IS_WIDGET (widget
), FALSE
);
163 g_return_val_if_fail (DMA_IS_SPARSE_VIEW (view
), FALSE
);
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
);
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
)
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
);
201 dma_sparse_view_goto_position_func (DmaSparseView
*view
)
205 GdkWindow
*window
= gtk_widget_get_window (GTK_WIDGET (view
));
206 GdkScreen
*screen
= gdk_window_get_screen (window
);
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
);
223 dma_sparse_view_goto_activate (GtkWidget
*menu_item
,
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
));
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
));
248 view
->priv
->goto_window
= gtk_window_new (GTK_WINDOW_POPUP
);
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
),
258 g_signal_connect (view
->priv
->goto_window
, "key_press_event",
259 G_CALLBACK (dma_sparse_view_goto_key_press_event
),
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);
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
,
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.
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.
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
);
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
);
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");
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.
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.
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
);
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
);
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");
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 *---------------------------------------------------------------------------*/
433 marker_ianjuta_to_view (IAnjutaMarkableMarker marker
)
438 case IANJUTA_MARKABLE_LINEMARKER
:
439 mark
= SPARSE_VIEW_LINEMARKER
;
441 case IANJUTA_MARKABLE_BOOKMARK
:
442 mark
= SPARSE_VIEW_BOOKMARK
;
444 case IANJUTA_MARKABLE_BREAKPOINT_DISABLED
:
445 mark
= SPARSE_VIEW_BREAKPOINT_DISABLED
;
447 case IANJUTA_MARKABLE_BREAKPOINT_ENABLED
:
448 mark
= SPARSE_VIEW_BREAKPOINT_ENABLED
;
450 case IANJUTA_MARKABLE_PROGRAM_COUNTER
:
451 mark
= SPARSE_VIEW_PROGRAM_COUNTER
;
454 mark
= SPARSE_VIEW_LINEMARKER
;
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
);
471 dma_sparse_view_free_marker (DmaSparseView
*view
)
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
;
486 *---------------------------------------------------------------------------*/
489 dma_sparse_view_populate_popup (DmaSparseView
*view
,
491 DmaSparseView
*user_data
)
493 GtkWidget
*menu_item
;
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
);
510 dma_sparse_view_move_cursor (GtkTextView
*text_view
,
511 GtkMovementStep step
,
513 gboolean extend_selection
)
515 DmaSparseView
*view
= DMA_SPARSE_VIEW (text_view
);
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
:
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
));
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
));
536 case GTK_MOVEMENT_BUFFER_ENDS
:
542 GTK_TEXT_VIEW_CLASS (dma_sparse_view_parent_class
)->move_cursor (text_view
,
548 dma_sparse_view_synchronize_iter (DmaSparseView
*view
, DmaSparseIter
*iter
)
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
);
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
);
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
));
577 draw_line_markers (DmaSparseView
*view
,
582 GdkPixbuf
*composite
;
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
];
600 composite
= gdk_pixbuf_copy (pixbuf
);
601 width
= gdk_pixbuf_get_width (composite
);
602 height
= gdk_pixbuf_get_height (composite
);
609 pixbuf_w
= gdk_pixbuf_get_width (pixbuf
);
610 pixbuf_h
= gdk_pixbuf_get_height (pixbuf
);
611 gdk_pixbuf_composite (pixbuf
,
616 (double) pixbuf_w
/ width
,
617 (double) pixbuf_h
/ height
,
621 //g_object_unref (pixbuf);
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 */
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
);
646 g_object_unref (composite
);
652 dma_sparse_view_paint_margin (DmaSparseView
*view
,
655 GtkTextView
*text_view
;
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
,
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
,
692 gtk_text_view_window_to_buffer_coords (text_view
,
693 GTK_TEXT_WINDOW_LEFT
,
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;
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
,
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
);
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
);
743 /* Display address */
749 gtk_text_view_buffer_to_window_coords (text_view
,
750 GTK_TEXT_WINDOW_LEFT
,
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
);
768 if ((prev_address
!= address
) && (view
->priv
->show_line_markers
))
770 gint current_marker
= dma_sparse_buffer_get_marks (view
->priv
->buffer
, address
);
776 if (view
->priv
->show_line_numbers
)
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
);
792 g_object_unref (G_OBJECT (layout
));
796 dma_sparse_view_update_adjustement (DmaSparseView
*view
)
799 GdkRectangle text_area
;
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
);
826 dma_sparse_view_value_changed (GtkAdjustment
*adj
,
829 dma_sparse_view_synchronize_iter (view
, &view
->priv
->start
);
830 dma_sparse_view_refresh (view
);
835 dma_sparse_view_notify_vadjustment (DmaSparseView
*view
,
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
,
853 g_object_unref (view
->priv
->vadjustment
);
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
),
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
);
886 *---------------------------------------------------------------------------*/
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
);
909 dma_sparse_view_get_sparse_buffer (DmaSparseView
*view
)
911 return view
->priv
->buffer
;
915 dma_sparse_view_refresh (DmaSparseView
*view
)
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 */
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);
936 dma_sparse_iter_insert_lines (&view
->priv
->start
, &end
, view
->priv
->line_by_page
);
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
);
947 *---------------------------------------------------------------------------*/
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
;
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
));
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
));
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
);
980 dma_sparse_view_get_location (DmaSparseView
*view
)
983 GtkTextBuffer
*buffer
;
985 DmaSparseIter buf_iter
;
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 *---------------------------------------------------------------------------*/
1003 dma_sparse_view_draw (GtkWidget
*widget
,
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
;
1024 event_handled
= GTK_WIDGET_CLASS (dma_sparse_view_parent_class
)->draw (widget
, cr
);
1027 return event_handled
;
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 *---------------------------------------------------------------------------*/
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 *---------------------------------------------------------------------------*/
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
);
1087 dma_sparse_view_set_sparse_buffer (view
, g_value_get_object (value
));
1089 case PROP_SHOW_LINE_NUMBERS
:
1090 dma_sparse_view_set_show_line_numbers (view
, g_value_get_boolean (value
));
1092 case PROP_SHOW_LINE_MARKERS
:
1093 dma_sparse_view_set_show_line_markers (view
, g_value_get_boolean (value
));
1096 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
);
1113 g_value_set_object (value
, view
->priv
->buffer
);
1115 case PROP_SHOW_LINE_NUMBERS
:
1116 g_value_set_boolean (value
, dma_sparse_view_get_show_line_numbers (view
));
1118 case PROP_SHOW_LINE_MARKERS
:
1119 g_value_set_boolean (value
, dma_sparse_view_get_show_line_markers (view
));
1122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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.*/
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
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
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 */
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
,
1235 g_param_spec_object ("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"),
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"),
1255 G_PARAM_READWRITE
));
1258 /* Creation and Destruction
1259 *---------------------------------------------------------------------------*/
1262 dma_sparse_view_new_with_buffer (DmaSparseBuffer
*buffer
)
1266 view
= g_object_new (DMA_SPARSE_VIEW_TYPE
, "buffer", buffer
, NULL
);
1267 g_assert (view
!= NULL
);