1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-view.c
4 *
5 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
6 * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
7 * Copyright (C) 2003-2005 Paolo Maggi
8 * Copyright (C) 2006 Johannes Schmid
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 /*
27 * Modified by the anjuta Team, 1998-2005. See the AUTHORS file for a
28 * list of people on the anjuta Team.
29 * See the ChangeLog files for a list of changes.
30 *
31 * $Id$
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <string.h>
39 #include <stdlib.h>
40
41 #include <gdk/gdkkeysyms.h>
42
43 #include <glib/gi18n.h>
44 #include <glib.h>
45
46 #include <libanjuta/anjuta-debug.h>
47 #include <libanjuta/anjuta-encodings.h>
48 #include <libanjuta/anjuta-utils.h>
49 #include <libanjuta/interfaces/ianjuta-file-loader.h>
50
51 #include "anjuta-view.h"
52 #include "sourceview.h"
53 #include "sourceview-private.h"
54 #include "anjuta-marshal.h"
55
56 #define ANJUTA_VIEW_SCROLL_MARGIN 0.02
57
58 #define TARGET_URI_LIST 100
59 #define TARGET_GLADE 101
60
61 #define ANJUTA_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), ANJUTA_TYPE_VIEW, AnjutaViewPrivate))
62
63 enum
64 {
65 ANJUTA_VIEW_POPUP = 1,
66 ANJUTA_VIEW_SOURCEVIEW
67 };
68
69 struct _AnjutaViewPrivate
70 {
71 GtkWidget* popup;
72 guint scroll_idle;
73 Sourceview* sv;
74 };
75
76 static void anjuta_view_dispose (GObject *object);
77 static gint anjuta_view_focus_out (GtkWidget *widget,
78 GdkEventFocus *event);
79
80 static gboolean anjuta_view_draw (GtkWidget *widget,
81 cairo_t* cr);
82
83 static void anjuta_view_popup_menu_real (GtkWidget *widget, GdkEventButton *event);
84 static gboolean anjuta_view_popup_menu (GtkWidget *widget);
85
86 static gboolean anjuta_view_key_press_event (GtkWidget *widget,
87 GdkEventKey *event);
88 static gboolean anjuta_view_button_press_event (GtkWidget *widget,
89 GdkEventButton *event);
90
G_DEFINE_TYPE(AnjutaView,anjuta_view,GTK_SOURCE_TYPE_VIEW)91 G_DEFINE_TYPE(AnjutaView, anjuta_view, GTK_SOURCE_TYPE_VIEW)
92
93 static gboolean
94 scroll_to_cursor_real (AnjutaView *view)
95 {
96 GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
97 g_return_val_if_fail (buffer != NULL, FALSE);
98
99 gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
100 gtk_text_buffer_get_insert (buffer));
101
102 view->priv->scroll_idle = 0;
103 return FALSE;
104 }
105
106 static void
anjuta_view_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)107 anjuta_view_set_property (GObject * object,
108 guint property_id,
109 const GValue * value, GParamSpec * pspec)
110 {
111 AnjutaView *self = ANJUTA_VIEW (object);
112 g_return_if_fail(value != NULL);
113 g_return_if_fail(pspec != NULL);
114
115 switch (property_id)
116 {
117 case ANJUTA_VIEW_POPUP:
118 {
119 GtkWidget* widget;
120 self->priv->popup = g_value_get_object (value);
121 widget = gtk_menu_get_attach_widget(GTK_MENU(self->priv->popup));
122 /* This is a very ugly hack, maybe somebody more familiar with gtk menus
123 can fix this */
124 if (widget != NULL)
125 gtk_menu_detach(GTK_MENU(self->priv->popup));
126 gtk_menu_attach_to_widget(GTK_MENU(self->priv->popup), GTK_WIDGET(self), NULL);
127 break;
128 }
129 case ANJUTA_VIEW_SOURCEVIEW:
130 {
131 self->priv->sv = g_value_get_object (value);
132 break;
133 }
134 default:
135 {
136 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
137 break;
138 }
139 }
140 }
141
142 static void
anjuta_view_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)143 anjuta_view_get_property (GObject * object,
144 guint property_id,
145 GValue * value, GParamSpec * pspec)
146 {
147 AnjutaView *self = ANJUTA_VIEW (object);
148
149 g_return_if_fail(value != NULL);
150 g_return_if_fail(pspec != NULL);
151
152 switch (property_id)
153 {
154 case ANJUTA_VIEW_POPUP:
155 {
156 g_value_set_object (value, self->priv->popup);
157 break;
158 }
159 case ANJUTA_VIEW_SOURCEVIEW:
160 {
161 g_value_set_object (value, self->priv->sv);
162 break;
163 }
164 default:
165 {
166 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
167 break;
168 }
169 }
170 }
171
172 static GdkAtom
drag_get_target(GtkWidget * widget,GdkDragContext * context)173 drag_get_target (GtkWidget *widget,
174 GdkDragContext *context)
175 {
176 GdkAtom target;
177 GtkTargetList *tl;
178
179 tl = gtk_drag_dest_get_target_list (widget);
180
181 target = gtk_drag_dest_find_target (widget, context, tl);
182
183 return target;
184 }
185
186 static gboolean
anjuta_view_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint timestamp)187 anjuta_view_drag_drop (GtkWidget *widget,
188 GdkDragContext *context,
189 gint x,
190 gint y,
191 guint timestamp)
192 {
193 gboolean result;
194 GdkAtom target;
195
196 /* If this is a URL, just get the drag data */
197 target = drag_get_target (widget, context);
198
199 if (target != GDK_NONE)
200 {
201 gtk_drag_get_data (widget, context, target, timestamp);
202 result = TRUE;
203 }
204 else
205 {
206 /* Chain up */
207 result = GTK_WIDGET_CLASS (anjuta_view_parent_class)->drag_drop (widget, context, x, y, timestamp);
208 }
209
210 return result;
211 }
212
213 static SourceviewCell*
get_cell_from_position(GtkTextView * view,gint x,gint y)214 get_cell_from_position (GtkTextView* view,
215 gint x,
216 gint y)
217 {
218 gint buffer_x, buffer_y;
219 GtkTextIter iter;
220 SourceviewCell* cell;
221
222 gtk_text_view_window_to_buffer_coords (view,
223 GTK_TEXT_WINDOW_WIDGET,
224 x, y, &buffer_x, &buffer_y);
225
226 gtk_text_view_get_iter_at_location (view,
227 &iter, buffer_x, buffer_y);
228
229 cell = sourceview_cell_new (&iter, view);
230
231 return cell;
232 }
233
234 static gboolean
anjuta_view_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint timestamp)235 anjuta_view_drag_motion (GtkWidget *widget,
236 GdkDragContext *context,
237 gint x,
238 gint y,
239 guint timestamp)
240 {
241 AnjutaView* view = ANJUTA_VIEW (widget);
242 SourceviewCell* cell;
243 gboolean retval;
244
245 cell = get_cell_from_position (GTK_TEXT_VIEW(view->priv->sv->priv->view), x, y);
246
247 g_signal_emit_by_name (view->priv->sv,
248 "drop-possible",
249 cell, &retval);
250
251 g_object_unref (cell);
252
253 if (retval)
254 {
255 gdk_drag_status (context, GDK_ACTION_COPY, timestamp);
256 }
257
258 GTK_WIDGET_CLASS (anjuta_view_parent_class)->drag_motion (widget, context, x, y, timestamp);
259
260 return retval;
261 }
262
263 static void
anjuta_view_drag_data_received(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint timestamp)264 anjuta_view_drag_data_received (GtkWidget *widget,
265 GdkDragContext *context,
266 gint x,
267 gint y,
268 GtkSelectionData *selection_data,
269 guint info,
270 guint timestamp)
271 {
272 GSList* files;
273 AnjutaView* view = ANJUTA_VIEW (widget);
274 /* If this is an URL emit DROP_URIS, otherwise chain up the signal */
275 if (info == TARGET_URI_LIST)
276 {
277 files = anjuta_utils_drop_get_files (selection_data);
278
279 if (files != NULL)
280 {
281 IAnjutaFileLoader* loader = anjuta_shell_get_interface (view->priv->sv->priv->plugin->shell,
282 IAnjutaFileLoader, NULL);
283 GSList* node;
284 for (node = files; node != NULL; node = g_slist_next(node))
285 {
286 GFile* file = node->data;
287 ianjuta_file_loader_load (loader, file, FALSE, NULL);
288 g_object_unref (file);
289 }
290 g_slist_free (files);
291 gtk_drag_finish (context, TRUE, FALSE, timestamp);
292 }
293 gtk_drag_finish (context, FALSE, FALSE, timestamp);
294 }
295 else if (info == TARGET_GLADE)
296 {
297 const gchar* signal_data = (gchar*) gtk_selection_data_get_data (selection_data);
298 SourceviewCell* cell = get_cell_from_position (GTK_TEXT_VIEW (view->priv->sv->priv->view),
299 x, y);
300 g_signal_emit_by_name (view->priv->sv,
301 "drop",
302 cell,
303 signal_data);
304 g_object_unref (cell);
305 gtk_drag_finish (context, TRUE, FALSE, timestamp);
306 }
307 else
308 {
309 GTK_WIDGET_CLASS (anjuta_view_parent_class)->drag_data_received (widget, context, x, y, selection_data, info, timestamp);
310 }
311 }
312
313 static void
anjuta_view_class_init(AnjutaViewClass * klass)314 anjuta_view_class_init (AnjutaViewClass *klass)
315 {
316 GObjectClass *object_class = G_OBJECT_CLASS (klass);
317 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
318
319 object_class->dispose = anjuta_view_dispose;
320 object_class->set_property = anjuta_view_set_property;
321 object_class->get_property = anjuta_view_get_property;
322
323 widget_class->focus_out_event = anjuta_view_focus_out;
324 widget_class->draw = anjuta_view_draw;
325 widget_class->key_press_event = anjuta_view_key_press_event;
326 widget_class->button_press_event = anjuta_view_button_press_event;
327 widget_class->popup_menu = anjuta_view_popup_menu;
328 widget_class->drag_drop = anjuta_view_drag_drop;
329 widget_class->drag_data_received = anjuta_view_drag_data_received;
330 widget_class->drag_motion = anjuta_view_drag_motion;
331
332 g_type_class_add_private (klass, sizeof (AnjutaViewPrivate));
333
334 g_object_class_install_property (object_class,
335 ANJUTA_VIEW_POPUP,
336 g_param_spec_object ("popup",
337 "Popup menu",
338 "The popup-menu to show",
339 GTK_TYPE_WIDGET,
340 G_PARAM_READWRITE));
341 g_object_class_install_property (object_class,
342 ANJUTA_VIEW_SOURCEVIEW,
343 g_param_spec_object ("sourceview",
344 "Sourceview object",
345 "",
346 ANJUTA_TYPE_SOURCEVIEW,
347 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
348 }
349
350 static void
anjuta_view_init(AnjutaView * view)351 anjuta_view_init (AnjutaView *view)
352 {
353 GtkTargetList* tl;
354 view->priv = ANJUTA_VIEW_GET_PRIVATE (view);
355
356 /* Drag and drop support */
357 tl = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
358
359 if (tl != NULL)
360 {
361 GdkAtom target = gdk_atom_intern_static_string ("application/x-glade-signal");
362 gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
363 gtk_target_list_add (tl, target, GTK_TARGET_OTHER_WIDGET, TARGET_GLADE);
364 }
365 }
366
367 static void
anjuta_view_dispose(GObject * object)368 anjuta_view_dispose (GObject *object)
369 {
370 AnjutaView *view;
371
372 view = ANJUTA_VIEW (object);
373
374 if (view->priv->scroll_idle > 0)
375 g_source_remove (view->priv->scroll_idle);
376
377 if (view->priv->popup != NULL)
378 {
379 GtkWidget* widget = gtk_menu_get_attach_widget (GTK_MENU (view->priv->popup));
380 if (widget != NULL)
381 gtk_menu_detach (GTK_MENU (view->priv->popup));
382 }
383
384 (* G_OBJECT_CLASS (anjuta_view_parent_class)->dispose) (object);
385 }
386
387 static gint
anjuta_view_focus_out(GtkWidget * widget,GdkEventFocus * event)388 anjuta_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
389 {
390 AnjutaView *view = ANJUTA_VIEW (widget);
391 AssistTip* assist_tip = view->priv->sv->priv->assist_tip;
392
393 if (assist_tip)
394 gtk_widget_destroy(GTK_WIDGET(assist_tip));
395
396 gtk_widget_queue_draw (widget);
397
398
399 (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->focus_out_event) (widget, event);
400
401 return FALSE;
402 }
403
404
405 /**
406 * anjuta_view_new:
407 * @sv: a #Sourceview
408 *
409 * Creates a new #AnjutaView object displaying the @sv->priv->doc document.
410 * @doc cannot be NULL.
411 *
412 * Return value: a new #AnjutaView
413 **/
414 GtkWidget *
anjuta_view_new(Sourceview * sv)415 anjuta_view_new (Sourceview *sv)
416 {
417 GtkWidget *view;
418
419 /* Create widget with sane defaults */
420 view = GTK_WIDGET (g_object_new (ANJUTA_TYPE_VIEW,
421 "buffer", GTK_TEXT_BUFFER (sv->priv->document),
422 "sourceview", sv,
423 "wrap-mode", FALSE,
424 "indent-on-tab", TRUE, /* Fix #388727 */
425 "smart-home-end", GTK_SOURCE_SMART_HOME_END_BEFORE,
426 NULL));
427
428 return view;
429 }
430
431 void
anjuta_view_cut_clipboard(AnjutaView * view)432 anjuta_view_cut_clipboard (AnjutaView *view)
433 {
434 GtkTextBuffer *buffer;
435 GtkClipboard *clipboard;
436
437 g_return_if_fail (ANJUTA_IS_VIEW (view));
438
439 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
440 g_return_if_fail (buffer != NULL);
441
442 if (!gtk_text_view_get_editable (GTK_TEXT_VIEW(view)))
443 return;
444
445 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
446 GDK_SELECTION_CLIPBOARD);
447
448 /* FIXME: what is default editability of a buffer? */
449 gtk_text_buffer_cut_clipboard (buffer,
450 clipboard,
451 TRUE);
452
453 gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
454 gtk_text_buffer_get_insert (buffer));
455 }
456
457 void
anjuta_view_copy_clipboard(AnjutaView * view)458 anjuta_view_copy_clipboard (AnjutaView *view)
459 {
460 GtkTextBuffer *buffer;
461 GtkClipboard *clipboard;
462
463 g_return_if_fail (ANJUTA_IS_VIEW (view));
464
465 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
466 g_return_if_fail (buffer != NULL);
467
468 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
469 GDK_SELECTION_CLIPBOARD);
470
471 gtk_text_buffer_copy_clipboard (buffer, clipboard);
472 }
473
474 void
anjuta_view_paste_clipboard(AnjutaView * view)475 anjuta_view_paste_clipboard (AnjutaView *view)
476 {
477 GtkTextBuffer *buffer;
478 GtkClipboard *clipboard;
479
480 g_return_if_fail (ANJUTA_IS_VIEW (view));
481
482 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
483 g_return_if_fail (buffer != NULL);
484
485 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (view),
486 GDK_SELECTION_CLIPBOARD);
487
488 gtk_text_buffer_paste_clipboard (buffer,
489 clipboard,
490 NULL,
491 TRUE);
492
493 gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (view),
494 gtk_text_buffer_get_insert (buffer));
495 }
496
497 void
anjuta_view_delete_selection(AnjutaView * view)498 anjuta_view_delete_selection (AnjutaView *view)
499 {
500 GtkTextBuffer *buffer = NULL;
501
502 g_return_if_fail (ANJUTA_IS_VIEW (view));
503
504 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
505 g_return_if_fail (buffer != NULL);
506
507 /* FIXME: what is default editability of a buffer? */
508 gtk_text_buffer_delete_selection (buffer,
509 TRUE,
510 TRUE);
511
512 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
513 gtk_text_buffer_get_insert (buffer),
514 ANJUTA_VIEW_SCROLL_MARGIN,
515 FALSE,
516 0.0,
517 0.0);
518 }
519
520 void
anjuta_view_select_all(AnjutaView * view)521 anjuta_view_select_all (AnjutaView *view)
522 {
523 GtkTextBuffer *buffer = NULL;
524 GtkTextIter start, end;
525
526 g_return_if_fail (ANJUTA_IS_VIEW (view));
527
528 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
529 g_return_if_fail (buffer != NULL);
530
531 gtk_text_buffer_get_bounds (buffer, &start, &end);
532 gtk_text_buffer_select_range (buffer, &start, &end);
533 }
534
535 void
anjuta_view_scroll_to_cursor(AnjutaView * view)536 anjuta_view_scroll_to_cursor (AnjutaView *view)
537 {
538 g_return_if_fail (ANJUTA_IS_VIEW (view));
539
540 view->priv->scroll_idle = g_idle_add ((GSourceFunc) scroll_to_cursor_real, view);
541 }
542
543 void
anjuta_view_set_font(AnjutaView * view,gboolean def,const gchar * font_name)544 anjuta_view_set_font (AnjutaView *view,
545 gboolean def,
546 const gchar *font_name)
547 {
548
549 g_return_if_fail (ANJUTA_IS_VIEW (view));
550
551 if (!def)
552 {
553 PangoFontDescription *font_desc = NULL;
554
555 g_return_if_fail (font_name != NULL);
556
557 font_desc = pango_font_description_from_string (font_name);
558 g_return_if_fail (font_desc != NULL);
559
560 gtk_widget_override_font (GTK_WIDGET (view), font_desc);
561
562 pango_font_description_free (font_desc);
563 }
564 else
565 {
566 gtk_widget_override_font (GTK_WIDGET (view), NULL);
567 }
568 }
569
570 static gboolean
anjuta_view_draw(GtkWidget * widget,cairo_t * cr)571 anjuta_view_draw (GtkWidget *widget,
572 cairo_t *cr)
573 {
574 GtkTextView *text_view;
575 text_view = GTK_TEXT_VIEW (widget);
576
577 if (gtk_cairo_should_draw_window (cr, gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT)))
578 {
579 GdkRectangle visible_rect;
580 GtkTextIter iter1, iter2;
581
582 gtk_text_view_get_visible_rect (text_view, &visible_rect);
583 gtk_text_view_get_line_at_y (text_view, &iter1,
584 visible_rect.y, NULL);
585 gtk_text_view_get_line_at_y (text_view, &iter2,
586 visible_rect.y
587 + visible_rect.height, NULL);
588 gtk_text_iter_forward_line (&iter2);
589 }
590
591 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->draw)(widget, cr);
592 }
593
594 static gboolean
anjuta_view_key_press_event(GtkWidget * widget,GdkEventKey * event)595 anjuta_view_key_press_event (GtkWidget *widget, GdkEventKey *event)
596 {
597 AnjutaView* view = ANJUTA_VIEW(widget);
598 AssistTip* assist_tip;
599
600 assist_tip = view->priv->sv->priv->assist_tip;
601 switch (event->keyval)
602 {
603 case GDK_KEY_Escape:
604 case GDK_KEY_Up:
605 case GDK_KEY_Down:
606 case GDK_KEY_Page_Up:
607 case GDK_KEY_Page_Down:
608 if (assist_tip)
609 {
610 gtk_widget_destroy (GTK_WIDGET(assist_tip));
611 break;
612 }
613 break;
614 case GDK_KEY_F7:
615 /* F7 is used to toggle cursor visibility but we rather like to
616 * use it as shortcut for building (#611204)
617 */
618 return FALSE;
619 case GDK_KEY_Return:
620 /* Ctrl-Return is used for autocompletion */
621 if (event->state == GDK_CONTROL_MASK)
622 return FALSE;
623 }
624 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->key_press_event)(widget, event);
625 }
626
627 static void
anjuta_view_popup_menu_real(GtkWidget * widget,GdkEventButton * event)628 anjuta_view_popup_menu_real (GtkWidget *widget, GdkEventButton *event)
629 {
630 AnjutaView* view = ANJUTA_VIEW (widget);
631 gint button;
632 gint event_time;
633
634 if (event)
635 {
636 button = event->button;
637 event_time = event->time;
638 }
639 else
640 {
641 button = 0;
642 event_time = gtk_get_current_event_time ();
643 }
644
645 gtk_menu_popup (GTK_MENU (view->priv->popup), NULL, NULL, NULL, NULL,
646 button, event_time);
647 }
648
649 static gboolean
anjuta_view_popup_menu(GtkWidget * widget)650 anjuta_view_popup_menu (GtkWidget *widget)
651 {
652 anjuta_view_popup_menu_real (widget, NULL);
653
654 return TRUE;
655 }
656
657 static gboolean
anjuta_view_button_press_event(GtkWidget * widget,GdkEventButton * event)658 anjuta_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
659 {
660 AnjutaView* view = ANJUTA_VIEW(widget);
661
662 /* If we have a calltip shown - hide it */
663 AssistTip* assist_tip = view->priv->sv->priv->assist_tip;
664 if (assist_tip)
665 {
666 gtk_widget_destroy (GTK_WIDGET (assist_tip));
667 }
668
669 switch(event->button)
670 {
671 case 1: /* Handle double clicks to select complete word */
672 if (event->type == GDK_2BUTTON_PRESS)
673 {
674 GtkTextIter start, end;
675 anjuta_view_get_current_word (view, &start, &end);
676 gtk_text_buffer_select_range (gtk_text_iter_get_buffer (&start),
677 &start, &end);
678 return TRUE;
679 }
680 break;
681 case 3: /* Right Button */
682 {
683 GtkTextBuffer* buffer = GTK_TEXT_BUFFER (view->priv->sv->priv->document);
684 if (!gtk_text_buffer_get_has_selection (buffer))
685 {
686 /* Move cursor to set breakpoints at correct line (#530689) */
687 GtkTextIter iter;
688 gint buffer_x, buffer_y;
689 GtkTextWindowType type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view),
690 event->window);
691 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
692 type,
693 event->x,
694 event->y,
695 &buffer_x,
696 &buffer_y);
697 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view),
698 &iter, buffer_x, buffer_y);
699 gtk_text_buffer_place_cursor (buffer, &iter);
700 }
701 anjuta_view_popup_menu_real(widget, event);
702 return TRUE;
703 }
704 default:
705 break;
706 }
707 return (* GTK_WIDGET_CLASS (anjuta_view_parent_class)->button_press_event)(widget, event);
708 }
709
710 static gboolean
wordcharacters_contains(gchar c)711 wordcharacters_contains (gchar c)
712 {
713 if (g_ascii_isalnum(c) ||
714 c == '_')
715 return TRUE;
716 else
717 return FALSE;
718 }
719
720 void
anjuta_view_get_current_word(AnjutaView * view,GtkTextIter * start,GtkTextIter * end)721 anjuta_view_get_current_word (AnjutaView *view,
722 GtkTextIter *start,
723 GtkTextIter *end)
724 {
725 GtkTextBuffer *buffer =
726 gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
727 gchar c;
728
729 gtk_text_buffer_get_iter_at_mark (buffer, start,
730 gtk_text_buffer_get_insert (buffer));
731 gtk_text_buffer_get_iter_at_mark (buffer, end,
732 gtk_text_buffer_get_insert (buffer));
733
734 do
735 {
736 gunichar uni = gtk_text_iter_get_char (start);
737 gchar* outbuf = g_new0(gchar, 6);
738 gint len = g_unichar_to_utf8 (uni, outbuf);
739 /* Check for non-ascii */
740 if (len > 1)
741 break;
742 c = outbuf[0];
743 g_free (outbuf);
744 }
745 while (wordcharacters_contains (c) && gtk_text_iter_backward_char (start));
746 do
747 {
748 gunichar uni = gtk_text_iter_get_char (end);
749 gchar* outbuf = g_new0(gchar, 6);
750 gint len = g_unichar_to_utf8 (uni, outbuf);
751 /* Check for non-ascii */
752 if (len > 1)
753 break;
754 c = outbuf[0];
755 g_free (outbuf);
756 }
757 while (wordcharacters_contains (c) && gtk_text_iter_forward_char (end));
758
759 /* Point to the correct start character (not the character before) */
760 gtk_text_iter_forward_char (start);
761 }
762