2 * (c) 2010 Cyrill Gorcunov, gorcunov@gmail.com
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 * source view handling
29 #include <sys/param.h>
30 #include <sys/types.h>
35 #include <gdk/gdkkeysyms.h>
38 #include "sourceview.h"
55 void source_view_scroll_to_line(struct source_view
*sv
, unsigned long line
)
61 * for a caller @line is starting from 1 but in turn
62 * internally they are counted from 0 in widget
64 gtk_text_buffer_get_iter_at_line(sv
->text_buffer
, &sv
->text_iter_start
, line
- 1);
65 gtk_text_buffer_get_iter_at_line(sv
->text_buffer
, &sv
->text_iter_end
, line
);
67 gtk_text_buffer_select_range(sv
->text_buffer
, &sv
->text_iter_start
, &sv
->text_iter_end
);
69 while(gtk_events_pending())
72 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(sv
->text_widget
), &sv
->text_iter_start
, 0.25, FALSE
, 0, 0);
75 static int source_view_current_line(struct source_view
*sv
)
77 gtk_text_buffer_get_selection_bounds(sv
->text_buffer
,
78 &sv
->text_iter_start
, &sv
->text_iter_end
);
79 return gtk_text_iter_get_line(&sv
->text_iter_start
);
82 static struct tag
*tag_from_row(GtkTreeView
*view
, GtkTreePath
*path
, struct list_head
*tags
)
88 model
= gtk_tree_view_get_model(view
);
89 if (gtk_tree_model_get_iter(model
, &iter
, path
)) {
91 gtk_tree_model_get(model
, &iter
, COL_INDEX
, &key
, -1);
92 t
= tag_key_lookup(tags
, key
);
93 /* FIXME: free or unreference */
99 static gboolean
on_tagsTree_button_press_event(GtkWidget
*widget
,
100 GdkEventButton
*event
, gpointer data
)
102 struct source_view
*sv
= (struct source_view
*)data
;
103 GtkTreeViewColumn
*focus_column
= NULL
;
104 GtkTreePath
*path
= NULL
;
106 if (event
->button
!= 1 || event
->type
!= GDK_2BUTTON_PRESS
)
109 gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget
), &path
, &focus_column
);
111 struct list_head
*list
= sv
->etags
;
112 struct tag
*t
= tag_from_row(GTK_TREE_VIEW(widget
), path
, list
);
114 source_view_scroll_to_line(sv
, t
->line
);
115 gtk_tree_path_free(path
);
121 static void source_view_delete_hook(GtkWidget
*child
, void *private)
123 struct source_view
*sv
= private;
127 gtk_list_store_clear(sv
->etags_store
);
129 gtk_widget_destroy(sv
->text_widget
);
130 gtk_widget_destroy(sv
->etags_tree_widget
);
131 gtk_widget_destroy(sv
->me
);
133 g_free(sv
->text_contents
);
134 tags_free(sv
->etags
);
139 static void __cb_popup_cscope_query(struct source_view
*sv
, int type
, int nocase
)
142 if (gtk_text_buffer_get_selection_bounds(sv
->text_buffer
,
143 &sv
->text_iter_start
, &sv
->text_iter_end
)) {
144 str
= gtk_text_buffer_get_slice(sv
->text_buffer
,
145 &sv
->text_iter_start
, &sv
->text_iter_end
,
147 str
= skip_spaces(str
);
151 do_cscope_query(&gscope_info
, str
, type
, nocase
);
155 static void cp_popup_cscope_calling(gpointer user_data
, void *dummy
)
157 struct source_view
*sv
= (struct source_view
*)user_data
;
158 __cb_popup_cscope_query(sv
, CSCOPE_KEY_QRY_CALLING_FUNC
, 0);
161 static void cp_popup_cscope_called(gpointer user_data
, void *dummy
)
163 struct source_view
*sv
= (struct source_view
*)user_data
;
164 __cb_popup_cscope_query(sv
, CSCOPE_KEY_QRY_CALLED_FUNC
, 0);
167 static void cp_popup_cscope_ref(gpointer user_data
, void *dummy
)
169 struct source_view
*sv
= (struct source_view
*)user_data
;
170 __cb_popup_cscope_query(sv
, CSCOPE_KEY_QRY_REFERENCES
, 0);
173 static void cp_popup_cscope_def(gpointer user_data
, void *dummy
)
175 struct source_view
*sv
= (struct source_view
*)user_data
;
176 __cb_popup_cscope_query(sv
, CSCOPE_KEY_QRY_DEFINITION
, 0);
179 static void cb_populate_popup(GtkTextView
*entry
, GtkMenu
*menu
, gpointer user_data
)
181 GtkWidget
*mnuSep
= gtk_separator_menu_item_new();
182 GtkWidget
*mnuCScope_Def
= gtk_menu_item_new_with_label("Definition");
183 GtkWidget
*mnuCScope_Ref
= gtk_menu_item_new_with_label("References");
184 GtkWidget
*mnuCScope_Called
= gtk_menu_item_new_with_label("Called By");
185 GtkWidget
*mnuCScope_Calling
= gtk_menu_item_new_with_label("Calling");
187 #define popup_push(mnu, callback) \
189 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), mnu, 0); \
190 gtk_widget_show(mnu); \
191 g_signal_connect_swapped(GTK_OBJECT(mnu), "activate", \
192 G_CALLBACK(callback), (gpointer)user_data); \
195 gtk_menu_shell_insert(GTK_MENU_SHELL(menu
), mnuSep
, 0);
196 gtk_widget_show(mnuSep
);
198 popup_push(mnuCScope_Calling
, cp_popup_cscope_calling
);
199 popup_push(mnuCScope_Called
, cp_popup_cscope_called
);
200 popup_push(mnuCScope_Ref
, cp_popup_cscope_ref
);
201 popup_push(mnuCScope_Def
, cp_popup_cscope_def
);
204 static gboolean
cb_press_key(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
)
206 struct source_view
*sv
= (struct source_view
*)user_data
;
208 //debug("event->state: %x event->keyval: %x", event->state, event->keyval);
210 // GDK_Control_L, GDK_bracketleft
212 switch (event
->keyval
) {
213 case GDK_bracketleft
:
214 if (!(event
->state
& GDK_CONTROL_MASK
))
217 case GDK_bracketright
:
218 if (!(event
->state
& GDK_CONTROL_MASK
))
223 if (event
->state
& GDK_CONTROL_MASK
) {
224 struct notebook_page
*page
;
225 page
= notebook_page_find(gscope_info
.notebook_source
, sv
->me
);
227 g_signal_emit_by_name(page
->title
.close_button
, "clicked");
228 /* note after this point there is no user-data anymore */
237 GError
*error
= NULL
;
240 (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
)))
243 if (event
->state
& GDK_SHIFT_MASK
) {
244 argv
[0] = (char *)"gvim";
245 argv
[1] = sv
->file_path
;
249 argv
[0] = (char *)"gvim";
250 argv
[1] = (char *)"-R";
251 argv
[2] = sv
->file_path
;
256 snprintf(line
, sizeof(line
), "+%d",
257 source_view_current_line(sv
) + 1);
259 g_spawn_async_with_pipes(NULL
, argv
, NULL
,
262 NULL
, &pout
, NULL
, &error
);
271 * creates tags tree and textbox (both filled
272 * owb way by a content from file @path) and
273 * embed them into container
275 struct source_view
*source_view_create(char *path
)
277 GtkWidget
*scroll_tree
;
278 GtkWidget
*scroll_text
;
279 PangoFontDescription
*font_desc
;
280 GtkCellRenderer
*renderer
;
281 GtkTreeViewColumn
*column
;
289 struct source_view
*sv
= xzalloc(sizeof(*sv
));
292 * parse all things first
294 sv
->etags
= tag_parse_file(path
);
297 sv
->file_path
= strdup(path
);
298 sv
->file_name
= g_path_get_basename(sv
->file_path
);
302 if (!g_file_get_contents(path
, &sv
->text_contents
, &size
, &err
))
308 sv
->me
= gtk_hpaned_new();
310 scroll_tree
= gtk_scrolled_window_new(NULL
, NULL
);
311 scroll_text
= gtk_scrolled_window_new(NULL
, NULL
);
313 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_tree
),
314 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
315 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_text
),
316 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
321 sv
->etags_tree_widget
= gtk_tree_view_new();
322 gtk_container_add(GTK_CONTAINER(scroll_tree
), sv
->etags_tree_widget
);
323 gtk_widget_set_size_request(scroll_tree
, 20, -1);
325 renderer
= gtk_cell_renderer_text_new();
326 column
= gtk_tree_view_column_new_with_attributes("Name",
327 renderer
, "text", COL_NAME
, NULL
);
328 gtk_tree_view_column_set_resizable(column
, TRUE
);
329 gtk_tree_view_column_set_sort_column_id(column
, COL_NAME
);
330 gtk_tree_view_append_column(GTK_TREE_VIEW(sv
->etags_tree_widget
), column
);
332 renderer
= gtk_cell_renderer_text_new();
333 column
= gtk_tree_view_column_new_with_attributes("Line",
334 renderer
, "text", COL_LINE
, NULL
);
335 gtk_tree_view_column_set_resizable(column
, TRUE
);
336 gtk_tree_view_column_set_sort_column_id(column
, COL_LINE
);
337 gtk_tree_view_append_column(GTK_TREE_VIEW(sv
->etags_tree_widget
), column
);
339 renderer
= gtk_cell_renderer_text_new();
340 column
= gtk_tree_view_column_new_with_attributes("Type",
341 renderer
, "text", COL_TYPE
, NULL
);
342 gtk_tree_view_column_set_resizable(column
, TRUE
);
343 gtk_tree_view_column_set_sort_column_id(column
, COL_TYPE
);
344 gtk_tree_view_append_column(GTK_TREE_VIEW(sv
->etags_tree_widget
), column
);
346 sv
->etags_store
= gtk_list_store_new(NUM_COLS
,
347 G_TYPE_STRING
, G_TYPE_UINT
,
348 G_TYPE_STRING
, G_TYPE_ULONG
);
350 list_for_each_entry(t
, sv
->etags
, list
) {
351 gtk_list_store_append(sv
->etags_store
, &iter
);
352 gtk_list_store_set(sv
->etags_store
, &iter
,
355 COL_TYPE
, t
->symtype
,
360 model
= GTK_TREE_MODEL(sv
->etags_store
);
361 gtk_tree_view_set_model(GTK_TREE_VIEW(sv
->etags_tree_widget
), model
);
363 /* there is own reference anyway */
364 g_object_unref(model
);
367 g_signal_connect(G_OBJECT(sv
->etags_tree_widget
), "button_press_event",
368 G_CALLBACK(on_tagsTree_button_press_event
),
374 sv
->text_widget
= gtk_text_view_new();
375 gtk_container_add(GTK_CONTAINER(scroll_text
), sv
->text_widget
);
377 //font_desc = pango_font_description_from_string("monospace 10");
378 font_desc
= pango_font_description_from_string("Droid Sans Mono 11");
379 gtk_widget_modify_font(sv
->text_widget
, font_desc
);
380 pango_font_description_free(font_desc
);
381 gtk_text_view_set_editable(GTK_TEXT_VIEW(sv
->text_widget
), FALSE
);
382 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(sv
->text_widget
), 5);
383 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(sv
->text_widget
), 5);
385 sv
->text_buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(sv
->text_widget
));
386 gtk_text_buffer_set_text(sv
->text_buffer
, sv
->text_contents
, -1);
388 gtk_text_buffer_get_iter_at_line(sv
->text_buffer
, &sv
->text_iter_start
, 1);
389 gtk_text_buffer_get_iter_at_line(sv
->text_buffer
, &sv
->text_iter_end
, 1);
391 gtk_paned_pack1(GTK_PANED(sv
->me
), scroll_tree
, TRUE
, FALSE
);
392 gtk_paned_pack2(GTK_PANED(sv
->me
), scroll_text
, TRUE
, FALSE
);
397 g_signal_connect(G_OBJECT(sv
->text_widget
),
399 G_CALLBACK(&cb_populate_popup
),
405 g_signal_connect(G_OBJECT(sv
->text_widget
),
407 G_CALLBACK(&cb_press_key
),
410 sv
->delete_hook
= &source_view_delete_hook
;
415 tags_free(sv
->etags
);