4 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
5 * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
6 * Copyright (C) 2003-2005 Paolo Maggi
7 * Copyright (C) 2006 Johannes Schmid
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
26 * Modified by the anjuta Team, 1998-2005. See the AUTHORS file for a
27 * list of people on the anjuta Team.
28 * See the ChangeLog files for a list of changes.
40 #include <gdk/gdkkeysyms.h>
42 #include <glib/gi18n.h>
45 #include <libanjuta/anjuta-debug.h>
46 #include <libanjuta/anjuta-encodings.h>
48 #include "anjuta-view.h"
49 #include "sourceview.h"
50 #include "sourceview-private.h"
51 #include "anjuta-marshal.h"
53 #define ANJUTA_VIEW_SCROLL_MARGIN 0.02
55 #define ANJUTA_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_VIEW, AnjutaViewPrivate))
62 struct _AnjutaViewPrivate
69 static void anjuta_view_destroy (GtkObject
*object
);
70 static void anjuta_view_finalize (GObject
*object
);
71 static void anjuta_view_move_cursor (GtkTextView
*text_view
,
74 gboolean extend_selection
);
75 static gint
anjuta_view_focus_out (GtkWidget
*widget
,
76 GdkEventFocus
*event
);
78 static gint
anjuta_view_expose (GtkWidget
*widget
,
79 GdkEventExpose
*event
);
81 static gboolean
anjuta_view_key_press_event (GtkWidget
*widget
,
83 static gboolean
anjuta_view_button_press_event (GtkWidget
*widget
,
84 GdkEventButton
*event
);
86 G_DEFINE_TYPE(AnjutaView
, anjuta_view
, GTK_TYPE_SOURCE_VIEW
)
89 scroll_to_cursor_real (AnjutaView
*view
)
91 GtkTextBuffer
* buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
92 g_return_val_if_fail (buffer
!= NULL
, FALSE
);
94 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view
),
95 gtk_text_buffer_get_insert (buffer
),
101 view
->priv
->scroll_idle
= 0;
106 anjuta_view_set_property (GObject
* object
,
108 const GValue
* value
, GParamSpec
* pspec
)
110 AnjutaView
*self
= ANJUTA_VIEW (object
);
111 g_return_if_fail(value
!= NULL
);
112 g_return_if_fail(pspec
!= NULL
);
116 case ANJUTA_VIEW_POPUP
:
119 self
->priv
->popup
= g_value_get_object (value
);
120 widget
= gtk_menu_get_attach_widget(GTK_MENU(self
->priv
->popup
));
121 /* This is a very ugly hack, maybe somebody more familiar with gtk menus
124 gtk_menu_detach(GTK_MENU(self
->priv
->popup
));
125 gtk_menu_attach_to_widget(GTK_MENU(self
->priv
->popup
), GTK_WIDGET(self
), NULL
);
130 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
137 anjuta_view_get_property (GObject
* object
,
139 GValue
* value
, GParamSpec
* pspec
)
141 AnjutaView
*self
= ANJUTA_VIEW (object
);
143 g_return_if_fail(value
!= NULL
);
144 g_return_if_fail(pspec
!= NULL
);
148 case ANJUTA_VIEW_POPUP
:
150 g_value_set_object (value
, self
->priv
->popup
);
155 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
162 anjuta_view_class_init (AnjutaViewClass
*klass
)
164 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
165 GtkObjectClass
*gtkobject_class
= GTK_OBJECT_CLASS (klass
);
166 GtkTextViewClass
*textview_class
= GTK_TEXT_VIEW_CLASS (klass
);
167 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (klass
);
168 GtkBindingSet
*binding_set
;
169 GParamSpec
*anjuta_view_spec_popup
;
171 gtkobject_class
->destroy
= anjuta_view_destroy
;
172 object_class
->finalize
= anjuta_view_finalize
;
173 object_class
->set_property
= anjuta_view_set_property
;
174 object_class
->get_property
= anjuta_view_get_property
;
176 widget_class
->focus_out_event
= anjuta_view_focus_out
;
177 widget_class
->expose_event
= anjuta_view_expose
;
178 widget_class
->key_press_event
= anjuta_view_key_press_event
;
179 widget_class
->button_press_event
= anjuta_view_button_press_event
;
181 textview_class
->move_cursor
= anjuta_view_move_cursor
;
183 g_type_class_add_private (klass
, sizeof (AnjutaViewPrivate
));
185 anjuta_view_spec_popup
= g_param_spec_object ("popup",
187 "The popup-menu to show",
190 g_object_class_install_property (object_class
,
192 anjuta_view_spec_popup
);
194 binding_set
= gtk_binding_set_by_class (klass
);
198 move_cursor (GtkTextView
*text_view
,
199 const GtkTextIter
*new_location
,
200 gboolean extend_selection
)
202 GtkTextBuffer
*buffer
= text_view
->buffer
;
204 if (extend_selection
)
205 gtk_text_buffer_move_mark_by_name (buffer
,
209 gtk_text_buffer_place_cursor (buffer
, new_location
);
211 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (text_view
),
212 gtk_text_buffer_get_insert (buffer
),
213 ANJUTA_VIEW_SCROLL_MARGIN
,
220 anjuta_view_move_cursor (GtkTextView
*text_view
,
221 GtkMovementStep step
,
223 gboolean extend_selection
)
225 GtkTextBuffer
*buffer
= text_view
->buffer
;
227 GtkTextIter cur
, iter
;
229 /* really make sure gtksourceview's home/end is disabled */
230 g_return_if_fail (!gtk_source_view_get_smart_home_end (
231 GTK_SOURCE_VIEW (text_view
)));
233 mark
= gtk_text_buffer_get_insert (buffer
);
234 gtk_text_buffer_get_iter_at_mark (buffer
, &cur
, mark
);
237 if (step
== GTK_MOVEMENT_DISPLAY_LINE_ENDS
&&
238 (count
== -1) && gtk_text_iter_starts_line (&iter
))
240 /* Find the iter of the first character on the line. */
241 while (!gtk_text_iter_ends_line (&cur
))
245 c
= gtk_text_iter_get_char (&cur
);
246 if (g_unichar_isspace (c
))
247 gtk_text_iter_forward_char (&cur
);
252 /* if we are clearing selection, we need to move_cursor even
253 * if we are at proper iter because selection_bound may need
255 if (!gtk_text_iter_equal (&cur
, &iter
) || !extend_selection
)
256 move_cursor (text_view
, &cur
, extend_selection
);
258 else if (step
== GTK_MOVEMENT_DISPLAY_LINE_ENDS
&&
259 (count
== 1) && gtk_text_iter_ends_line (&iter
))
261 /* Find the iter of the last character on the line. */
262 while (!gtk_text_iter_starts_line (&cur
))
266 gtk_text_iter_backward_char (&cur
);
267 c
= gtk_text_iter_get_char (&cur
);
268 if (!g_unichar_isspace (c
))
270 /* We've gone one character too far. */
271 gtk_text_iter_forward_char (&cur
);
276 /* if we are clearing selection, we need to move_cursor even
277 * if we are at proper iter because selection_bound may need
279 if (!gtk_text_iter_equal (&cur
, &iter
) || !extend_selection
)
280 move_cursor (text_view
, &cur
, extend_selection
);
284 /* note that we chain up to GtkTextView skipping GtkSourceView */
285 (* GTK_TEXT_VIEW_CLASS (anjuta_view_parent_class
)->move_cursor
) (text_view
,
293 anjuta_view_init (AnjutaView
*view
)
295 view
->priv
= ANJUTA_VIEW_GET_PRIVATE (view
);
298 * Set tab, fonts, wrap mode, colors, etc. according
302 g_object_set (G_OBJECT (view
),
304 "show-line-numbers", TRUE
,
307 "insert-spaces-instead-of-tabs", FALSE
,
308 "highlight-current-line", TRUE
,
309 "indent-on-tab", TRUE
, /* Fix #388727 */
310 "smart-home-end", FALSE
, /* Never changes this */
315 anjuta_view_destroy (GtkObject
*object
)
319 view
= ANJUTA_VIEW (object
);
321 (* GTK_OBJECT_CLASS (anjuta_view_parent_class
)->destroy
) (object
);
325 anjuta_view_finalize (GObject
*object
)
329 view
= ANJUTA_VIEW (object
);
331 if (view
->priv
->popup
!= NULL
)
333 GtkWidget
* widget
= gtk_menu_get_attach_widget (GTK_MENU (view
->priv
->popup
));
335 gtk_menu_detach (GTK_MENU (view
->priv
->popup
));
338 (* G_OBJECT_CLASS (anjuta_view_parent_class
)->finalize
) (object
);
342 anjuta_view_focus_out (GtkWidget
*widget
, GdkEventFocus
*event
)
344 AnjutaView
*view
= ANJUTA_VIEW (widget
);
345 AssistWindow
* assist_win
= view
->priv
->sv
->priv
->assist_win
;
346 AssistTip
* assist_tip
= view
->priv
->sv
->priv
->assist_tip
;
349 gtk_widget_destroy(GTK_WIDGET(assist_win
));
352 gtk_widget_destroy(GTK_WIDGET(assist_tip
));
354 gtk_widget_queue_draw (widget
);
357 (* GTK_WIDGET_CLASS (anjuta_view_parent_class
)->focus_out_event
) (widget
, event
);
367 * Creates a new #AnjutaView object displaying the @sv->priv->doc document.
368 * @doc cannot be NULL.
370 * Return value: a new #AnjutaView
373 anjuta_view_new (Sourceview
*sv
)
377 view
= GTK_WIDGET (g_object_new (ANJUTA_TYPE_VIEW
, NULL
));
379 gtk_text_view_set_buffer (GTK_TEXT_VIEW (view
),
380 GTK_TEXT_BUFFER (sv
->priv
->document
));
382 gtk_widget_show_all (view
);
384 ANJUTA_VIEW(view
)->priv
->sv
= sv
;
390 anjuta_view_cut_clipboard (AnjutaView
*view
)
392 GtkTextBuffer
*buffer
;
393 GtkClipboard
*clipboard
;
395 g_return_if_fail (ANJUTA_IS_VIEW (view
));
397 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
398 g_return_if_fail (buffer
!= NULL
);
400 if (!gtk_text_view_get_editable (GTK_TEXT_VIEW(view
)))
403 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (view
),
404 GDK_SELECTION_CLIPBOARD
);
406 /* FIXME: what is default editability of a buffer? */
407 gtk_text_buffer_cut_clipboard (buffer
,
411 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view
),
412 gtk_text_buffer_get_insert (buffer
),
413 ANJUTA_VIEW_SCROLL_MARGIN
,
420 anjuta_view_copy_clipboard (AnjutaView
*view
)
422 GtkTextBuffer
*buffer
;
423 GtkClipboard
*clipboard
;
425 g_return_if_fail (ANJUTA_IS_VIEW (view
));
427 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
428 g_return_if_fail (buffer
!= NULL
);
430 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (view
),
431 GDK_SELECTION_CLIPBOARD
);
433 gtk_text_buffer_copy_clipboard (buffer
, clipboard
);
435 /* on copy do not scroll, we are already on screen */
439 anjuta_view_paste_clipboard (AnjutaView
*view
)
441 GtkTextBuffer
*buffer
;
442 GtkClipboard
*clipboard
;
444 g_return_if_fail (ANJUTA_IS_VIEW (view
));
446 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
447 g_return_if_fail (buffer
!= NULL
);
449 clipboard
= gtk_widget_get_clipboard (GTK_WIDGET (view
),
450 GDK_SELECTION_CLIPBOARD
);
452 /* FIXME: what is default editability of a buffer? */
453 gtk_text_buffer_paste_clipboard (buffer
,
458 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view
),
459 gtk_text_buffer_get_insert (buffer
),
460 ANJUTA_VIEW_SCROLL_MARGIN
,
467 anjuta_view_delete_selection (AnjutaView
*view
)
469 GtkTextBuffer
*buffer
= NULL
;
471 g_return_if_fail (ANJUTA_IS_VIEW (view
));
473 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
474 g_return_if_fail (buffer
!= NULL
);
476 /* FIXME: what is default editability of a buffer? */
477 gtk_text_buffer_delete_selection (buffer
,
481 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view
),
482 gtk_text_buffer_get_insert (buffer
),
483 ANJUTA_VIEW_SCROLL_MARGIN
,
490 anjuta_view_select_all (AnjutaView
*view
)
492 GtkTextBuffer
*buffer
= NULL
;
493 GtkTextIter start
, end
;
495 g_return_if_fail (ANJUTA_IS_VIEW (view
));
497 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
498 g_return_if_fail (buffer
!= NULL
);
500 gtk_text_buffer_get_bounds (buffer
, &start
, &end
);
501 gtk_text_buffer_select_range (buffer
, &start
, &end
);
505 anjuta_view_scroll_to_cursor (AnjutaView
*view
)
507 g_return_if_fail (ANJUTA_IS_VIEW (view
));
509 view
->priv
->scroll_idle
= g_idle_add ((GSourceFunc
) scroll_to_cursor_real
, view
);
513 anjuta_view_set_font (AnjutaView
*view
,
515 const gchar
*font_name
)
518 g_return_if_fail (ANJUTA_IS_VIEW (view
));
522 PangoFontDescription
*font_desc
= NULL
;
524 g_return_if_fail (font_name
!= NULL
);
526 font_desc
= pango_font_description_from_string (font_name
);
527 g_return_if_fail (font_desc
!= NULL
);
529 gtk_widget_modify_font (GTK_WIDGET (view
), font_desc
);
531 pango_font_description_free (font_desc
);
535 GtkRcStyle
*rc_style
;
537 rc_style
= gtk_widget_get_modifier_style (GTK_WIDGET (view
));
539 if (rc_style
->font_desc
)
540 pango_font_description_free (rc_style
->font_desc
);
542 rc_style
->font_desc
= NULL
;
544 gtk_widget_modify_style (GTK_WIDGET (view
), rc_style
);
549 anjuta_view_expose (GtkWidget
*widget
,
550 GdkEventExpose
*event
)
552 GtkTextView
*text_view
;
555 text_view
= GTK_TEXT_VIEW (widget
);
557 doc
= gtk_text_view_get_buffer (text_view
);
559 if ((event
->window
== gtk_text_view_get_window (text_view
, GTK_TEXT_WINDOW_TEXT
)))
561 GdkRectangle visible_rect
;
562 GtkTextIter iter1
, iter2
;
564 gtk_text_view_get_visible_rect (text_view
, &visible_rect
);
565 gtk_text_view_get_line_at_y (text_view
, &iter1
,
566 visible_rect
.y
, NULL
);
567 gtk_text_view_get_line_at_y (text_view
, &iter2
,
569 + visible_rect
.height
, NULL
);
570 gtk_text_iter_forward_line (&iter2
);
573 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class
)->expose_event
)(widget
, event
);
577 anjuta_view_key_press_event (GtkWidget
*widget
, GdkEventKey
*event
)
579 GtkTextBuffer
*buffer
;
580 AnjutaView
* view
= ANJUTA_VIEW(widget
);
581 AssistWindow
* assist_win
;
582 AssistTip
* assist_tip
;
584 buffer
= gtk_text_view_get_buffer (GTK_TEXT_VIEW (view
));
586 assist_win
= view
->priv
->sv
->priv
->assist_win
;
589 if (assist_window_filter_keypress(assist_win
, event
->keyval
))
591 DEBUG_PRINT("key filtered: %d", event
->keyval
);
595 assist_tip
= view
->priv
->sv
->priv
->assist_tip
;
598 switch (event
->keyval
)
605 gtk_widget_destroy (GTK_WIDGET(assist_tip
));
609 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class
)->key_press_event
)(widget
, event
);
613 anjuta_view_button_press_event (GtkWidget
*widget
, GdkEventButton
*event
)
615 AnjutaView
* view
= ANJUTA_VIEW(widget
);
617 /* If we have a calltip shown - hide it */
618 AssistTip
* assist_tip
= view
->priv
->sv
->priv
->assist_tip
;
619 AssistWindow
* assist_win
= view
->priv
->sv
->priv
->assist_win
;
622 gtk_widget_destroy (GTK_WIDGET (assist_win
));
626 gtk_widget_destroy (GTK_WIDGET (assist_tip
));
629 switch(event
->button
)
631 case 3: /* Right Button */
633 GtkTextBuffer
* buffer
= GTK_TEXT_BUFFER (view
->priv
->sv
->priv
->document
);
634 if (!gtk_text_buffer_get_has_selection (buffer
))
636 /* Move cursor to set breakpoints at correct line (#530689) */
638 gint buffer_x
, buffer_y
;
639 GtkTextWindowType type
= gtk_text_view_get_window_type (GTK_TEXT_VIEW (view
),
641 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view
),
647 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view
),
648 &iter
, buffer_x
, buffer_y
);
649 gtk_text_buffer_place_cursor (buffer
, &iter
);
651 gtk_menu_popup (GTK_MENU (view
->priv
->popup
), NULL
, NULL
, NULL
, NULL
,
652 event
->button
, event
->time
);
656 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class
)->button_press_event
)(widget
, event
);