geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ui_utils.c
Go to the documentation of this file.
1/*
2 * ui_utils.c - this file is part of Geany, a fast and lightweight IDE
3 *
4 * Copyright 2006 The Geany contributors
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/** @file ui_utils.h
22 * User Interface general utility functions.
23 */
24
25#ifdef HAVE_CONFIG_H
26# include "config.h"
27#endif
28
29#include "ui_utils.h"
30
31#include "app.h"
32#include "callbacks.h"
33#include "dialogs.h"
34#include "documentprivate.h"
35#include "encodingsprivate.h"
36#include "filetypes.h"
38#include "keyfile.h"
39#include "keybindings.h"
40#include "main.h"
41#include "msgwindow.h"
42#include "prefs.h"
43#include "project.h"
44#include "sciwrappers.h"
45#include "sidebar.h"
46#include "stash.h"
47#include "support.h"
48#include "symbols.h"
49#include "toolbar.h"
50#include "utils.h"
51#include "win32.h"
52#include "osx.h"
53
54#include <string.h>
55#include <ctype.h>
56#include <stdarg.h>
57#include <gtk/gtk.h>
58#include <gdk/gdkkeysyms.h>
59
60
61#define DEFAULT_STATUSBAR_TEMPLATE N_(\
62 "line: %l / %L\t " \
63 "col: %c\t " \
64 "sel: %s\t " \
65 "%w %t %m" \
66 "mode: %M " \
67 "encoding: %e " \
68 "filetype: %f " \
69 "scope: %S")
70
73
74UIPrefs ui_prefs;
75UIWidgets ui_widgets;
76
77static GtkBuilder *builder = NULL;
78static GtkWidget* window1 = NULL;
79static GtkWidget* toolbar_popup_menu1 = NULL;
80static GtkWidget* edit_menu1 = NULL;
81static GtkWidget* prefs_dialog = NULL;
82static GtkWidget* project_dialog = NULL;
83
84static struct
85{
86 /* pointers to widgets only sensitive when there is at least one document, the pointers can
87 * also be GtkAction objects, so check each pointer before using it */
88 GPtrArray *document_buttons;
90 GtkWidget *popup_goto_items[4];
91 GtkWidget *popup_copy_items[3];
92 GtkWidget *menu_copy_items[3];
93 GtkWidget *redo_items[3];
94 GtkWidget *undo_items[3];
95 GtkWidget *save_buttons[4];
97}
99
100enum
101{
105
106typedef struct
107{
108 gint type;
110 GtkWidget *menubar;
111 GtkWidget *toolbar;
112 void (*activate_cb)(GtkMenuItem *, gpointer);
114
115
116static void update_recent_menu(GeanyRecentFiles *grf);
117static void recent_file_loaded(const gchar *utf8_filename, GeanyRecentFiles *grf);
118static void recent_file_activate_cb(GtkMenuItem *menuitem, gpointer user_data);
119static void recent_project_activate_cb(GtkMenuItem *menuitem, gpointer user_data);
120static GtkWidget *progress_bar_create(void);
121static void ui_menu_sort_by_label(GtkMenu *menu);
122
123
124/* simple wrapper for gtk_widget_set_sensitive() to allow widget being NULL */
125void ui_widget_set_sensitive(GtkWidget *widget, gboolean set)
126{
127 if (widget != NULL)
128 gtk_widget_set_sensitive(widget, set);
129}
130
131
132/* allow_override is TRUE if text can be ignored when another message has been set
133 * that didn't use allow_override and has not timed out. */
134static void set_statusbar(const gchar *text, gboolean allow_override)
135{
136 static guint id = 0;
137 static glong last_time = 0;
138 GTimeVal timeval;
139 const gint GEANY_STATUS_TIMEOUT = 1;
140
142 return; /* just do nothing if statusbar is not visible */
143
144 if (id == 0)
145 id = gtk_statusbar_get_context_id(GTK_STATUSBAR(ui_widgets.statusbar), "geany-main");
146
147 g_get_current_time(&timeval);
148
149 if (! allow_override)
150 {
151 gtk_statusbar_pop(GTK_STATUSBAR(ui_widgets.statusbar), id);
152 gtk_statusbar_push(GTK_STATUSBAR(ui_widgets.statusbar), id, text);
153 last_time = timeval.tv_sec;
154 }
155 else
156 if (timeval.tv_sec > last_time + GEANY_STATUS_TIMEOUT)
157 {
158 gtk_statusbar_pop(GTK_STATUSBAR(ui_widgets.statusbar), id);
159 gtk_statusbar_push(GTK_STATUSBAR(ui_widgets.statusbar), id, text);
160 }
161}
162
163
164/** Displays text on the statusbar.
165 * @param log Whether the message should be recorded in the Status window.
166 * @param format A @c printf -style string. */
167GEANY_API_SYMBOL
168void ui_set_statusbar(gboolean log, const gchar *format, ...)
169{
170 gchar *string;
171 va_list args;
172
173 va_start(args, format);
174 string = g_strdup_vprintf(format, args);
175 va_end(args);
176
178 set_statusbar(string, FALSE);
179
181 msgwin_status_add("%s", string);
182
183 g_free(string);
184}
185
186
187/* note: some comments below are for translators */
189 guint line, guint vcol, guint pos)
190{
191 const gchar *cur_tag;
192 const gchar *fmt;
193 const gchar *expos; /* % expansion position */
194 const gchar sp[] = " ";
195 GString *stats_str;
196 ScintillaObject *sci = doc->editor->sci;
197
198 if (!EMPTY(ui_prefs.statusbar_template))
199 fmt = ui_prefs.statusbar_template;
200 else
202
203 stats_str = g_string_sized_new(120);
204
205 while ((expos = strchr(fmt, '%')) != NULL)
206 {
207 /* append leading text before % char */
208 g_string_append_len(stats_str, fmt, expos - fmt);
209
210 switch (*++expos)
211 {
212 case 'l':
213 g_string_append_printf(stats_str, "%d", line + 1);
214 break;
215 case 'L':
216 g_string_append_printf(stats_str, "%d",
218 break;
219 case 'c':
220 g_string_append_printf(stats_str, "%d", vcol);
221 break;
222 case 'C':
223 g_string_append_printf(stats_str, "%d", vcol + 1);
224 break;
225 case 'p':
226 g_string_append_printf(stats_str, "%u", pos);
227 break;
228 case 's':
229 {
230 gint len = sci_get_selected_text_length(sci) - 1;
231 /* check if whole lines are selected */
232 if (!len || sci_get_col_from_position(sci,
236 g_string_append_printf(stats_str, "%d", len);
237 else /* L = lines */
238 g_string_append_printf(stats_str, _("%dL"),
240 break;
241 }
242 case 'n' :
243 g_string_append_printf(stats_str, "%d",
245 break;
246 case 'w':
247 /* RO = read-only */
248 g_string_append(stats_str, (doc->readonly) ? _("RO ") :
249 /* OVR = overwrite/overtype, INS = insert */
250 (sci_get_overtype(doc->editor->sci) ? _("OVR") : _("INS")));
251 break;
252 case 'r':
253 if (doc->readonly)
254 {
255 g_string_append(stats_str, _("RO ")); /* RO = read-only */
256 g_string_append(stats_str, sp + 1);
257 }
258 break;
259 case 't':
260 {
261 switch (editor_get_indent_prefs(doc->editor)->type)
262 {
264 g_string_append(stats_str, _("TAB"));
265 break;
266 case GEANY_INDENT_TYPE_SPACES: /* SP = space */
267 g_string_append(stats_str, _("SP"));
268 break;
269 case GEANY_INDENT_TYPE_BOTH: /* T/S = tabs and spaces */
270 g_string_append(stats_str, _("T/S"));
271 break;
272 }
273 break;
274 }
275 case 'm':
276 if (doc->changed)
277 {
278 g_string_append(stats_str, _("MOD")); /* MOD = modified */
279 g_string_append(stats_str, sp);
280 }
281 break;
282 case 'M':
283 g_string_append(stats_str, utils_get_eol_short_name(sci_get_eol_mode(doc->editor->sci)));
284 break;
285 case 'e':
286 g_string_append(stats_str,
287 doc->encoding ? doc->encoding : _("unknown"));
289 {
290 g_string_append_c(stats_str, ' ');
291 g_string_append(stats_str, _("(with BOM)")); /* BOM = byte order mark */
292 }
293 break;
294 case 'f':
295 g_string_append(stats_str, filetypes_get_display_name(doc->file_type));
296 break;
297 case 'S':
298 symbols_get_current_scope(doc, &cur_tag);
299 g_string_append(stats_str, cur_tag);
300 break;
301 case 'Y':
302 g_string_append_c(stats_str, ' ');
303 g_string_append_printf(stats_str, "%d",
305 break;
306 default:
307 g_string_append_len(stats_str, expos, 1);
308 }
309
310 /* skip past %c chars */
311 if (*expos)
312 fmt = expos + 1;
313 else
314 break;
315 }
316 /* add any remaining text */
317 g_string_append(stats_str, fmt);
318
319 return g_string_free(stats_str, FALSE);
320}
321
322
323/* updates the status bar document statistics */
325{
326 g_return_if_fail(doc == NULL || doc->is_valid);
327
329 return; /* just do nothing if statusbar is not visible */
330
331 if (doc == NULL)
332 doc = document_get_current();
333
334 if (doc != NULL)
335 {
336 guint line, vcol;
337 gchar *stats_str;
338
339 if (pos == -1)
342
343 /* Add temporary fix for sci infinite loop in Document::GetColumn(int)
344 * when current pos is beyond document end (can occur when removing
345 * blocks of selected lines especially esp. brace sections near end of file). */
346 if (pos <= sci_get_length(doc->editor->sci))
348 else
349 vcol = 0;
351
352 stats_str = create_statusbar_statistics(doc, line, vcol, pos);
353
354 /* can be overridden by status messages */
355 set_statusbar(stats_str, TRUE);
356 g_free(stats_str);
357 }
358 else /* no documents */
359 {
360 set_statusbar("", TRUE); /* can be overridden by status messages */
361 }
362}
363
364
365/* This sets the window title according to the current filename. */
367{
368 GString *str;
369 GeanyProject *project = app->project;
370
371 g_return_if_fail(doc == NULL || doc->is_valid);
372
373 if (doc == NULL)
374 doc = document_get_current();
375
376 str = g_string_new(NULL);
377
378 if (doc != NULL)
379 {
380 g_string_append(str, doc->changed ? "*" : "");
381
382 if (doc->file_name == NULL)
383 g_string_append(str, DOC_FILENAME(doc));
384 else
385 {
386 gchar *short_name = document_get_basename_for_display(doc, 30);
387 gchar *dirname = g_path_get_dirname(DOC_FILENAME(doc));
388
389 g_string_append(str, short_name);
390 g_string_append(str, " - ");
391 g_string_append(str, dirname ? dirname : "");
392 g_free(short_name);
393 g_free(dirname);
394 }
395 g_string_append(str, " - ");
396 }
397 if (project)
398 {
399 g_string_append_c(str, '[');
400 g_string_append(str, project->name);
401 g_string_append(str, "] - ");
402 }
403 g_string_append(str, "Geany");
404 if (cl_options.new_instance)
405 {
406 g_string_append(str, _(" (new instance)"));
407 }
408 gtk_window_set_title(GTK_WINDOW(main_widgets.window), str->str);
409 g_string_free(str, TRUE);
410}
411
412
413void ui_set_editor_font(const gchar *font_name)
414{
415 guint i;
416
417 g_return_if_fail(font_name != NULL);
418
419 /* do nothing if font has not changed */
421 if (strcmp(font_name, interface_prefs.editor_font) == 0)
422 return;
423
425 interface_prefs.editor_font = g_strdup(font_name);
426
427 /* We copy the current style, and update the font in all open tabs. */
428 for (i = 0; i < documents_array->len; i++)
429 {
430 if (documents[i]->editor)
431 {
433 }
434 }
435
436 ui_set_statusbar(TRUE, _("Font updated (%s)."), interface_prefs.editor_font);
437}
438
439
441{
442 if (ui_prefs.fullscreen)
443 {
444 gtk_window_fullscreen(GTK_WINDOW(main_widgets.window));
445 }
446 else
447 {
448 gtk_window_unfullscreen(GTK_WINDOW(main_widgets.window));
449 }
450}
451
452
454{
455 gboolean enable_undo;
456 gboolean enable_redo;
457 guint i, len;
458
459 g_return_if_fail(doc == NULL || doc->is_valid);
460
461 if (doc == NULL)
462 {
463 enable_undo = FALSE;
464 enable_redo = FALSE;
465 }
466 else
467 {
468 enable_undo = document_can_undo(doc);
469 enable_redo = document_can_redo(doc);
470 }
471
472 /* index 0 is the popup menu, 1 is the menubar, 2 is the toolbar */
473 len = G_N_ELEMENTS(widgets.undo_items);
474 for (i = 0; i < len; i++)
475 {
476 ui_widget_set_sensitive(widgets.undo_items[i], enable_undo);
477 }
478 len = G_N_ELEMENTS(widgets.redo_items);
479 for (i = 0; i < len; i++)
480 {
481 ui_widget_set_sensitive(widgets.redo_items[i], enable_redo);
482 }
483}
484
485
487{
488 gboolean enable;
489 guint i, len;
490
491 g_return_if_fail(doc == NULL || doc->is_valid);
492
493 if (doc == NULL)
494 enable = FALSE;
495 else
496 enable = sci_has_selection(doc->editor->sci);
497
498 len = G_N_ELEMENTS(widgets.popup_copy_items);
499 for (i = 0; i < len; i++)
500 ui_widget_set_sensitive(widgets.popup_copy_items[i], enable);
501}
502
503
504void ui_update_popup_goto_items(gboolean enable)
505{
506 guint i, len;
507 len = G_N_ELEMENTS(widgets.popup_goto_items);
508 for (i = 0; i < len; i++)
509 ui_widget_set_sensitive(widgets.popup_goto_items[i], enable);
510}
511
512
513void ui_menu_copy_items_set_sensitive(gboolean sensitive)
514{
515 guint i, len;
516
517 len = G_N_ELEMENTS(widgets.menu_copy_items);
518 for (i = 0; i < len; i++)
519 ui_widget_set_sensitive(widgets.menu_copy_items[i], sensitive);
520}
521
522
524{
525 gboolean enable = FALSE;
526 GtkWidget *focusw = gtk_window_get_focus(GTK_WINDOW(main_widgets.window));
527
528 g_return_if_fail(doc == NULL || doc->is_valid);
529
530 if (IS_SCINTILLA(focusw))
531 enable = (doc == NULL) ? FALSE : sci_has_selection(doc->editor->sci);
532 else
533 if (GTK_IS_EDITABLE(focusw))
534 enable = gtk_editable_get_selection_bounds(GTK_EDITABLE(focusw), NULL, NULL);
535 else
536 if (GTK_IS_TEXT_VIEW(focusw))
537 {
538 GtkTextBuffer *buffer = gtk_text_view_get_buffer(
539 GTK_TEXT_VIEW(focusw));
540 enable = gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL);
541 }
542
544}
545
546
548{
549 gboolean enable = FALSE;
550
551 g_return_if_fail(doc == NULL || doc->is_valid);
552
553 if (doc == NULL || doc->file_type == NULL)
554 enable = FALSE;
555 else if (doc->file_type->id == GEANY_FILETYPES_C || doc->file_type->id == GEANY_FILETYPES_CPP)
556 enable = TRUE;
557
558 ui_widget_set_sensitive(widgets.menu_insert_include_items[item], enable);
559}
560
561
563{
567}
568
569
570/* @include include name or NULL for empty with cursor ready for typing it */
571static void insert_include(GeanyDocument *doc, gint pos, const gchar *include)
572{
573 gint pos_after = -1;
574 gchar *text;
575
576 g_return_if_fail(doc != NULL);
577 g_return_if_fail(pos == -1 || pos >= 0);
578
579 if (pos == -1)
581
582 if (! include)
583 {
584 text = g_strdup("#include \"\"\n");
585 pos_after = pos + 10;
586 }
587 else
588 {
589 text = g_strconcat("#include <", include, ">\n", NULL);
590 }
591
595 g_free(text);
596 if (pos_after >= 0)
597 sci_goto_pos(doc->editor->sci, pos_after, FALSE);
598}
599
600
601static void on_popup_insert_include_activate(GtkMenuItem *menuitem, gpointer user_data)
602{
603 insert_include(document_get_current(), editor_info.click_pos, user_data);
604}
605
606
607static void on_menu_insert_include_activate(GtkMenuItem *menuitem, gpointer user_data)
608{
609 insert_include(document_get_current(), -1, user_data);
610}
611
612
613static void insert_include_items(GtkMenu *me, GtkMenu *mp, gchar **includes, gchar *label)
614{
615 guint i = 0;
616 GtkWidget *edit_menu, *edit_menu_item;
617 GtkWidget *popup_menu, *popup_menu_item;
618
619 edit_menu = gtk_menu_new();
620 popup_menu = gtk_menu_new();
621 edit_menu_item = gtk_menu_item_new_with_label(label);
622 popup_menu_item = gtk_menu_item_new_with_label(label);
623 gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_menu_item), edit_menu);
624 gtk_menu_item_set_submenu(GTK_MENU_ITEM(popup_menu_item), popup_menu);
625
626 while (includes[i] != NULL)
627 {
628 GtkWidget *tmp_menu = gtk_menu_item_new_with_label(includes[i]);
629 GtkWidget *tmp_popup = gtk_menu_item_new_with_label(includes[i]);
630
631 gtk_container_add(GTK_CONTAINER(edit_menu), tmp_menu);
632 gtk_container_add(GTK_CONTAINER(popup_menu), tmp_popup);
633 g_signal_connect(tmp_menu, "activate",
634 G_CALLBACK(on_menu_insert_include_activate), (gpointer) includes[i]);
635 g_signal_connect(tmp_popup, "activate",
636 G_CALLBACK(on_popup_insert_include_activate), (gpointer) includes[i]);
637 i++;
638 }
639 gtk_widget_show_all(edit_menu_item);
640 gtk_widget_show_all(popup_menu_item);
641 gtk_container_add(GTK_CONTAINER(me), edit_menu_item);
642 gtk_container_add(GTK_CONTAINER(mp), popup_menu_item);
643}
644
645
647{
648 GtkMenu *menu_edit = GTK_MENU(ui_lookup_widget(main_widgets.window, "insert_include2_menu"));
649 GtkMenu *menu_popup = GTK_MENU(ui_lookup_widget(main_widgets.editor_menu, "insert_include1_menu"));
650 GtkWidget *blank;
651 const gchar *c_includes_stdlib[] = {
652 "assert.h", "ctype.h", "errno.h", "float.h", "limits.h", "locale.h", "math.h", "setjmp.h",
653 "signal.h", "stdarg.h", "stddef.h", "stdio.h", "stdlib.h", "string.h", "time.h", NULL
654 };
655 const gchar *c_includes_c99[] = {
656 "complex.h", "fenv.h", "inttypes.h", "iso646.h", "stdbool.h", "stdint.h",
657 "tgmath.h", "wchar.h", "wctype.h", NULL
658 };
659 const gchar *c_includes_cpp[] = {
660 "cstdio", "cstring", "cctype", "cmath", "ctime", "cstdlib", "cstdarg", NULL
661 };
662 const gchar *c_includes_cppstdlib[] = {
663 "iostream", "fstream", "iomanip", "sstream", "exception", "stdexcept",
664 "memory", "locale", NULL
665 };
666 const gchar *c_includes_stl[] = {
667 "bitset", "deque", "list", "map", "set", "queue", "stack", "vector", "algorithm",
668 "iterator", "functional", "string", "complex", "valarray", NULL
669 };
670
671 blank = gtk_menu_item_new_with_label("#include \"...\"");
672 gtk_container_add(GTK_CONTAINER(menu_edit), blank);
673 gtk_widget_show(blank);
674 g_signal_connect(blank, "activate", G_CALLBACK(on_menu_insert_include_activate), NULL);
675 blank = gtk_separator_menu_item_new ();
676 gtk_container_add(GTK_CONTAINER(menu_edit), blank);
677 gtk_widget_show(blank);
678
679 blank = gtk_menu_item_new_with_label("#include \"...\"");
680 gtk_container_add(GTK_CONTAINER(menu_popup), blank);
681 gtk_widget_show(blank);
682 g_signal_connect(blank, "activate", G_CALLBACK(on_popup_insert_include_activate), NULL);
683 blank = gtk_separator_menu_item_new();
684 gtk_container_add(GTK_CONTAINER(menu_popup), blank);
685 gtk_widget_show(blank);
686
687 insert_include_items(menu_edit, menu_popup, (gchar**) c_includes_stdlib, _("C Standard Library"));
688 insert_include_items(menu_edit, menu_popup, (gchar**) c_includes_c99, _("ISO C99"));
689 insert_include_items(menu_edit, menu_popup, (gchar**) c_includes_cpp, _("C++ (C Standard Library)"));
690 insert_include_items(menu_edit, menu_popup, (gchar**) c_includes_cppstdlib, _("C++ Standard Library"));
691 insert_include_items(menu_edit, menu_popup, (gchar**) c_includes_stl, _("C++ STL"));
692}
693
694
695static void insert_date(GeanyDocument *doc, gint pos, const gchar *date_style)
696{
697 const gchar *format = NULL;
698 gchar *time_str;
699
700 g_return_if_fail(doc != NULL);
701 g_return_if_fail(pos == -1 || pos >= 0);
702
703 if (pos == -1)
705
706 /* set default value */
707 if (utils_str_equal("", ui_prefs.custom_date_format))
708 {
709 g_free(ui_prefs.custom_date_format);
710 ui_prefs.custom_date_format = g_strdup("%d.%m.%Y");
711 }
712
713 if (utils_str_equal(_("dd.mm.yyyy"), date_style))
714 format = "%d.%m.%Y";
715 else if (utils_str_equal(_("mm.dd.yyyy"), date_style))
716 format = "%m.%d.%Y";
717 else if (utils_str_equal(_("yyyy/mm/dd"), date_style))
718 format = "%Y/%m/%d";
719 else if (utils_str_equal(_("dd.mm.yyyy hh:mm:ss"), date_style))
720 format = "%d.%m.%Y %H:%M:%S";
721 else if (utils_str_equal(_("mm.dd.yyyy hh:mm:ss"), date_style))
722 format = "%m.%d.%Y %H:%M:%S";
723 else if (utils_str_equal(_("yyyy/mm/dd hh:mm:ss"), date_style))
724 format = "%Y/%m/%d %H:%M:%S";
725 else if (utils_str_equal(_("_Use Custom Date Format"), date_style))
726 format = ui_prefs.custom_date_format;
727 else
728 {
729 gchar *str = dialogs_show_input(_("Custom Date Format"), GTK_WINDOW(main_widgets.window),
730 _("Enter here a custom date and time format. "
731 "You can use any conversion specifiers which can be used with the ANSI C strftime function."),
732 ui_prefs.custom_date_format);
733 if (str)
734 SETPTR(ui_prefs.custom_date_format, str);
735 return;
736 }
737
738 time_str = utils_get_date_time(format, NULL);
739 if (time_str != NULL)
740 {
742 sci_insert_text(doc->editor->sci, pos, time_str);
743 sci_goto_pos(doc->editor->sci, pos + strlen(time_str), FALSE);
745 g_free(time_str);
746 }
747 else
748 {
749 utils_beep();
750 ui_set_statusbar(TRUE,
751 _("Date format string could not be converted (possibly too long)."));
752 }
753}
754
755
756static void on_popup_insert_date_activate(GtkMenuItem *menuitem, gpointer user_data)
757{
758 insert_date(document_get_current(), editor_info.click_pos, user_data);
759}
760
761
762static void on_menu_insert_date_activate(GtkMenuItem *menuitem, gpointer user_data)
763{
764 insert_date(document_get_current(), -1, user_data);
765}
766
767
768static void insert_date_items(GtkMenu *me, GtkMenu *mp, gchar *label)
769{
770 GtkWidget *item;
771
772 item = gtk_menu_item_new_with_mnemonic(label);
773 gtk_container_add(GTK_CONTAINER(me), item);
774 gtk_widget_show(item);
775 g_signal_connect(item, "activate", G_CALLBACK(on_menu_insert_date_activate), label);
776
777 item = gtk_menu_item_new_with_mnemonic(label);
778 gtk_container_add(GTK_CONTAINER(mp), item);
779 gtk_widget_show(item);
780 g_signal_connect(item, "activate", G_CALLBACK(on_popup_insert_date_activate), label);
781}
782
783
785{
786 GtkMenu *menu_edit = GTK_MENU(ui_lookup_widget(main_widgets.window, "insert_date1_menu"));
787 GtkMenu *menu_popup = GTK_MENU(ui_lookup_widget(main_widgets.editor_menu, "insert_date2_menu"));
788 GtkWidget *item;
789 gchar *str;
790
791 insert_date_items(menu_edit, menu_popup, _("dd.mm.yyyy"));
792 insert_date_items(menu_edit, menu_popup, _("mm.dd.yyyy"));
793 insert_date_items(menu_edit, menu_popup, _("yyyy/mm/dd"));
794
795 item = gtk_separator_menu_item_new();
796 gtk_container_add(GTK_CONTAINER(menu_edit), item);
797 gtk_widget_show(item);
798 item = gtk_separator_menu_item_new();
799 gtk_container_add(GTK_CONTAINER(menu_popup), item);
800 gtk_widget_show(item);
801
802 insert_date_items(menu_edit, menu_popup, _("dd.mm.yyyy hh:mm:ss"));
803 insert_date_items(menu_edit, menu_popup, _("mm.dd.yyyy hh:mm:ss"));
804 insert_date_items(menu_edit, menu_popup, _("yyyy/mm/dd hh:mm:ss"));
805
806 item = gtk_separator_menu_item_new();
807 gtk_container_add(GTK_CONTAINER(menu_edit), item);
808 gtk_widget_show(item);
809 item = gtk_separator_menu_item_new();
810 gtk_container_add(GTK_CONTAINER(menu_popup), item);
811 gtk_widget_show(item);
812
813 str = _("_Use Custom Date Format");
814 item = gtk_menu_item_new_with_mnemonic(str);
815 gtk_container_add(GTK_CONTAINER(menu_edit), item);
816 gtk_widget_show(item);
817 g_signal_connect(item, "activate", G_CALLBACK(on_menu_insert_date_activate), str);
818 ui_hookup_widget(main_widgets.window, item, "insert_date_custom1");
819
820 item = gtk_menu_item_new_with_mnemonic(str);
821 gtk_container_add(GTK_CONTAINER(menu_popup), item);
822 gtk_widget_show(item);
823 g_signal_connect(item, "activate", G_CALLBACK(on_popup_insert_date_activate), str);
824 ui_hookup_widget(main_widgets.editor_menu, item, "insert_date_custom2");
825
826 insert_date_items(menu_edit, menu_popup, _("_Set Custom Date Format"));
827}
828
829
830void ui_save_buttons_toggle(gboolean enable)
831{
832 guint i;
833 gboolean dirty_tabs = FALSE;
834
835 if (ui_prefs.allow_always_save)
836 enable = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) > 0;
837
838 ui_widget_set_sensitive(widgets.save_buttons[0], enable);
839 ui_widget_set_sensitive(widgets.save_buttons[1], enable);
840
841 /* save all menu item and tool button */
842 for (i = 0; i < documents_array->len; i++)
843 {
844 /* check whether there are files where changes were made and if there are some,
845 * we need the save all button / item */
846 if (documents[i]->is_valid && documents[i]->changed)
847 {
848 dirty_tabs = TRUE;
849 break;
850 }
851 }
852
853 ui_widget_set_sensitive(widgets.save_buttons[2], dirty_tabs);
854 ui_widget_set_sensitive(widgets.save_buttons[3], dirty_tabs);
855}
856
857
858#define add_doc_widget(widget_name) \
859 g_ptr_array_add(widgets.document_buttons, ui_lookup_widget(main_widgets.window, widget_name))
860
861#define add_doc_toolitem(widget_name) \
862 g_ptr_array_add(widgets.document_buttons, toolbar_get_action_by_name(widget_name))
863
864static void init_document_widgets(void)
865{
866 widgets.document_buttons = g_ptr_array_new();
867
868 /* Cache the document-sensitive widgets so we don't have to keep looking them up
869 * when using ui_document_buttons_update(). */
870 add_doc_widget("menu_close1");
871 add_doc_widget("close_other_documents1");
872 add_doc_widget("menu_change_font1");
873 add_doc_widget("menu_close_all1");
874 add_doc_widget("menu_save1");
875 add_doc_widget("menu_save_all1");
876 add_doc_widget("menu_save_as1");
877 add_doc_widget("menu_count_words1");
878 add_doc_widget("menu_build1");
879 add_doc_widget("add_comments1");
880 add_doc_widget("menu_paste1");
881 add_doc_widget("menu_undo2");
882 add_doc_widget("properties1");
883 add_doc_widget("menu_reload1");
884 add_doc_widget("menu_document1");
885 add_doc_widget("menu_choose_color1");
886 add_doc_widget("menu_color_schemes");
887 add_doc_widget("menu_markers_margin1");
888 add_doc_widget("menu_linenumber_margin1");
889 add_doc_widget("menu_show_white_space1");
890 add_doc_widget("menu_show_line_endings1");
891 add_doc_widget("menu_show_indentation_guides1");
892 add_doc_widget("menu_zoom_in1");
893 add_doc_widget("menu_zoom_out1");
894 add_doc_widget("normal_size1");
895 add_doc_widget("treeview6");
896 add_doc_widget("print1");
897 add_doc_widget("menu_reload_as1");
898 add_doc_widget("menu_select_all1");
899 add_doc_widget("insert_date1");
900 add_doc_widget("insert_alternative_white_space1");
901 add_doc_widget("menu_format1");
902 add_doc_widget("commands2");
903 add_doc_widget("menu_open_selected_file1");
904 add_doc_widget("page_setup1");
905 add_doc_widget("find1");
906 add_doc_widget("find_next1");
907 add_doc_widget("find_previous1");
908 add_doc_widget("go_to_next_marker1");
909 add_doc_widget("go_to_previous_marker1");
910 add_doc_widget("replace1");
911 add_doc_widget("find_nextsel1");
912 add_doc_widget("find_prevsel1");
913 add_doc_widget("find_usage1");
914 add_doc_widget("find_document_usage1");
915 add_doc_widget("mark_all1");
916 add_doc_widget("go_to_line1");
917 add_doc_widget("goto_tag_definition1");
918 add_doc_widget("goto_tag_declaration1");
919 add_doc_widget("reset_indentation1");
920 add_doc_toolitem("Close");
921 add_doc_toolitem("CloseAll");
922 add_doc_toolitem("Search");
923 add_doc_toolitem("SearchEntry");
924 add_doc_toolitem("ZoomIn");
925 add_doc_toolitem("ZoomOut");
926 add_doc_toolitem("Indent");
927 add_doc_toolitem("UnIndent");
928 add_doc_toolitem("Cut");
929 add_doc_toolitem("Copy");
930 add_doc_toolitem("Paste");
931 add_doc_toolitem("Delete");
932 add_doc_toolitem("Save");
933 add_doc_toolitem("SaveAs");
934 add_doc_toolitem("SaveAll");
935 add_doc_toolitem("Compile");
936 add_doc_toolitem("Run");
937 add_doc_toolitem("Reload");
938 add_doc_toolitem("Color");
939 add_doc_toolitem("Goto");
940 add_doc_toolitem("GotoEntry");
941 add_doc_toolitem("Replace");
942 add_doc_toolitem("Print");
943}
944
945
947{
948 guint i;
949 gboolean enable = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) > 0;
950
951 for (i = 0; i < widgets.document_buttons->len; i++)
952 {
953 GtkWidget *widget = g_ptr_array_index(widgets.document_buttons, i);
954 if (GTK_IS_ACTION(widget))
955 gtk_action_set_sensitive(GTK_ACTION(widget), enable);
956 else
957 ui_widget_set_sensitive(widget, enable);
958 }
959}
960
961
962static void on_doc_sensitive_widget_destroy(GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
963{
964 g_ptr_array_remove_fast(widgets.document_buttons, widget);
965}
966
967
968/** Adds a widget to the list of widgets that should be set sensitive/insensitive
969 * when some documents are present/no documents are open.
970 * It will be removed when the widget is destroyed.
971 * @param widget The widget to add.
972 *
973 * @since 0.15
974 **/
975GEANY_API_SYMBOL
976void ui_add_document_sensitive(GtkWidget *widget)
977{
978 gboolean enable = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) > 0;
979
980 ui_widget_set_sensitive(widget, enable);
981
982 g_ptr_array_add(widgets.document_buttons, widget);
983 g_signal_connect(widget, "destroy", G_CALLBACK(on_doc_sensitive_widget_destroy), NULL);
984}
985
986
987void ui_widget_show_hide(GtkWidget *widget, gboolean show)
988{
989 if (show)
990 {
991 gtk_widget_show(widget);
992 }
993 else
994 {
995 gtk_widget_hide(widget);
996 }
997}
998
999
1001{
1002 GtkWidget *widget;
1003
1004 /* check that there are no other notebook pages before hiding the sidebar completely
1005 * other pages could be e.g. the file browser plugin */
1007 gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.sidebar_notebook)) <= 2)
1008 {
1009 ui_prefs.sidebar_visible = FALSE;
1010 }
1011
1012 widget = ui_lookup_widget(main_widgets.window, "menu_show_sidebar1");
1013 if (ui_prefs.sidebar_visible != gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
1014 {
1015 ignore_callback = TRUE;
1016 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), ui_prefs.sidebar_visible);
1017 ignore_callback = FALSE;
1018 }
1019
1021
1022 ui_widget_show_hide(gtk_notebook_get_nth_page(
1024 ui_widget_show_hide(gtk_notebook_get_nth_page(
1026}
1027
1028
1030{
1031 const gchar *widget_name;
1032 GtkWidget *item;
1033 const GeanyIndentPrefs *iprefs;
1034
1035 g_return_if_fail(doc == NULL || doc->is_valid);
1036
1037 if (doc == NULL)
1038 doc = document_get_current();
1039
1040 if (doc == NULL)
1041 return;
1042
1043 ignore_callback = TRUE;
1044
1045 gtk_check_menu_item_set_active(
1046 GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_line_wrapping1")),
1047 doc->editor->line_wrapping);
1048
1049 gtk_check_menu_item_set_active(
1050 GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "line_breaking1")),
1051 doc->editor->line_breaking);
1052
1053 iprefs = editor_get_indent_prefs(doc->editor);
1054
1055 item = ui_lookup_widget(main_widgets.window, "menu_use_auto_indentation1");
1056 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), doc->editor->auto_indent);
1057
1058 switch (iprefs->type)
1059 {
1061 widget_name = "spaces1"; break;
1063 widget_name = "tabs1"; break;
1065 default:
1066 widget_name = "tabs_and_spaces1"; break;
1067 }
1068 item = ui_lookup_widget(main_widgets.window, widget_name);
1069 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1070
1071 if (iprefs->width >= 1 && iprefs->width <= 8)
1072 {
1073 gchar *name;
1074
1075 name = g_strdup_printf("indent_width_%d", iprefs->width);
1077 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
1078 g_free(name);
1079 }
1080
1081 gtk_check_menu_item_set_active(
1082 GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "set_file_readonly1")),
1083 doc->readonly);
1084
1085 item = ui_lookup_widget(main_widgets.window, "menu_write_unicode_bom1");
1086 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), doc->has_bom);
1088
1089 switch (sci_get_eol_mode(doc->editor->sci))
1090 {
1091 case SC_EOL_CR: widget_name = "cr"; break;
1092 case SC_EOL_LF: widget_name = "lf"; break;
1093 default: widget_name = "crlf"; break;
1094 }
1095 gtk_check_menu_item_set_active(
1096 GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, widget_name)), TRUE);
1097
1100
1101 ignore_callback = FALSE;
1102}
1103
1104
1105void ui_set_search_entry_background(GtkWidget *widget, gboolean success)
1106{
1107 gtk_widget_set_name(widget, success ? NULL : "geany-search-entry-no-match");
1108}
1109
1110
1112{
1113 guint i, len;
1114
1115 len = MIN(file_prefs.mru_length, g_queue_get_length(grf->recent_queue));
1116 for (i = 0; i < len; i++)
1117 {
1118 /* create menu item for the recent files menu in the menu bar */
1119 const gchar *filename = g_queue_peek_nth(grf->recent_queue, i);
1120 GtkWidget *tmp = gtk_menu_item_new_with_label(filename);
1121
1122 gtk_widget_show(tmp);
1123 gtk_container_add(GTK_CONTAINER(grf->menubar), tmp);
1124 g_signal_connect(tmp, "activate", G_CALLBACK(grf->activate_cb), NULL);
1125 /* create menu item for the recent files menu in the toolbar */
1126 if (grf->toolbar != NULL)
1127 {
1128 tmp = gtk_menu_item_new_with_label(filename);
1129 gtk_widget_show(tmp);
1130 gtk_container_add(GTK_CONTAINER(grf->toolbar), tmp);
1131 g_signal_connect(tmp, "activate", G_CALLBACK(grf->activate_cb), NULL);
1132 }
1133 }
1134}
1135
1136
1138{
1139 static GeanyRecentFiles grf = { RECENT_FILE_FILE, NULL, NULL, NULL, NULL };
1140
1141 if (G_UNLIKELY(grf.recent_queue == NULL))
1142 {
1143 grf.recent_queue = ui_prefs.recent_queue;
1144 grf.menubar = ui_widgets.recent_files_menu_menubar;
1148 }
1149 return &grf;
1150}
1151
1152
1154{
1156
1157 if (G_UNLIKELY(grf.recent_queue == NULL))
1158 {
1159 grf.recent_queue = ui_prefs.recent_projects_queue;
1160 grf.menubar = ui_widgets.recent_projects_menu_menubar;
1161 grf.toolbar = NULL;
1163 }
1164 return &grf;
1165}
1166
1167
1169{
1172}
1173
1174
1175static void recent_file_activate_cb(GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
1176{
1177 gchar *utf8_filename = ui_menu_item_get_text(menuitem);
1178 gchar *locale_filename = utils_get_locale_from_utf8(utf8_filename);
1179
1180 if (document_open_file(locale_filename, FALSE, NULL, NULL) != NULL)
1182
1183 g_free(locale_filename);
1184 g_free(utf8_filename);
1185}
1186
1187
1188static void recent_project_activate_cb(GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
1189{
1190 gchar *utf8_filename = ui_menu_item_get_text(menuitem);
1191 gchar *locale_filename = utils_get_locale_from_utf8(utf8_filename);
1192
1193 if (app->project && !project_close(FALSE)) {}
1194 else if (project_load_file_with_session(locale_filename))
1196
1197 g_free(locale_filename);
1198 g_free(utf8_filename);
1199}
1200
1201
1202static void add_recent_file(const gchar *utf8_filename, GeanyRecentFiles *grf,
1203 const GtkRecentData *rdata)
1204{
1205 if (g_queue_find_custom(grf->recent_queue, utf8_filename, (GCompareFunc) strcmp) == NULL)
1206 {
1207
1208 if (grf->type == RECENT_FILE_FILE && rdata)
1209 {
1210 GtkRecentManager *manager = gtk_recent_manager_get_default();
1211 gchar *uri = g_filename_to_uri(utf8_filename, NULL, NULL);
1212 if (uri != NULL)
1213 {
1214 gtk_recent_manager_add_full(manager, uri, rdata);
1215 g_free(uri);
1216 }
1217 }
1218
1219 g_queue_push_head(grf->recent_queue, g_strdup(utf8_filename));
1220 if (g_queue_get_length(grf->recent_queue) > file_prefs.mru_length)
1221 {
1222 g_free(g_queue_pop_tail(grf->recent_queue));
1223 }
1224 update_recent_menu(grf);
1225 }
1226 /* filename already in recent list */
1227 else
1228 recent_file_loaded(utf8_filename, grf);
1229}
1230
1231
1233{
1234 /* what are the groups for actually? */
1235 static const gchar *groups[2] = {
1236 "geany",
1237 NULL
1238 };
1239 GtkRecentData rdata;
1240
1241 /* Prepare the data for gtk_recent_manager_add_full() */
1242 rdata.display_name = NULL;
1243 rdata.description = NULL;
1244 rdata.mime_type = doc->file_type->mime_type;
1245 /* if we ain't got no mime-type, fallback to plain text */
1246 if (! rdata.mime_type)
1247 rdata.mime_type = (gchar *) "text/plain";
1248 rdata.app_name = (gchar *) "geany";
1249 rdata.app_exec = (gchar *) "geany %u";
1250 rdata.groups = (gchar **) groups;
1251 rdata.is_private = FALSE;
1252
1254}
1255
1256
1257void ui_add_recent_project_file(const gchar *utf8_filename)
1258{
1260}
1261
1262
1263/* Returns: newly allocated string with the UTF-8 menu text. */
1264gchar *ui_menu_item_get_text(GtkMenuItem *menu_item)
1265{
1266 const gchar *text = NULL;
1267
1268 if (gtk_bin_get_child(GTK_BIN(menu_item)))
1269 {
1270 GtkWidget *child = gtk_bin_get_child(GTK_BIN(menu_item));
1271
1272 if (GTK_IS_LABEL(child))
1273 text = gtk_label_get_text(GTK_LABEL(child));
1274 }
1275 /* GTK owns text so it's much safer to return a copy of it in case the memory is reallocated */
1276 return g_strdup(text);
1277}
1278
1279
1280static gint find_recent_file_item(gconstpointer list_data, gconstpointer user_data)
1281{
1282 gchar *menu_text = ui_menu_item_get_text(GTK_MENU_ITEM(list_data));
1283 gint result;
1284
1285 if (utils_str_equal(menu_text, user_data))
1286 result = 0;
1287 else
1288 result = 1;
1289
1290 g_free(menu_text);
1291 return result;
1292}
1293
1294
1295/* update the project menu item's sensitivity */
1297{
1299 GList *children, *item;
1300
1301 /* only need to update the menubar menu, the project doesn't have a toolbar item */
1302 children = gtk_container_get_children(GTK_CONTAINER(grf->menubar));
1303 for (item = children; item; item = item->next)
1304 {
1305 gboolean sensitive = TRUE;
1306
1307 if (app->project)
1308 {
1309 const gchar *filename = gtk_menu_item_get_label(item->data);
1310 sensitive = g_strcmp0(app->project->file_name, filename) != 0;
1311 }
1312 gtk_widget_set_sensitive(item->data, sensitive);
1313 }
1314 g_list_free(children);
1315}
1316
1317
1318/* Use instead of gtk_menu_reorder_child() to update the menubar properly on OS X */
1319static void menu_reorder_child(GtkMenu *menu, GtkWidget *child, gint position)
1320{
1321 gtk_menu_reorder_child(menu, child, position);
1322#ifdef MAC_INTEGRATION
1323 /* On OS X GtkMenuBar is kept in sync with the native OS X menubar using
1324 * signals. Unfortunately gtk_menu_reorder_child() doesn't emit anything
1325 * so we have to update the OS X menubar manually. */
1326 gtkosx_application_sync_menubar(gtkosx_application_get());
1327#endif
1328}
1329
1330
1331static void add_recent_file_menu_item(const gchar *utf8_filename, GeanyRecentFiles *grf, GtkWidget *menu)
1332{
1333 GtkWidget *child = gtk_menu_item_new_with_label(utf8_filename);
1334
1335 gtk_widget_show(child);
1336 if (menu != grf->toolbar)
1337 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), child);
1338 else
1339 {
1340 /* this is a bit ugly, but we need to use gtk_container_add(). Using
1341 * gtk_menu_shell_prepend() doesn't emit GtkContainer's "add" signal
1342 * which we need in GeanyMenubuttonAction */
1343 gtk_container_add(GTK_CONTAINER(menu), child);
1344 menu_reorder_child(GTK_MENU(menu), child, 0);
1345 }
1346 g_signal_connect(child, "activate", G_CALLBACK(grf->activate_cb), NULL);
1347}
1348
1349
1350static void recent_file_loaded(const gchar *utf8_filename, GeanyRecentFiles *grf)
1351{
1352 GList *item;
1353 GtkWidget *parents[] = { grf->menubar, grf->toolbar };
1354 guint i;
1355
1356 /* first reorder the queue */
1357 item = g_queue_find_custom(grf->recent_queue, utf8_filename, (GCompareFunc) strcmp);
1358 g_return_if_fail(item != NULL);
1359
1360 g_queue_unlink(grf->recent_queue, item);
1361 g_queue_push_head_link(grf->recent_queue, item);
1362
1363 for (i = 0; i < G_N_ELEMENTS(parents); i++)
1364 {
1365 GList *children;
1366
1367 if (! parents[i])
1368 continue;
1369
1370 children = gtk_container_get_children(GTK_CONTAINER(parents[i]));
1371 item = g_list_find_custom(children, utf8_filename, (GCompareFunc) find_recent_file_item);
1372 /* either reorder or prepend a new one */
1373 if (item)
1374 menu_reorder_child(GTK_MENU(parents[i]), item->data, 0);
1375 else
1376 add_recent_file_menu_item(utf8_filename, grf, parents[i]);
1377 g_list_free(children);
1378 }
1379
1380 if (grf->type == RECENT_FILE_PROJECT)
1382}
1383
1384
1386{
1387 gchar *filename;
1388 GtkWidget *parents[] = { grf->menubar, grf->toolbar };
1389 guint i;
1390
1391 filename = g_queue_peek_head(grf->recent_queue);
1392
1393 for (i = 0; i < G_N_ELEMENTS(parents); i++)
1394 {
1395 GList *children;
1396
1397 if (! parents[i])
1398 continue;
1399
1400 /* clean the MRU list before adding an item */
1401 children = gtk_container_get_children(GTK_CONTAINER(parents[i]));
1402 if (g_list_length(children) > file_prefs.mru_length - 1)
1403 {
1404 GList *item = g_list_nth(children, file_prefs.mru_length - 1);
1405 while (item != NULL)
1406 {
1407 if (GTK_IS_MENU_ITEM(item->data))
1408 gtk_widget_destroy(GTK_WIDGET(item->data));
1409 item = g_list_next(item);
1410 }
1411 }
1412 g_list_free(children);
1413
1414 /* create the new item */
1415 add_recent_file_menu_item(filename, grf, parents[i]);
1416 }
1417
1418 if (grf->type == RECENT_FILE_PROJECT)
1420}
1421
1422
1423void ui_toggle_editor_features(GeanyUIEditorFeatures feature)
1424{
1425 guint i;
1426
1428 {
1429 GeanyDocument *doc = documents[i];
1430
1431 switch (feature)
1432 {
1433 case GEANY_EDITOR_SHOW_MARKERS_MARGIN:
1435 break;
1436 case GEANY_EDITOR_SHOW_LINE_NUMBERS:
1438 break;
1439 case GEANY_EDITOR_SHOW_WHITE_SPACE:
1441 break;
1442 case GEANY_EDITOR_SHOW_LINE_ENDINGS:
1444 break;
1445 case GEANY_EDITOR_SHOW_INDENTATION_GUIDES:
1447 break;
1448 }
1449 }
1450}
1451
1452
1454{
1455 ignore_callback = TRUE;
1456 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_markers_margin1")), editor_prefs.show_markers_margin);
1457 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_linenumber_margin1")), editor_prefs.show_linenumber_margin);
1458 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_white_space1")), editor_prefs.show_white_space);
1459 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_line_endings1")), editor_prefs.show_line_endings);
1460 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_indentation_guides1")), editor_prefs.show_indent_guide);
1461 ignore_callback = FALSE;
1462}
1463
1464
1465/** Creates a GNOME HIG-style frame (with no border and indented child alignment).
1466 * @param label_text The label text.
1467 * @param alignment An address to store the alignment widget pointer.
1468 *
1469 * @return @transfer{floating} The frame widget, setting the alignment container for
1470 * packing child widgets.
1471 *
1472 * @deprecated 1.29: Use GTK API directly
1473 **/
1474GEANY_API_SYMBOL
1475GtkWidget *ui_frame_new_with_alignment(const gchar *label_text, GtkWidget **alignment)
1476{
1477 GtkWidget *label, *align;
1478 GtkWidget *frame = gtk_frame_new(NULL);
1479
1480 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
1481
1482 align = gtk_alignment_new(0.5, 0.5, 1, 1);
1483 gtk_container_add(GTK_CONTAINER(frame), align);
1484 gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
1485
1486 label = ui_label_new_bold(label_text);
1487 gtk_frame_set_label_widget(GTK_FRAME(frame), label);
1488
1489 *alignment = align;
1490 return frame;
1491}
1492
1493
1494/** Makes a fixed border for dialogs without increasing the button box border.
1495 * @param dialog The parent container for the @c GtkVBox.
1496 *
1497 * @return @transfer{none} The packed @c GtkVBox. */
1498GEANY_API_SYMBOL
1499GtkWidget *ui_dialog_vbox_new(GtkDialog *dialog)
1500{
1501 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); /* need child vbox to set a separate border. */
1502
1503 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
1504 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0);
1505 return vbox;
1506}
1507
1508
1509/* Reorders a dialog's buttons
1510 * @param dialog A dialog
1511 * @param response First response ID to reorder
1512 * @param ... more response IDs, terminated by -1
1513 *
1514 * Like gtk_dialog_set_alternative_button_order(), but reorders the default
1515 * buttons layout, not the alternative one. This is useful if you e.g. added a
1516 * button to a dialog which already had some and need yours not to be on the
1517 * end.
1518 */
1519/* Heavily based on gtk_dialog_set_alternative_button_order().
1520 * This relies on the action area to be a GtkBox, but although not documented
1521 * the API expose it to be a GtkHButtonBox though GtkBuilder, so it should be
1522 * fine */
1523void ui_dialog_set_primary_button_order(GtkDialog *dialog, gint response, ...)
1524{
1525 va_list ap;
1526 GtkWidget *action_area = gtk_dialog_get_action_area(dialog);
1527 gint position;
1528
1529 va_start(ap, response);
1530 for (position = 0; response != -1; position++)
1531 {
1532 GtkWidget *child = gtk_dialog_get_widget_for_response(dialog, response);
1533 if (child)
1534 gtk_box_reorder_child(GTK_BOX(action_area), child, position);
1535 else
1536 g_warning("%s: no child button with response id %d.", G_STRFUNC, response);
1537
1538 response = va_arg(ap, gint);
1539 }
1540 va_end(ap);
1541}
1542
1543
1544/** Creates a @c GtkButton with custom text and a stock image similar to
1545 * @c gtk_button_new_from_stock().
1546 * @param stock_id A @c GTK_STOCK_NAME string.
1547 * @param text Button label text, can include mnemonics.
1548 *
1549 * @return @transfer{floating} The new @c GtkButton.
1550 */
1551GEANY_API_SYMBOL
1552GtkWidget *ui_button_new_with_image(const gchar *stock_id, const gchar *text)
1553{
1554 GtkWidget *image, *button;
1555
1556 button = gtk_button_new_with_mnemonic(text);
1557 gtk_widget_show(button);
1558 image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON);
1559 gtk_button_set_image(GTK_BUTTON(button), image);
1560 /* note: image is shown by gtk */
1561 return button;
1562}
1563
1564
1565/** Creates a @c GtkImageMenuItem with a stock image and a custom label.
1566 * @param stock_id Stock image ID, e.g. @c GTK_STOCK_OPEN.
1567 * @param label Menu item label, can include mnemonics.
1568 * @return @transfer{floating} The new @c GtkImageMenuItem.
1569 *
1570 * @since 0.16
1571 */
1572GEANY_API_SYMBOL
1573GtkWidget *
1574ui_image_menu_item_new(const gchar *stock_id, const gchar *label)
1575{
1576 GtkWidget *item = gtk_image_menu_item_new_with_mnemonic(label);
1577 GtkWidget *image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU);
1578
1579 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1580 gtk_widget_show(image);
1581 return item;
1582}
1583
1584
1585static void entry_clear_icon_release_cb(GtkEntry *entry, gint icon_pos,
1586 GdkEvent *event, gpointer data)
1587{
1588 if (event->button.button == 1 && icon_pos == 1)
1589 {
1590 gtk_entry_set_text(entry, "");
1591 gtk_widget_grab_focus(GTK_WIDGET(entry));
1592 }
1593}
1594
1595
1596/** Adds a small clear icon to the right end of the passed @a entry.
1597 * A callback to clear the contents of the GtkEntry is automatically added.
1598 *
1599 * @param entry The GtkEntry object to which the icon should be attached.
1600 *
1601 * @since 0.16
1602 */
1603GEANY_API_SYMBOL
1605{
1606 g_object_set(entry, "secondary-icon-stock", GTK_STOCK_CLEAR,
1607 "secondary-icon-activatable", TRUE, NULL);
1608 g_signal_connect(entry, "icon-release", G_CALLBACK(entry_clear_icon_release_cb), NULL);
1609}
1610
1611
1612/* Adds a :activate-backwards signal emitted by default when <Shift>Return is pressed */
1614{
1615 static gboolean installed = FALSE;
1616
1617 g_return_if_fail(GTK_IS_ENTRY(entry));
1618
1619 if (G_UNLIKELY(! installed))
1620 {
1621 GtkBindingSet *binding_set;
1622
1623 installed = TRUE;
1624
1625 /* try to handle the unexpected case where GTK would already have installed the signal */
1626 if (g_signal_lookup("activate-backward", G_TYPE_FROM_INSTANCE(entry)))
1627 {
1628 g_warning("Signal GtkEntry:activate-backward is unexpectedly already installed");
1629 return;
1630 }
1631
1632 g_signal_new("activate-backward", G_TYPE_FROM_INSTANCE(entry),
1633 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, 0, NULL, NULL,
1634 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1635 binding_set = gtk_binding_set_by_class(GTK_ENTRY_GET_CLASS(entry));
1636 gtk_binding_entry_add_signal(binding_set, GDK_KEY_Return, GDK_SHIFT_MASK, "activate-backward", 0);
1637 }
1638}
1639
1640
1641static void add_to_size_group(GtkWidget *widget, gpointer size_group)
1642{
1643 g_return_if_fail(GTK_IS_SIZE_GROUP(size_group));
1644 gtk_size_group_add_widget(GTK_SIZE_GROUP(size_group), widget);
1645}
1646
1647
1648/* Copies the spacing and layout of the master GtkHButtonBox and synchronises
1649 * the width of each button box's children.
1650 * Should be called after all child widgets have been packed. */
1651void ui_hbutton_box_copy_layout(GtkButtonBox *master, GtkButtonBox *copy)
1652{
1653 GtkSizeGroup *size_group;
1654
1655 gtk_box_set_spacing(GTK_BOX(copy), 10);
1656 gtk_button_box_set_layout(copy, gtk_button_box_get_layout(master));
1657
1658 /* now we need to put the widest widget from each button box in a size group,
1659 * but we don't know the width before they are drawn, and for different label
1660 * translations the widest widget can vary, so we just add all widgets. */
1661 size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1662 gtk_container_foreach(GTK_CONTAINER(master), add_to_size_group, size_group);
1663 gtk_container_foreach(GTK_CONTAINER(copy), add_to_size_group, size_group);
1664 g_object_unref(size_group);
1665}
1666
1667
1668static gboolean tree_model_find_text(GtkTreeModel *model,
1669 GtkTreeIter *iter, gint column, const gchar *text)
1670{
1671 gchar *combo_text;
1672 gboolean found = FALSE;
1673
1674 if (gtk_tree_model_get_iter_first(model, iter))
1675 {
1676 do
1677 {
1678 gtk_tree_model_get(model, iter, 0, &combo_text, -1);
1679 found = utils_str_equal(combo_text, text);
1680 g_free(combo_text);
1681
1682 if (found)
1683 return TRUE;
1684 }
1685 while (gtk_tree_model_iter_next(model, iter));
1686 }
1687 return FALSE;
1688}
1689
1690
1691/** Prepends @a text to the drop down list, removing a duplicate element in
1692 * the list if found. Also ensures there are <= @a history_len elements.
1693 * @param combo_entry .
1694 * @param text @nullable Text to add, or @c NULL for current entry text.
1695 * @param history_len Max number of items, or @c 0 for default. */
1696GEANY_API_SYMBOL
1697void ui_combo_box_add_to_history(GtkComboBoxText *combo_entry,
1698 const gchar *text, gint history_len)
1699{
1700 GtkComboBox *combo = GTK_COMBO_BOX(combo_entry);
1701 GtkTreeModel *model;
1702 GtkTreeIter iter;
1703 GtkTreePath *path;
1704
1705 if (history_len <= 0)
1706 history_len = 10;
1707 if (!text)
1708 text = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo))));
1709
1710 model = gtk_combo_box_get_model(combo);
1711
1712 if (tree_model_find_text(model, &iter, 0, text))
1713 {
1714 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1715 }
1716 gtk_combo_box_text_prepend_text(combo_entry, text);
1717
1718 /* limit history */
1719 path = gtk_tree_path_new_from_indices(history_len, -1);
1720 if (gtk_tree_model_get_iter(model, &iter, path))
1721 {
1722 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1723 }
1724 gtk_tree_path_free(path);
1725}
1726
1727
1728/* Same as gtk_combo_box_text_prepend_text(), except that text is only prepended if it not already
1729 * exists in the combo's model. */
1730void ui_combo_box_prepend_text_once(GtkComboBoxText *combo, const gchar *text)
1731{
1732 GtkTreeModel *model;
1733 GtkTreeIter iter;
1734
1735 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
1736 if (tree_model_find_text(model, &iter, 0, text))
1737 return; /* don't prepend duplicate */
1738
1739 gtk_combo_box_text_prepend_text(combo, text);
1740}
1741
1742
1743/* Changes the color of the notebook tab text and open files items according to
1744 * document status. */
1746{
1747 gtk_widget_set_name(doc->priv->tab_label, document_get_status_widget_class(doc));
1748
1750}
1751
1752
1753static gboolean tree_model_iter_get_next(GtkTreeModel *model, GtkTreeIter *iter,
1754 gboolean down)
1755{
1756 GtkTreePath *path;
1757 gboolean result;
1758
1759 if (down)
1760 return gtk_tree_model_iter_next(model, iter);
1761
1762 path = gtk_tree_model_get_path(model, iter);
1763 result = gtk_tree_path_prev(path) && gtk_tree_model_get_iter(model, iter, path);
1764 gtk_tree_path_free(path);
1765 return result;
1766}
1767
1768
1769/* note: the while loop might be more efficient when searching upwards if it
1770 * used tree paths instead of tree iters, but in practice it probably doesn't matter much. */
1771static gboolean tree_view_find(GtkTreeView *treeview, TVMatchCallback cb, gboolean down)
1772{
1773 GtkTreeSelection *treesel;
1774 GtkTreeIter iter;
1775 GtkTreeModel *model;
1776
1777 treesel = gtk_tree_view_get_selection(treeview);
1778 if (gtk_tree_selection_get_selected(treesel, &model, &iter))
1779 {
1780 /* get the next selected item */
1781 if (! tree_model_iter_get_next(model, &iter, down))
1782 return FALSE; /* no more items */
1783 }
1784 else /* no selection */
1785 {
1786 if (! gtk_tree_model_get_iter_first(model, &iter))
1787 return TRUE; /* no items */
1788 }
1789 while (TRUE)
1790 {
1791 gtk_tree_selection_select_iter(treesel, &iter);
1792 if (cb(FALSE))
1793 break; /* found next message */
1794
1795 if (! tree_model_iter_get_next(model, &iter, down))
1796 return FALSE; /* no more items */
1797 }
1798 /* scroll item in view */
1799 if (ui_prefs.msgwindow_visible)
1800 {
1801 GtkTreePath *path = gtk_tree_model_get_path(
1802 gtk_tree_view_get_model(treeview), &iter);
1803
1804 gtk_tree_view_scroll_to_cell(treeview, path, NULL, TRUE, 0.5, 0.5);
1805 gtk_tree_path_free(path);
1806 }
1807 return TRUE;
1808}
1809
1810
1811/* Returns FALSE if the treeview has items but no matching next item. */
1812gboolean ui_tree_view_find_next(GtkTreeView *treeview, TVMatchCallback cb)
1813{
1814 return tree_view_find(treeview, cb, TRUE);
1815}
1816
1817
1818/* Returns FALSE if the treeview has items but no matching next item. */
1819gboolean ui_tree_view_find_previous(GtkTreeView *treeview, TVMatchCallback cb)
1820{
1821 return tree_view_find(treeview, cb, FALSE);
1822}
1823
1824
1825/* Shamelessly stolen from GTK */
1826static gboolean ui_tree_view_query_tooltip_cb(GtkWidget *widget, gint x, gint y,
1827 gboolean keyboard_tip, GtkTooltip *tooltip, gpointer data)
1828{
1829 GValue value = { 0 };
1830 GValue transformed = { 0 };
1831 GtkTreeIter iter;
1832 GtkTreePath *path;
1833 GtkTreeModel *model;
1834 GtkTreeView *tree_view = GTK_TREE_VIEW(widget);
1835 gint column = GPOINTER_TO_INT(data);
1836 gboolean tootlip_set = FALSE;
1837
1838 if (! gtk_tree_view_get_tooltip_context(tree_view, &x, &y, keyboard_tip, &model, &path, &iter))
1839 return FALSE;
1840
1841 gtk_tree_model_get_value(model, &iter, column, &value);
1842
1843 g_value_init(&transformed, G_TYPE_STRING);
1844 if (g_value_transform(&value, &transformed) && g_value_get_string(&transformed))
1845 {
1846 gtk_tooltip_set_text(tooltip, g_value_get_string(&transformed));
1847 gtk_tree_view_set_tooltip_row(tree_view, tooltip, path);
1848 tootlip_set = TRUE;
1849 }
1850
1851 g_value_unset(&transformed);
1852 g_value_unset(&value);
1853 gtk_tree_path_free(path);
1854
1855 return tootlip_set;
1856}
1857
1858
1859/** Adds text tooltips to a tree view.
1860 *
1861 * This is similar to gtk_tree_view_set_tooltip_column() but considers the column contents to be
1862 * text, not markup -- it uses gtk_tooltip_set_text() rather than gtk_tooltip_set_markup() to set
1863 * the tooltip's value.
1864 *
1865 * @warning Unlike gtk_tree_view_set_tooltip_column() you currently cannot change or remove the
1866 * tooltip column after it has been added. Trying to do so will probably give funky results.
1867 *
1868 * @param tree_view The tree view
1869 * @param column The column to get the tooltip from
1870 *
1871 * @since 1.25 (API 223)
1872 */
1873/* Note: @p column is int and not uint both to match gtk_tree_view_set_tooltip_column() signature
1874 * and to allow future support of -1 to unset if ever wanted */
1875GEANY_API_SYMBOL
1876void ui_tree_view_set_tooltip_text_column(GtkTreeView *tree_view, gint column)
1877{
1878 g_return_if_fail(column >= 0);
1879 g_return_if_fail(GTK_IS_TREE_VIEW(tree_view));
1880
1881 g_signal_connect(tree_view, "query-tooltip",
1882 G_CALLBACK(ui_tree_view_query_tooltip_cb), GINT_TO_POINTER(column));
1883 gtk_widget_set_has_tooltip(GTK_WIDGET(tree_view), TRUE);
1884}
1885
1886
1887/**
1888 * Modifies the font of a widget using gtk_widget_modify_font().
1889 *
1890 * @param widget The widget.
1891 * @param str The font name as expected by pango_font_description_from_string().
1892 */
1893GEANY_API_SYMBOL
1894void ui_widget_modify_font_from_string(GtkWidget *widget, const gchar *str)
1895{
1896 PangoFontDescription *pfd;
1897
1898 pfd = pango_font_description_from_string(str);
1899 gtk_widget_modify_font(widget, pfd);
1900 pango_font_description_free(pfd);
1901}
1902
1903
1904/** Creates a @c GtkHBox with @a entry packed into it and an open button which runs a
1905 * file chooser, replacing entry text (if successful) with the path returned from the
1906 * @c GtkFileChooser.
1907 * @note @a entry can be the child of an unparented widget, such as @c GtkComboBoxEntry.
1908 * @param title @nullable The file chooser dialog title, or @c NULL.
1909 * @param action The mode of the file chooser.
1910 * @param entry Can be an unpacked @c GtkEntry, or the child of an unpacked widget,
1911 * such as @c GtkComboBoxEntry.
1912 *
1913 * @return @transfer{floating} The @c GtkHBox.
1914 */
1915/* @see ui_setup_open_button_callback(). */
1916GEANY_API_SYMBOL
1917GtkWidget *ui_path_box_new(const gchar *title, GtkFileChooserAction action, GtkEntry *entry)
1918{
1919 GtkWidget *vbox, *dirbtn, *openimg, *hbox, *path_entry, *parent, *next_parent;
1920
1921 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
1922 path_entry = GTK_WIDGET(entry);
1923
1924 /* prevent path_entry being vertically stretched to the height of dirbtn */
1925 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1926
1927 parent = path_entry;
1928 while ((next_parent = gtk_widget_get_parent(parent)) != NULL)
1929 parent = next_parent;
1930
1931 gtk_box_pack_start(GTK_BOX(vbox), parent, TRUE, FALSE, 0);
1932
1933 dirbtn = gtk_button_new();
1934 openimg = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
1935 gtk_container_add(GTK_CONTAINER(dirbtn), openimg);
1936 ui_setup_open_button_callback(dirbtn, title, action, entry);
1937
1938 gtk_box_pack_end(GTK_BOX(hbox), dirbtn, FALSE, FALSE, 0);
1939 gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1940 return hbox;
1941}
1942
1943
1944static void ui_path_box_open_clicked(GtkButton *button, gpointer user_data);
1945
1946
1947/* Setup a GtkButton to run a GtkFileChooser, setting entry text if successful.
1948 * title can be NULL.
1949 * action is the file chooser mode to use. */
1950void ui_setup_open_button_callback(GtkWidget *open_btn, const gchar *title,
1951 GtkFileChooserAction action, GtkEntry *entry)
1952{
1953 GtkWidget *path_entry = GTK_WIDGET(entry);
1954
1955 if (title)
1956 g_object_set_data_full(G_OBJECT(open_btn), "title", g_strdup(title),
1957 (GDestroyNotify) g_free);
1958 g_object_set_data(G_OBJECT(open_btn), "action", GINT_TO_POINTER(action));
1959 g_signal_connect(open_btn, "clicked", G_CALLBACK(ui_path_box_open_clicked), path_entry);
1960}
1961
1962
1963#ifndef G_OS_WIN32
1964static gchar *run_file_chooser(const gchar *title, GtkFileChooserAction action,
1965 const gchar *utf8_path)
1966{
1967 GtkWidget *dialog = gtk_file_chooser_dialog_new(title,
1968 GTK_WINDOW(main_widgets.window), action,
1969 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1970 GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
1971 gchar *locale_path;
1972 gchar *ret_path = NULL;
1973
1974 gtk_widget_set_name(dialog, "GeanyDialog");
1975 locale_path = utils_get_locale_from_utf8(utf8_path);
1976 if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
1977 {
1978 if (g_path_is_absolute(locale_path) && g_file_test(locale_path, G_FILE_TEST_IS_DIR))
1979 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), locale_path);
1980 }
1981 else if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
1982 {
1983 if (g_path_is_absolute(locale_path))
1984 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), locale_path);
1985 }
1986 g_free(locale_path);
1987
1988 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1989 {
1990 gchar *dir_locale;
1991
1992 dir_locale = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
1993 ret_path = utils_get_utf8_from_locale(dir_locale);
1994 g_free(dir_locale);
1995 }
1996 gtk_widget_destroy(dialog);
1997 return ret_path;
1998}
1999#endif
2000
2001
2002static void ui_path_box_open_clicked(GtkButton *button, gpointer user_data)
2003{
2004 GtkFileChooserAction action = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "action"));
2005 GtkEntry *entry = user_data;
2006 const gchar *title = g_object_get_data(G_OBJECT(button), "title");
2007 gchar *utf8_path = NULL;
2008
2009 /* TODO: extend for other actions */
2010 g_return_if_fail(action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
2011 action == GTK_FILE_CHOOSER_ACTION_OPEN);
2012
2013 if (title == NULL)
2014 title = (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ?
2015 _("Select Folder") : _("Select File");
2016
2017 if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
2018 {
2019#ifdef G_OS_WIN32
2020 utf8_path = win32_show_file_dialog(GTK_WINDOW(ui_widgets.prefs_dialog), title,
2021 gtk_entry_get_text(GTK_ENTRY(entry)));
2022#else
2023 utf8_path = run_file_chooser(title, action, gtk_entry_get_text(GTK_ENTRY(entry)));
2024#endif
2025 }
2026 else if (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
2027 {
2028 gchar *path = g_path_get_dirname(gtk_entry_get_text(GTK_ENTRY(entry)));
2029#ifdef G_OS_WIN32
2030 utf8_path = win32_show_folder_dialog(ui_widgets.prefs_dialog, title,
2031 gtk_entry_get_text(GTK_ENTRY(entry)));
2032#else
2033 utf8_path = run_file_chooser(title, action, path);
2034#endif
2035 g_free(path);
2036 }
2037
2038 if (utf8_path != NULL)
2039 {
2040 gtk_entry_set_text(GTK_ENTRY(entry), utf8_path);
2041 g_free(utf8_path);
2042 }
2043}
2044
2045
2046void ui_statusbar_showhide(gboolean state)
2047{
2048 /* handle statusbar visibility */
2049 if (state)
2050 {
2051 gtk_widget_show(ui_widgets.statusbar);
2053 }
2054 else
2055 gtk_widget_hide(ui_widgets.statusbar);
2056}
2057
2058
2059/** Packs all @c GtkWidgets passed after the row argument into a table, using
2060 * one widget per cell. The first widget is not expanded as the table grows,
2061 * as this is usually a label.
2062 * @param table
2063 * @param row The row number of the table.
2064 */
2065GEANY_API_SYMBOL
2066void ui_table_add_row(GtkTable *table, gint row, ...)
2067{
2068 va_list args;
2069 guint i;
2070 GtkWidget *widget;
2071
2072 va_start(args, row);
2073 for (i = 0; (widget = va_arg(args, GtkWidget*), widget != NULL); i++)
2074 {
2075 gint options = (i == 0) ? GTK_FILL : GTK_EXPAND | GTK_FILL;
2076
2077 gtk_table_attach(GTK_TABLE(table), widget, i, i + 1, row, row + 1,
2078 options, 0, 0, 0);
2079 }
2080 va_end(args);
2081}
2082
2083
2084static void on_config_file_clicked(GtkWidget *widget, gpointer user_data)
2085{
2086 const gchar *file_name = user_data;
2087 GeanyFiletype *ft = NULL;
2088
2089 if (strstr(file_name, G_DIR_SEPARATOR_S "filetypes."))
2091
2092 if (g_file_test(file_name, G_FILE_TEST_EXISTS))
2093 document_open_file(file_name, FALSE, ft, NULL);
2094 else
2095 {
2096 gchar *utf8_filename = utils_get_utf8_from_locale(file_name);
2097 gchar *global_file;
2098 gchar *base_name = NULL;
2099 gchar *global_content = NULL;
2100 GeanyDocument *doc = NULL;
2101
2102 /* get the path inside app->configdir - can contain subdirectories */
2103 if (g_str_has_prefix(file_name, app->configdir))
2104 {
2105 gsize len = strlen(app->configdir);
2106 if (file_name[len] == G_DIR_SEPARATOR)
2107 base_name = g_strdup(file_name + len + 1);
2108 }
2109
2110 if (!base_name)
2111 base_name = g_path_get_basename(file_name);
2112
2113 global_file = g_build_filename(app->datadir, base_name, NULL);
2114
2115 /* if the requested file doesn't exist in the user's config dir, try loading the file
2116 * from the global data directory and use its contents for the newly created file */
2117 if (g_file_test(global_file, G_FILE_TEST_EXISTS))
2118 g_file_get_contents(global_file, &global_content, NULL, NULL);
2119
2120 doc = document_new_file(utf8_filename, ft, global_content);
2121 if (global_content)
2122 {
2123 sci_select_all(doc->editor->sci);
2127 document_set_text_changed(doc, FALSE);
2129 ui_document_show_hide(doc); /* update the document menu */
2130 }
2131 utils_free_pointers(4, utf8_filename, base_name, global_file, global_content, NULL);
2132 }
2133}
2134
2135
2136static void free_on_closure_notify(gpointer data, GClosure *closure)
2137{
2138 g_free(data);
2139}
2140
2141
2142/* @note You should connect to the "document-save" signal yourself to detect
2143 * if the user has just saved the config file, reloading it. */
2144void ui_add_config_file_menu_item(const gchar *real_path, const gchar *label, GtkContainer *parent)
2145{
2146 GtkWidget *item;
2147
2148 if (!parent)
2149 parent = GTK_CONTAINER(widgets.config_files_menu);
2150
2151 if (!label)
2152 {
2153 gchar *base_name;
2154
2155 base_name = g_path_get_basename(real_path);
2156 item = gtk_menu_item_new_with_label(base_name);
2157 g_free(base_name);
2158 }
2159 else
2160 item = gtk_menu_item_new_with_mnemonic(label);
2161
2162 gtk_widget_show(item);
2163 gtk_container_add(parent, item);
2164 g_signal_connect_data(item, "activate", G_CALLBACK(on_config_file_clicked),
2165 g_strdup(real_path), free_on_closure_notify, 0);
2166}
2167
2168
2169static gboolean sort_menu(gpointer data)
2170{
2171 ui_menu_sort_by_label(GTK_MENU(data));
2172 return FALSE;
2173}
2174
2175
2177{
2178 GtkWidget *menu, *item;
2179
2180 widgets.config_files_menu = menu = gtk_menu_new();
2181
2182 item = ui_lookup_widget(main_widgets.window, "configuration_files1");
2183 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
2184
2185 item = gtk_menu_item_new_with_mnemonic(_("_Filetype Configuration"));
2186 gtk_container_add(GTK_CONTAINER(menu), item);
2187 ui_widgets.config_files_filetype_menu = gtk_menu_new();
2188 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), ui_widgets.config_files_filetype_menu);
2189 gtk_widget_show(item);
2190
2191 /* sort menu after all items added */
2192 g_idle_add(sort_menu, widgets.config_files_menu);
2193}
2194
2195
2196/* adds factory icons with a named icon source using the stock items id */
2197static void add_stock_icons(const GtkStockItem *items, gsize count)
2198{
2199 GtkIconFactory *factory = gtk_icon_factory_new();
2200 GtkIconSource *source = gtk_icon_source_new();
2201 gsize i;
2202
2203 for (i = 0; i < count; i++)
2204 {
2205 GtkIconSet *set = gtk_icon_set_new();
2206
2207 gtk_icon_source_set_icon_name(source, items[i].stock_id);
2208 gtk_icon_set_add_source(set, source);
2209 gtk_icon_factory_add(factory, items[i].stock_id, set);
2210 gtk_icon_set_unref(set);
2211 }
2212 gtk_icon_source_free(source);
2213 gtk_icon_factory_add_default(factory);
2214 g_object_unref(factory);
2215}
2216
2217
2219{
2220 GtkStockItem items[] =
2221 {
2222 { GEANY_STOCK_SAVE_ALL, N_("Save All"), 0, 0, GETTEXT_PACKAGE },
2223 { GEANY_STOCK_CLOSE_ALL, N_("Close All"), 0, 0, GETTEXT_PACKAGE },
2224 { GEANY_STOCK_BUILD, N_("Build"), 0, 0, GETTEXT_PACKAGE }
2225 };
2226
2227 gtk_stock_add(items, G_N_ELEMENTS(items));
2228 add_stock_icons(items, G_N_ELEMENTS(items));
2229}
2230
2231
2233{
2234 widgets.save_buttons[1] = toolbar_get_widget_by_name("Save");
2235 widgets.save_buttons[3] = toolbar_get_widget_by_name("SaveAll");
2236 widgets.redo_items[2] = toolbar_get_widget_by_name("Redo");
2237 widgets.undo_items[2] = toolbar_get_widget_by_name("Undo");
2238}
2239
2240
2242{
2243 GtkWidget *pane = ui_lookup_widget(main_widgets.window, "hpaned1");
2244 GtkWidget *left = gtk_paned_get_child1(GTK_PANED(pane));
2245 GtkWidget *right = gtk_paned_get_child2(GTK_PANED(pane));
2246
2247 g_object_ref(left);
2248 g_object_ref(right);
2249 gtk_container_remove (GTK_CONTAINER (pane), left);
2250 gtk_container_remove (GTK_CONTAINER (pane), right);
2251 /* only scintilla notebook should expand */
2252 gtk_paned_pack1(GTK_PANED(pane), right, right == main_widgets.notebook, TRUE);
2253 gtk_paned_pack2(GTK_PANED(pane), left, left == main_widgets.notebook, TRUE);
2254 g_object_unref(left);
2255 g_object_unref(right);
2256
2257 gtk_paned_set_position(GTK_PANED(pane), gtk_widget_get_allocated_width(pane)
2258 - gtk_paned_get_position(GTK_PANED(pane)));
2259}
2260
2261
2262static void init_recent_files(void)
2263{
2264 GtkWidget *toolbar_recent_files_menu;
2265
2266 /* add recent files to the File menu */
2267 ui_widgets.recent_files_menuitem = ui_lookup_widget(main_widgets.window, "recent_files1");
2268 ui_widgets.recent_files_menu_menubar = gtk_menu_new();
2269 gtk_menu_item_set_submenu(GTK_MENU_ITEM(ui_widgets.recent_files_menuitem),
2270 ui_widgets.recent_files_menu_menubar);
2271
2272 /* add recent files to the toolbar Open button */
2273 toolbar_recent_files_menu = gtk_menu_new();
2274 g_object_ref(toolbar_recent_files_menu);
2276 toolbar_get_action_by_name("Open")), toolbar_recent_files_menu);
2277}
2278
2279
2280static void ui_menu_move(GtkWidget *menu, GtkWidget *old, GtkWidget *new)
2281{
2282 g_object_ref(menu);
2283 gtk_menu_item_set_submenu(GTK_MENU_ITEM(old), NULL);
2284 gtk_menu_item_set_submenu(GTK_MENU_ITEM(new), menu);
2285 g_object_unref(menu);
2286}
2287
2288
2289typedef struct GeanySharedMenu
2290{
2291 const gchar *menu;
2292 const gchar *menubar_item;
2293 const gchar *popup_item;
2294}
2296
2297#define foreach_menu(item, array) \
2298 for (item = array; item->menu; item++)
2299
2300static void on_editor_menu_show(GtkWidget *widget, GeanySharedMenu *items)
2301{
2302 GeanySharedMenu *item;
2303
2304 foreach_menu(item, items)
2305 {
2306 GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, item->popup_item);
2307 GtkWidget *bar = ui_lookup_widget(main_widgets.window, item->menubar_item);
2308 GtkWidget *menu = ui_lookup_widget(main_widgets.window, item->menu);
2309
2310 ui_menu_move(menu, bar, popup);
2311 }
2312}
2313
2314
2315static void on_editor_menu_hide(GtkWidget *widget, GeanySharedMenu *items)
2316{
2317 GeanySharedMenu *item;
2318
2319 foreach_menu(item, items)
2320 {
2321 GtkWidget *popup = ui_lookup_widget(main_widgets.editor_menu, item->popup_item);
2322 GtkWidget *bar = ui_lookup_widget(main_widgets.window, item->menubar_item);
2323 GtkWidget *menu = ui_lookup_widget(main_widgets.window, item->menu);
2324
2325 ui_menu_move(menu, popup, bar);
2326 }
2327}
2328
2329
2330/* Currently ui_init() is called before keyfile.c stash group code is initialized,
2331 * so this is called after that's done. */
2333{
2334 StashGroup *group = stash_group_new(PACKAGE);
2335
2336 /* various prefs */
2338
2340 "show_symbol_list_expanders", TRUE);
2342 "compiler_tab_autoscroll", TRUE);
2343 stash_group_add_string(group, &ui_prefs.statusbar_template,
2344 "statusbar_template", _(DEFAULT_STATUSBAR_TEMPLATE));
2345 stash_group_add_boolean(group, &ui_prefs.new_document_after_close,
2346 "new_document_after_close", FALSE);
2348 "msgwin_status_visible", TRUE);
2350 "msgwin_compiler_visible", TRUE);
2352 "msgwin_messages_visible", TRUE);
2354 "msgwin_scribble_visible", TRUE);
2355}
2356
2357
2358/* Used to find out the name of the GtkBuilder retrieved object since
2359 * some objects will be GTK_IS_BUILDABLE() and use the GtkBuildable
2360 * 'name' property for that and those that don't implement GtkBuildable
2361 * will have a "gtk-builder-name" stored in the GObject's data list. */
2362static const gchar *ui_guess_object_name(GObject *obj)
2363{
2364 const gchar *name = NULL;
2365
2366 g_return_val_if_fail(G_IS_OBJECT(obj), NULL);
2367
2368 if (GTK_IS_BUILDABLE(obj))
2369 name = gtk_buildable_get_name(GTK_BUILDABLE(obj));
2370 if (! name)
2371 name = g_object_get_data(obj, "gtk-builder-name");
2372 if (! name)
2373 return NULL;
2374
2375 return name;
2376}
2377
2378
2379/* Compatibility functions */
2380GtkWidget *create_edit_menu1(void)
2381{
2382 return edit_menu1;
2383}
2384
2385
2386GtkWidget *create_prefs_dialog(void)
2387{
2388 return prefs_dialog;
2389}
2390
2391
2393{
2394 return project_dialog;
2395}
2396
2397
2399{
2400 return toolbar_popup_menu1;
2401}
2402
2403
2404GtkWidget *create_window1(void)
2405{
2406 return window1;
2407}
2408
2409
2410static GtkWidget *ui_get_top_parent(GtkWidget *widget)
2411{
2412 GtkWidget *parent;
2413
2414 g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
2415
2416 for (;;)
2417 {
2418 if (GTK_IS_MENU(widget))
2419 parent = gtk_menu_get_attach_widget(GTK_MENU(widget));
2420 else
2421 parent = gtk_widget_get_parent(widget);
2422 if (parent == NULL)
2423 parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey");
2424 if (parent == NULL)
2425 break;
2426 widget = parent;
2427 }
2428
2429 return widget;
2430}
2431
2432
2434{
2435 gchar *interface_file;
2436 const gchar *name;
2437 GError *error;
2438 GSList *iter, *all_objects;
2439 GtkWidget *widget, *toplevel;
2440
2441 /* prevent function from being called twice */
2442 if (GTK_IS_BUILDER(builder))
2443 return;
2444
2445 builder = gtk_builder_new();
2446
2447 gtk_builder_set_translation_domain(builder, GETTEXT_PACKAGE);
2448
2449 error = NULL;
2450 interface_file = g_build_filename(app->datadir, "geany.glade", NULL);
2451 if (! gtk_builder_add_from_file(builder, interface_file, &error))
2452 {
2453 /* Show the user this message so they know WTF happened */
2454 dialogs_show_msgbox_with_secondary(GTK_MESSAGE_ERROR,
2455 _("Geany cannot start!"), error->message);
2456 /* Aborts */
2457 g_error("Cannot create user-interface: %s", error->message);
2458 g_error_free(error);
2459 g_free(interface_file);
2460 g_object_unref(builder);
2461 return;
2462 }
2463 g_free(interface_file);
2464
2466
2467 edit_menu1 = GTK_WIDGET(gtk_builder_get_object(builder, "edit_menu1"));
2468 prefs_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "prefs_dialog"));
2469 project_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "project_dialog"));
2470 toolbar_popup_menu1 = GTK_WIDGET(gtk_builder_get_object(builder, "toolbar_popup_menu1"));
2471 window1 = GTK_WIDGET(gtk_builder_get_object(builder, "window1"));
2472
2473 g_object_set_data(G_OBJECT(edit_menu1), "edit_menu1", edit_menu1);
2474 g_object_set_data(G_OBJECT(prefs_dialog), "prefs_dialog", prefs_dialog);
2475 g_object_set_data(G_OBJECT(project_dialog), "project_dialog", project_dialog);
2476 g_object_set_data(G_OBJECT(toolbar_popup_menu1), "toolbar_popup_menu1", toolbar_popup_menu1);
2477 g_object_set_data(G_OBJECT(window1), "window1", window1);
2478
2479 all_objects = gtk_builder_get_objects(builder);
2480 for (iter = all_objects; iter != NULL; iter = g_slist_next(iter))
2481 {
2482 if (! GTK_IS_WIDGET(iter->data))
2483 continue;
2484
2485 widget = GTK_WIDGET(iter->data);
2486
2487 name = ui_guess_object_name(G_OBJECT(widget));
2488 if (! name)
2489 {
2490 g_warning("Unable to get name from GtkBuilder object");
2491 continue;
2492 }
2493 else
2494 {
2495 /* Set a default name for use from CSS by name */
2496 gtk_widget_set_name(widget, name);
2497 }
2498
2499 toplevel = ui_get_top_parent(widget);
2500 if (toplevel)
2501 ui_hookup_widget(toplevel, widget, name);
2502 }
2503 g_slist_free(all_objects);
2504}
2505
2506
2507static void load_css_theme(const gchar *fn, guint priority)
2508{
2509 GtkCssProvider *provider = gtk_css_provider_new();
2510 GError *error = NULL;
2511
2512 if (! gtk_css_provider_load_from_path(provider, fn, &error))
2513 {
2514 g_warning("Failed to load custom CSS: %s", error->message);
2515 g_error_free(error);
2516 return;
2517 }
2518
2519 gtk_style_context_add_provider_for_screen(gdk_screen_get_default(),
2520 GTK_STYLE_PROVIDER(provider), priority);
2521 geany_debug("Loaded GTK+ CSS theme '%s'", fn);
2522
2523 g_object_unref(provider);
2524}
2525
2526
2527static void init_css_styles(void)
2528{
2529 gchar *theme_fn;
2530
2531 // load the main geany.css file from system data dir
2532 theme_fn = g_build_filename(app->datadir, "geany.css", NULL);
2533 load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
2534 g_free(theme_fn);
2535
2536 // load themes to handle breakage between various GTK+ versions
2537 const struct
2538 {
2539 guint min_version;
2540 guint max_version;
2541 const gchar *file;
2542 }
2543 css_files[] =
2544 {
2545 { 20, G_MAXUINT, "geany-3.20.css" },
2546 { 0, 19, "geany-3.0.css" },
2547 };
2548
2549 guint gtk_version = gtk_get_minor_version();
2550 for (guint i = 0; i < G_N_ELEMENTS(css_files); i++)
2551 {
2552 if (gtk_version >= css_files[i].min_version &&
2553 gtk_version <= css_files[i].max_version)
2554 {
2555 theme_fn = g_build_filename(app->datadir, css_files[i].file, NULL);
2556 load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
2557 g_free(theme_fn);
2558 }
2559 }
2560
2561 // if the user provided a geany.css file in their config dir, try and load that
2562 theme_fn = g_build_filename(app->configdir, "geany.css", NULL);
2563 if (g_file_test(theme_fn, G_FILE_TEST_EXISTS))
2564 load_css_theme(theme_fn, GTK_STYLE_PROVIDER_PRIORITY_USER);
2565 g_free(theme_fn);
2566}
2567
2568
2570{
2571 gchar *theme_fn;
2572 theme_fn = g_build_filename(app->configdir, "geany.css", NULL);
2574 g_free(theme_fn);
2575}
2576
2577
2578void ui_init(void)
2579{
2582
2583 ui_widgets.statusbar = ui_lookup_widget(main_widgets.window, "statusbar");
2584 ui_widgets.print_page_setup = ui_lookup_widget(main_widgets.window, "page_setup1");
2585
2587
2588 /* current word sensitive items */
2589 widgets.popup_goto_items[0] = ui_lookup_widget(main_widgets.editor_menu, "goto_tag_definition2");
2590 widgets.popup_goto_items[1] = ui_lookup_widget(main_widgets.editor_menu, "context_action1");
2591 widgets.popup_goto_items[2] = ui_lookup_widget(main_widgets.editor_menu, "find_usage2");
2592 widgets.popup_goto_items[3] = ui_lookup_widget(main_widgets.editor_menu, "find_document_usage2");
2593
2594 widgets.popup_copy_items[0] = ui_lookup_widget(main_widgets.editor_menu, "cut1");
2595 widgets.popup_copy_items[1] = ui_lookup_widget(main_widgets.editor_menu, "copy1");
2596 widgets.popup_copy_items[2] = ui_lookup_widget(main_widgets.editor_menu, "delete1");
2597 widgets.menu_copy_items[0] = ui_lookup_widget(main_widgets.window, "menu_cut1");
2598 widgets.menu_copy_items[1] = ui_lookup_widget(main_widgets.window, "menu_copy1");
2599 widgets.menu_copy_items[2] = ui_lookup_widget(main_widgets.window, "menu_delete1");
2600 widgets.menu_insert_include_items[0] = ui_lookup_widget(main_widgets.editor_menu, "insert_include1");
2601 widgets.menu_insert_include_items[1] = ui_lookup_widget(main_widgets.window, "insert_include2");
2602 widgets.save_buttons[0] = ui_lookup_widget(main_widgets.window, "menu_save1");
2603 widgets.save_buttons[2] = ui_lookup_widget(main_widgets.window, "menu_save_all1");
2604 widgets.redo_items[0] = ui_lookup_widget(main_widgets.editor_menu, "redo1");
2605 widgets.redo_items[1] = ui_lookup_widget(main_widgets.window, "menu_redo2");
2606 widgets.undo_items[0] = ui_lookup_widget(main_widgets.editor_menu, "undo1");
2607 widgets.undo_items[1] = ui_lookup_widget(main_widgets.window, "menu_undo2");
2608
2609 /* reparent context submenus as needed */
2610 {
2611 GeanySharedMenu arr[] = {
2612 {"commands2_menu", "commands2", "commands1"},
2613 {"menu_format1_menu", "menu_format1", "menu_format2"},
2614 {"more1_menu", "more1", "search2"},
2615 {NULL, NULL, NULL}
2616 };
2617 static GeanySharedMenu items[G_N_ELEMENTS(arr)];
2618
2619 memcpy(items, arr, sizeof(arr));
2620 g_signal_connect(main_widgets.editor_menu, "show", G_CALLBACK(on_editor_menu_show), items);
2621 g_signal_connect(main_widgets.editor_menu, "hide", G_CALLBACK(on_editor_menu_hide), items);
2622 }
2623
2626
2629}
2630
2631
2633{
2634 if (GTK_IS_BUILDER(builder))
2635 g_object_unref(builder);
2636
2637 /* cleanup refs lingering even after GtkBuilder is destroyed */
2638 if (GTK_IS_WIDGET(edit_menu1))
2639 gtk_widget_destroy(edit_menu1);
2640 if (GTK_IS_WIDGET(prefs_dialog))
2641 gtk_widget_destroy(prefs_dialog);
2642 if (GTK_IS_WIDGET(project_dialog))
2643 gtk_widget_destroy(project_dialog);
2644 if (GTK_IS_WIDGET(toolbar_popup_menu1))
2645 gtk_widget_destroy(toolbar_popup_menu1);
2646 if (GTK_IS_WIDGET(window1))
2647 gtk_widget_destroy(window1);
2648}
2649
2650
2651static void auto_separator_update(GeanyAutoSeparator *autosep)
2652{
2653 g_return_if_fail(autosep->item_count >= 0);
2654
2655 if (autosep->widget)
2656 {
2657 if (autosep->item_count > 0)
2658 ui_widget_show_hide(autosep->widget, autosep->show_count > 0);
2659 else
2660 gtk_widget_destroy(autosep->widget);
2661 }
2662}
2663
2664
2665static void on_auto_separator_item_show_hide(GtkWidget *widget, gpointer user_data)
2666{
2667 GeanyAutoSeparator *autosep = user_data;
2668
2669 if (gtk_widget_get_visible(widget))
2670 autosep->show_count++;
2671 else
2672 autosep->show_count--;
2673 auto_separator_update(autosep);
2674}
2675
2676
2677static void on_auto_separator_item_destroy(GtkWidget *widget, gpointer user_data)
2678{
2679 GeanyAutoSeparator *autosep = user_data;
2680
2681 autosep->item_count--;
2682 autosep->item_count = MAX(autosep->item_count, 0);
2683 /* gtk_widget_get_visible() won't work now the widget is being destroyed,
2684 * so assume widget was visible */
2685 autosep->show_count--;
2686 autosep->show_count = MAX(autosep->item_count, 0);
2687 auto_separator_update(autosep);
2688}
2689
2690
2691/* Show the separator widget if @a item or another is visible. */
2692/* Note: This would be neater taking a widget argument, setting a "visible-count"
2693 * property, and using reference counting to keep the widget alive whilst its visible group
2694 * is alive. */
2695void ui_auto_separator_add_ref(GeanyAutoSeparator *autosep, GtkWidget *item)
2696{
2697 /* set widget ptr NULL when widget destroyed */
2698 if (autosep->item_count == 0)
2699 g_signal_connect(autosep->widget, "destroy",
2700 G_CALLBACK(gtk_widget_destroyed), &autosep->widget);
2701
2702 if (gtk_widget_get_visible(item))
2703 autosep->show_count++;
2704
2705 autosep->item_count++;
2706 auto_separator_update(autosep);
2707
2708 g_signal_connect(item, "show", G_CALLBACK(on_auto_separator_item_show_hide), autosep);
2709 g_signal_connect(item, "hide", G_CALLBACK(on_auto_separator_item_show_hide), autosep);
2710 g_signal_connect(item, "destroy", G_CALLBACK(on_auto_separator_item_destroy), autosep);
2711}
2712
2713
2714/**
2715 * Sets @a text as the contents of the tooltip for @a widget.
2716 *
2717 * @param widget The widget the tooltip should be set for.
2718 * @param text The text for the tooltip.
2719 *
2720 * @since 0.16
2721 * @deprecated 0.21 use gtk_widget_set_tooltip_text() instead
2722 */
2723GEANY_API_SYMBOL
2724void ui_widget_set_tooltip_text(GtkWidget *widget, const gchar *text)
2725{
2726 gtk_widget_set_tooltip_text(widget, text);
2727}
2728
2729
2730/** Returns a widget from a name in a component, usually created by Glade.
2731 * Call it with the toplevel widget in the component (i.e. a window/dialog),
2732 * or alternatively any widget in the component, and the name of the widget
2733 * you want returned.
2734 * @param widget Widget with the @a widget_name property set.
2735 * @param widget_name Name to lookup.
2736 *
2737 * @return @transfer{none} The widget found.
2738 * @see ui_hookup_widget().
2739 *
2740 * @since 0.16
2741 */
2742GEANY_API_SYMBOL
2743GtkWidget *ui_lookup_widget(GtkWidget *widget, const gchar *widget_name)
2744{
2745 GtkWidget *parent, *found_widget;
2746
2747 g_return_val_if_fail(widget != NULL, NULL);
2748 g_return_val_if_fail(widget_name != NULL, NULL);
2749
2750 for (;;)
2751 {
2752 if (GTK_IS_MENU(widget))
2753 parent = gtk_menu_get_attach_widget(GTK_MENU(widget));
2754 else
2755 parent = gtk_widget_get_parent(widget);
2756 if (parent == NULL)
2757 parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey");
2758 if (parent == NULL)
2759 break;
2760 widget = parent;
2761 }
2762
2763 found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget), widget_name);
2764 if (G_UNLIKELY(found_widget == NULL))
2765 g_warning("Widget not found: %s", widget_name);
2766 return found_widget;
2767}
2768
2769
2770/* wraps gtk_builder_get_object()
2771 * unlike ui_lookup_widget(), it does only support getting object created from the main
2772 * UI file, but it can fetch any object, not only widgets */
2773gpointer ui_builder_get_object (const gchar *name)
2774{
2775 return gtk_builder_get_object (builder, name);
2776}
2777
2778
2779/* Progress Bar */
2780static guint progress_bar_timer_id = 0;
2781
2782
2783static GtkWidget *progress_bar_create(void)
2784{
2785 GtkWidget *bar = gtk_progress_bar_new();
2786
2787 /* Set the progressbar's height to 1 to fit it in the statusbar */
2788 gtk_widget_set_size_request(bar, -1, 1);
2789 gtk_box_pack_start (GTK_BOX(ui_widgets.statusbar), bar, FALSE, FALSE, 3);
2790
2791 return bar;
2792}
2793
2794
2795static gboolean progress_bar_pulse(gpointer data)
2796{
2797 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(main_widgets.progressbar));
2798
2799 return TRUE;
2800}
2801
2802
2803/**
2804 * Starts a constantly pulsing progressbar in the right corner of the statusbar
2805 * (if the statusbar is visible). This is a convenience function which adds a timer to
2806 * pulse the progressbar constantly until ui_progress_bar_stop() is called.
2807 * You can use this function when you have time consuming asynchronous operation and want to
2808 * display some activity in the GUI and when you don't know about detailed progress steps.
2809 * The progressbar widget is hidden by default when it is not active. This function and
2810 * ui_progress_bar_stop() will show and hide it automatically for you.
2811 *
2812 * You can also access the progressbar widget directly using @c geany->main_widgets->progressbar
2813 * and use the GtkProgressBar API to set discrete fractions to display better progress information.
2814 * In this case, you need to show and hide the widget yourself. You can find some example code
2815 * in @c src/printing.c.
2816 *
2817 * @param text @nullable The text to be shown as the progress bar label or @c NULL to leave it empty.
2818 *
2819 * @since 0.16
2820 **/
2821GEANY_API_SYMBOL
2822void ui_progress_bar_start(const gchar *text)
2823{
2824 g_return_if_fail(progress_bar_timer_id == 0);
2825
2827 return;
2828
2829 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), text);
2830
2831 progress_bar_timer_id = g_timeout_add(200, progress_bar_pulse, NULL);
2832
2833 gtk_widget_show(GTK_WIDGET(main_widgets.progressbar));
2834}
2835
2836
2837/** Stops a running progress bar and hides the widget again.
2838 *
2839 * @since 0.16
2840 **/
2841GEANY_API_SYMBOL
2843{
2844 gtk_widget_hide(GTK_WIDGET(main_widgets.progressbar));
2845
2846 if (progress_bar_timer_id != 0)
2847 {
2848 g_source_remove(progress_bar_timer_id);
2850 }
2851}
2852
2853
2854static gint compare_menu_item_labels(gconstpointer a, gconstpointer b)
2855{
2856 GtkMenuItem *item_a = GTK_MENU_ITEM(a);
2857 GtkMenuItem *item_b = GTK_MENU_ITEM(b);
2858 gchar *sa, *sb;
2859 gint result;
2860
2861 /* put entries with submenus at the end of the menu */
2862 if (gtk_menu_item_get_submenu(item_a) && !gtk_menu_item_get_submenu(item_b))
2863 return 1;
2864 else if (!gtk_menu_item_get_submenu(item_a) && gtk_menu_item_get_submenu(item_b))
2865 return -1;
2866
2867 sa = ui_menu_item_get_text(item_a);
2868 sb = ui_menu_item_get_text(item_b);
2869 result = utils_str_casecmp(sa, sb);
2870 g_free(sa);
2871 g_free(sb);
2872 return result;
2873}
2874
2875
2876/* Currently @a menu should contain only GtkMenuItems with labels. */
2877static void ui_menu_sort_by_label(GtkMenu *menu)
2878{
2879 GList *list = gtk_container_get_children(GTK_CONTAINER(menu));
2880 GList *node;
2881 gint pos;
2882
2883 list = g_list_sort(list, compare_menu_item_labels);
2884 pos = 0;
2885 foreach_list(node, list)
2886 {
2887 menu_reorder_child(menu, node->data, pos);
2888 pos++;
2889 }
2890 g_list_free(list);
2891}
2892
2893
2894void ui_label_set_markup(GtkLabel *label, const gchar *format, ...)
2895{
2896 va_list a;
2897 gchar *text;
2898
2899 va_start(a, format);
2900 text = g_markup_vprintf_escaped(format, a);
2901 va_end(a);
2902
2903 gtk_label_set_text(label, text);
2904 gtk_label_set_use_markup(label, TRUE);
2905 g_free(text);
2906}
2907
2908
2909GtkWidget *ui_label_new_bold(const gchar *text)
2910{
2911 GtkWidget *label;
2912
2913 label = gtk_label_new(NULL);
2914 ui_label_set_markup(GTK_LABEL(label), "<b>%s</b>", text);
2915 return label;
2916}
2917
2918
2919/** @girskip
2920 * Adds a list of document items to @a menu.
2921 * @param menu Menu.
2922 * @param active @nullable Which document to highlight, or @c NULL.
2923 * @param callback is used for each menu item's @c "activate" signal and will be
2924 * passed the corresponding document pointer as @c user_data.
2925 * @warning You should check @c doc->is_valid in the callback.
2926 * @since 0.19
2927 **/
2928GEANY_API_SYMBOL
2929void ui_menu_add_document_items(GtkMenu *menu, GeanyDocument *active, GCallback callback)
2930{
2931 ui_menu_add_document_items_sorted(menu, active, callback, NULL);
2932}
2933
2934
2935/** @girskip
2936 * Adds a list of document items to @a menu.
2937 *
2938 * @a compare_func might be NULL to not sort the documents in the menu. In this case,
2939 * the order of the document tabs is used.
2940 *
2941 * See document_compare_by_display_name() for an example sort function.
2942 *
2943 * @param menu Menu.
2944 * @param active @nullable Which document to highlight, or @c NULL.
2945 * @param callback is used for each menu item's @c "activate" signal and will be passed
2946 * the corresponding document pointer as @c user_data.
2947 * @param compare_func is used to sort the list. Might be @c NULL to not sort the list.
2948 * @warning You should check @c doc->is_valid in the callback.
2949 * @since 0.21
2950 **/
2951GEANY_API_SYMBOL
2953 GCallback callback, GCompareFunc compare_func)
2954{
2955 GtkWidget *menu_item, *menu_item_label, *image;
2956 GeanyDocument *doc;
2957 guint i, len;
2958 gchar *base_name;
2959 GPtrArray *sorted_documents;
2960
2961 len = (guint) gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
2962
2963 sorted_documents = g_ptr_array_sized_new(len);
2964 /* copy the documents_array into the new one */
2966 {
2967 g_ptr_array_add(sorted_documents, documents[i]);
2968 }
2969 if (compare_func == NULL)
2970 compare_func = document_compare_by_tab_order;
2971
2972 /* and now sort it */
2973 g_ptr_array_sort(sorted_documents, compare_func);
2974
2975 for (i = 0; i < sorted_documents->len; i++)
2976 {
2977 doc = g_ptr_array_index(sorted_documents, i);
2978
2979 base_name = g_path_get_basename(DOC_FILENAME(doc));
2980 menu_item = gtk_image_menu_item_new_with_label(base_name);
2981 image = gtk_image_new_from_gicon(doc->file_type->icon, GTK_ICON_SIZE_MENU);
2982 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), image);
2983 gtk_widget_set_tooltip_text(menu_item, DOC_FILENAME(doc));
2984
2985 gtk_widget_show(menu_item);
2986 gtk_container_add(GTK_CONTAINER(menu), menu_item);
2987 g_signal_connect(menu_item, "activate", callback, doc);
2988
2989 menu_item_label = gtk_bin_get_child(GTK_BIN(menu_item));
2990 gtk_widget_set_name(menu_item_label, document_get_status_widget_class(doc));
2991
2992 if (doc == active)
2993 ui_label_set_markup(GTK_LABEL(menu_item_label), "<b>%s</b>", base_name);
2994
2995 g_free(base_name);
2996 }
2997 g_ptr_array_free(sorted_documents, TRUE);
2998}
2999
3000
3001/** Checks whether the passed @a keyval is the Enter or Return key.
3002 * There are three different Enter/Return key values
3003 * (@c GDK_KEY_Return, @c GDK_KEY_ISO_Enter, @c GDK_KEY_KP_Enter).
3004 * This is just a convenience function.
3005 * @param keyval A keyval.
3006 * @return @c TRUE if @a keyval is the one of the Enter/Return key values, otherwise @c FALSE.
3007 * @since 0.19 */
3008GEANY_API_SYMBOL
3009gboolean ui_is_keyval_enter_or_return(guint keyval)
3010{
3011 return (keyval == GDK_KEY_Return || keyval == GDK_KEY_ISO_Enter|| keyval == GDK_KEY_KP_Enter);
3012}
3013
3014
3015/** Reads an integer from the GTK default settings registry
3016 * (see http://library.gnome.org/devel/gtk/stable/GtkSettings.html).
3017 * @param property_name The property to read.
3018 * @param default_value The default value in case the value could not be read.
3019 * @return The value for the property if it exists, otherwise the @a default_value.
3020 * @since 0.19 */
3021GEANY_API_SYMBOL
3022gint ui_get_gtk_settings_integer(const gchar *property_name, gint default_value)
3023{
3024 if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(
3025 gtk_settings_get_default())), property_name))
3026 {
3027 gint value;
3028 g_object_get(G_OBJECT(gtk_settings_get_default()), property_name, &value, NULL);
3029 return value;
3030 }
3031 else
3032 return default_value;
3033}
3034
3035
3036void ui_editable_insert_text_callback(GtkEditable *editable, gchar *new_text,
3037 gint new_text_len, gint *position, gpointer data)
3038{
3039 gboolean first = position != NULL && *position == 0;
3040 gint i;
3041
3042 if (new_text_len == -1)
3043 new_text_len = (gint) strlen(new_text);
3044
3045 for (i = 0; i < new_text_len; i++, new_text++)
3046 {
3047 if ((!first || !strchr("+-", *new_text)) && !isdigit(*new_text))
3048 {
3049 g_signal_stop_emission_by_name(editable, "insert-text");
3050 break;
3051 }
3052 first = FALSE;
3053 }
3054}
3055
3056
3057/* gets the icon that applies to a particular MIME type */
3058GIcon *ui_get_mime_icon(const gchar *mime_type)
3059{
3060 GIcon *icon = NULL;
3061 gchar *ctype;
3062
3063 ctype = g_content_type_from_mime_type(mime_type);
3064 if (ctype)
3065 {
3066 GdkScreen *screen = gdk_screen_get_default();
3067
3068 icon = g_content_type_get_icon(ctype);
3069 if (screen && icon)
3070 {
3071 GtkIconInfo *icon_info;
3072
3073 icon_info = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_for_screen(screen), icon, 16, 0);
3074 if (!icon_info)
3075 {
3076 g_object_unref(icon);
3077 icon = NULL;
3078 }
3079 else
3080 gtk_icon_info_free(icon_info);
3081 }
3082
3083 g_free(ctype);
3084 }
3085
3086 /* fallback if icon lookup failed, like it might happen on Windows (?) */
3087 if (! icon)
3088 {
3089 const gchar *icon_name = "text-x-generic";
3090
3091 if (strstr(mime_type, "directory"))
3092 icon_name = "folder";
3093
3094 icon = g_themed_icon_new(icon_name);
3095 }
3096 return icon;
3097}
3098
3099
3101{
3103
3104 if (doc != NULL)
3106}
3107
3108
3109/** Finds the label text associated with stock_id
3110 * @param stock_id stock_id to lookup e.g. @c GTK_STOCK_OPEN.
3111 * @return The label text for stock
3112 * @since Geany 1.22 */
3113GEANY_API_SYMBOL
3114const gchar *ui_lookup_stock_label(const gchar *stock_id)
3115{
3116 GtkStockItem item;
3117
3118 if (gtk_stock_lookup(stock_id, &item))
3119 return item.label;
3120
3121 g_warning("No stock id '%s'!", stock_id);
3122 return NULL;
3123}
3124
3125
3126/* finds the next iter at any level
3127 * @param iter in/out, the current iter, will be changed to the next one
3128 * @param down whether to try the child iter
3129 * @return TRUE if there @p iter was set, or FALSE if there is no next iter */
3130gboolean ui_tree_model_iter_any_next(GtkTreeModel *model, GtkTreeIter *iter, gboolean down)
3131{
3132 GtkTreeIter guess;
3133 GtkTreeIter copy = *iter;
3134
3135 /* go down if the item has children */
3136 if (down && gtk_tree_model_iter_children(model, &guess, iter))
3137 *iter = guess;
3138 /* or to the next item at the same level */
3139 else if (gtk_tree_model_iter_next(model, &copy))
3140 *iter = copy;
3141 /* or to the next item at a parent level */
3142 else if (gtk_tree_model_iter_parent(model, &guess, iter))
3143 {
3144 copy = guess;
3145 while (TRUE)
3146 {
3147 if (gtk_tree_model_iter_next(model, &copy))
3148 {
3149 *iter = copy;
3150 return TRUE;
3151 }
3152 else if (gtk_tree_model_iter_parent(model, &copy, &guess))
3153 guess = copy;
3154 else
3155 return FALSE;
3156 }
3157 }
3158 else
3159 return FALSE;
3160
3161 return TRUE;
3162}
3163
3164
3165GtkWidget *ui_create_encodings_combo_box(gboolean has_detect, gint default_enc)
3166{
3167 GtkCellRenderer *renderer;
3168 GtkTreeIter iter;
3169 GtkWidget *combo = gtk_combo_box_new();
3170 GtkTreeStore *store = encodings_encoding_store_new(has_detect);
3171
3172 if (default_enc < 0 || default_enc >= GEANY_ENCODINGS_MAX)
3173 default_enc = has_detect ? GEANY_ENCODINGS_MAX : GEANY_ENCODING_NONE;
3174
3175 gtk_combo_box_set_model(GTK_COMBO_BOX(combo), GTK_TREE_MODEL(store));
3176 if (encodings_encoding_store_get_iter(store, &iter, default_enc))
3177 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);
3178 renderer = gtk_cell_renderer_text_new();
3179 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
3180 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo), renderer,
3182
3183 return combo;
3184}
3185
3186
3188{
3189 GtkTreeIter iter;
3190 gint enc = GEANY_ENCODING_NONE;
3191
3192 /* there should always be an active iter anyway, but we check just in case */
3193 if (gtk_combo_box_get_active_iter(combo, &iter))
3194 {
3195 GtkTreeModel *model = gtk_combo_box_get_model(combo);
3196 enc = encodings_encoding_store_get_encoding(GTK_TREE_STORE(model), &iter);
3197 }
3198
3199 return enc;
3200}
3201
3202
3203gboolean ui_encodings_combo_box_set_active_encoding(GtkComboBox *combo, gint enc)
3204{
3205 GtkTreeIter iter;
3206 GtkTreeModel *model = gtk_combo_box_get_model(combo);
3207
3208 if (encodings_encoding_store_get_iter(GTK_TREE_STORE(model), &iter, enc))
3209 {
3210 gtk_combo_box_set_active_iter(combo, &iter);
3211 return TRUE;
3212 }
3213 return FALSE;
3214}
#define SC_EOL_CR
Definition: Scintilla.h:89
#define SC_EOL_LF
Definition: Scintilla.h:90
Contains the GeanyApp.
static const gchar * groups[GEANY_GBG_COUNT]
Definition: build.c:2287
const gchar * label
Definition: build.c:2676
void callbacks_connect(GtkBuilder *builder)
Definition: callbacks.c:1997
gboolean ignore_callback
Definition: libmain.c:87
gchar * dialogs_show_input(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text)
Asks the user for text input.
Definition: dialogs.c:1067
void dialogs_show_msgbox_with_secondary(GtkMessageType type, const gchar *text, const gchar *secondary)
Definition: dialogs.c:753
File related dialogs, miscellaneous dialogs, font dialog.
GeanyDocument * document_get_current(void)
Finds the current document.
Definition: document.c:371
gboolean document_can_redo(GeanyDocument *doc)
Definition: document.c:3083
void document_grab_focus(GeanyDocument *doc)
Definition: document.c:3812
const gchar * name
Definition: document.c:3219
gint document_compare_by_tab_order(gconstpointer a, gconstpointer b)
Compares documents by their tab order.
Definition: document.c:3776
const gchar * document_get_status_widget_class(GeanyDocument *doc)
Definition: document.c:3249
GeanyFilePrefs file_prefs
Definition: document.c:86
gboolean document_can_undo(GeanyDocument *doc)
Definition: document.c:2964
gchar * document_get_basename_for_display(GeanyDocument *doc, gint length)
Returns the last part of the filename of the given GeanyDocument.
Definition: document.c:412
GeanyDocument * document_open_file(const gchar *locale_filename, gboolean readonly, GeanyFiletype *ft, const gchar *forced_enc)
Opens a document specified by locale_filename.
Definition: document.c:908
GPtrArray * documents_array
Definition: document.c:87
void document_set_text_changed(GeanyDocument *doc, gboolean changed)
Updates the tab labels, the status bar, the window title and some save-sensitive buttons according to...
Definition: document.c:460
GeanyDocument * document_new_file(const gchar *utf8_filename, GeanyFiletype *ft, const gchar *text)
Creates a new document.
Definition: document.c:824
#define DOC_FILENAME(doc)
Returns the filename of the document passed or GEANY_STRING_UNTITLED (e.g.
Definition: document.h:170
#define documents
Wraps GeanyData::documents_array so it can be used with C array syntax.
Definition: document.h:130
#define foreach_document(i)
Iterates all valid document indexes.
Definition: document.h:153
void editor_set_font(GeanyEditor *editor, const gchar *font)
Definition: editor.c:4622
EditorInfo editor_info
Definition: editor.c:79
const GeanyIndentPrefs * editor_get_indent_prefs(GeanyEditor *editor)
Gets the indentation prefs for the editor.
Definition: editor.c:1267
gchar * text
Definition: editor.c:83
ScintillaObject * sci
Definition: editor.c:88
void editor_set_indentation_guides(GeanyEditor *editor)
Definition: editor.c:5091
gboolean set
Definition: editor.c:84
gint pos
Definition: editor.c:87
GeanyEditorPrefs editor_prefs
Definition: editor.c:77
@ GEANY_INDENT_TYPE_BOTH
Both.
Definition: editor.h:48
@ GEANY_INDENT_TYPE_TABS
Tabs.
Definition: editor.h:47
@ GEANY_INDENT_TYPE_SPACES
Spaces.
Definition: editor.h:46
void encodings_encoding_store_cell_data_func(GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
Definition: encodings.c:597
gboolean encodings_encoding_store_get_iter(GtkTreeStore *store, GtkTreeIter *iter, gint enc)
Definition: encodings.c:582
gint encodings_encoding_store_get_encoding(GtkTreeStore *store, GtkTreeIter *iter)
Definition: encodings.c:574
gboolean encodings_is_unicode_charset(const gchar *string)
Definition: encodings.c:855
void encodings_select_radio_item(const gchar *charset)
Definition: encodings.c:297
GtkTreeStore * encodings_encoding_store_new(gboolean has_detect)
Definition: encodings.c:517
@ GEANY_ENCODINGS_MAX
Definition: encodings.h:124
@ GEANY_ENCODING_NONE
Definition: encodings.h:121
void error(const errorSelection selection, const char *const format,...)
Definition: error.c:53
static GtkWidget * path_entry
Definition: filebrowser.c:85
Filetype detection, file extensions and filetype menu items.
@ GEANY_FILETYPES_CPP
Definition: filetypes.h:80
@ GEANY_FILETYPES_C
Definition: filetypes.h:55
@ GEANY_FILETYPES_CONF
Definition: filetypes.h:78
#define filetypes
Wraps GeanyData::filetypes_array so it can be used with C array syntax.
Definition: filetypes.h:178
vString * line
Definition: geany_cobol.c:133
CobolFormat format
Definition: geany_cobol.c:137
unsigned int count
tokenInfo * list
GtkWidget * geany_menu_button_action_get_menu(GeanyMenubuttonAction *action)
void geany_menu_button_action_set_menu(GeanyMenubuttonAction *action, GtkWidget *menu)
#define GEANY_MENU_BUTTON_ACTION(obj)
void keybindings_send_command(guint group_id, guint key_id)
Mimics a (built-in only) keybinding action.
Definition: keybindings.c:1426
Configurable keyboard shortcuts.
@ GEANY_KEY_GROUP_FORMAT
Group.
Definition: keybindings.h:107
@ GEANY_KEYS_FORMAT_COMMENTLINETOGGLE
Keybinding.
Definition: keybindings.h:228
void configuration_add_various_pref_group(struct StashGroup *group, const gchar *prefix)
Definition: keyfile.c:139
CommandLineOptions cl_options
Definition: libmain.c:90
GeanyApp * app
Definition: libmain.c:86
void geany_debug(gchar const *format,...)
Definition: log.c:67
Main program-related commands.
#define MAX(a, b)
Definition: mio.c:93
void msgwin_status_add(const gchar *format,...)
Logs a formatted status message without setting the status bar.
Definition: msgwindow.c:520
Message window functions (status, compiler, messages windows).
signal void(* project_close)(GObject *obj, gpointer user_data)
Sent after a project is closed.
GeanyPrefs prefs
Definition: prefs.c:66
gboolean project_load_file_with_session(const gchar *locale_file_name)
Definition: project.c:274
Project Management.
#define NULL
Definition: rbtree.h:150
char * strstr(const char *str, const char *substr)
Definition: routines.c:304
gint sci_get_col_from_position(ScintillaObject *sci, gint position)
Gets the column number relative to the start of the line that position is on.
Definition: sciwrappers.c:480
void sci_set_current_line(ScintillaObject *sci, gint line)
Definition: sciwrappers.c:544
gint sci_get_selected_text_length(ScintillaObject *sci)
Gets selected text length.
Definition: sciwrappers.c:788
gint sci_get_eol_mode(ScintillaObject *sci)
Definition: sciwrappers.c:262
void sci_set_symbol_margin(ScintillaObject *sci, gboolean set)
Definition: sciwrappers.c:202
gint sci_get_line_count(ScintillaObject *sci)
Gets the total number of lines.
Definition: sciwrappers.c:555
void sci_set_visible_eols(ScintillaObject *sci, gboolean set)
Definition: sciwrappers.c:238
gint sci_get_style_at(ScintillaObject *sci, gint position)
Gets style ID at position.
Definition: sciwrappers.c:1051
void sci_select_all(ScintillaObject *sci)
Definition: sciwrappers.c:1265
void sci_goto_pos(ScintillaObject *sci, gint pos, gboolean unfold)
Definition: sciwrappers.c:929
gint sci_get_length(ScintillaObject *sci)
Gets the length of all text.
Definition: sciwrappers.c:656
gint sci_get_current_position(ScintillaObject *sci)
Gets the cursor position.
Definition: sciwrappers.c:507
gint sci_get_overtype(ScintillaObject *sci)
Definition: sciwrappers.c:1297
void sci_set_line_numbers(ScintillaObject *sci, gboolean set)
Definition: sciwrappers.c:98
gint sci_get_lines_selected(ScintillaObject *sci)
Definition: sciwrappers.c:1199
gint sci_get_selection_end(ScintillaObject *sci)
Gets the selection end position.
Definition: sciwrappers.c:636
void sci_set_visible_white_spaces(ScintillaObject *sci, gboolean set)
Definition: sciwrappers.c:244
gint sci_get_cursor_virtual_space(ScintillaObject *sci)
Definition: sciwrappers.c:513
gboolean sci_has_selection(ScintillaObject *sci)
Checks if there's a selection.
Definition: sciwrappers.c:920
void sci_start_undo_action(ScintillaObject *sci)
Begins grouping a set of edits together as one Undo action.
Definition: sciwrappers.c:331
void sci_insert_text(ScintillaObject *sci, gint pos, const gchar *text)
Inserts text.
Definition: sciwrappers.c:1133
void sci_end_undo_action(ScintillaObject *sci)
Ends grouping a set of edits together as one Undo action.
Definition: sciwrappers.c:341
void sci_empty_undo_buffer(ScintillaObject *sci)
Definition: sciwrappers.c:353
gint sci_get_selection_start(ScintillaObject *sci)
Gets the selection start position.
Definition: sciwrappers.c:626
gint sci_get_line_from_position(ScintillaObject *sci, gint position)
Gets the line number from position.
Definition: sciwrappers.c:469
Wrapper functions for the Scintilla editor widget SCI_* messages.
GtkWidget * entry
Definition: search.c:118
gint position[2]
Definition: search.c:120
void sidebar_openfiles_update(GeanyDocument *doc)
Definition: sidebar.c:507
void filetypes_select_radio_item(const GeanyFiletype *ft)
Definition: filetypes.c:784
const gchar * filetypes_get_display_name(GeanyFiletype *ft)
Gets ft->name or a translation for filetype None.
Definition: filetypes.c:1527
StashGroup * group
Definition: stash-example.c:1
stash_group_add_boolean(group, &china_enabled, "china", TRUE)
stash_group_add_string(group, &potter_name, "potter_name", "Miss Clay")
const gchar filename[]
Definition: stash-example.c:4
GtkWidget * dialog
gtk_container_add(GTK_CONTAINER(dialog->vbox), check_button)
ui_hookup_widget(dialog, check_button, "check_handle")
gtk_widget_show_all(dialog)
StashGroup * stash_group_new(const gchar *name)
Creates a new group.
Definition: stash.c:360
Lightweight library for reading/writing GKeyFile settings and synchronizing widgets with C variables.
struct GeanyProject * project
Currently active project or NULL if none is open.
Definition: app.h:49
gchar * configdir
User configuration directory, usually ~/.config/geany.
Definition: app.h:45
gchar * datadir
Definition: app.h:46
Structure for representing an open tab with all its properties.
Definition: document.h:81
gchar * file_name
The UTF-8 encoded file name.
Definition: document.h:92
gboolean changed
Whether this document has been changed since it was last saved.
Definition: document.h:107
GeanyFiletype * file_type
The filetype for this document, it's only a reference to one of the elements of the global filetypes ...
Definition: document.h:101
struct GeanyDocumentPrivate * priv
Definition: document.h:121
gboolean has_bom
Internally used flag to indicate whether the file of this document has a byte-order-mark.
Definition: document.h:97
gchar * encoding
The encoding of the document, must be a valid string representation of an encoding,...
Definition: document.h:95
gboolean readonly
Whether this document is read-only.
Definition: document.h:105
gboolean is_valid
Flag used to check if this document is valid when iterating GeanyData::documents_array.
Definition: document.h:83
GeanyEditor * editor
The editor associated with the document.
Definition: document.h:98
gboolean show_markers_margin
Definition: editor.h:108
gboolean show_indent_guide
Definition: editor.h:102
gboolean show_linenumber_margin
Definition: editor.h:109
gboolean show_line_endings
Definition: editor.h:103
gboolean folding
Definition: editor.h:114
gboolean show_white_space
Definition: editor.h:101
gboolean line_breaking
Whether to split long lines as you type.
Definition: editor.h:158
gboolean auto_indent
TRUE if auto-indentation is enabled.
Definition: editor.h:154
ScintillaObject * sci
The Scintilla editor GtkWidget.
Definition: editor.h:152
gboolean line_wrapping
TRUE if line wrapping is enabled.
Definition: editor.h:153
guint mru_length
Definition: document.h:56
Represents a filetype.
Definition: filetypes.h:144
GIcon * icon
Definition: filetypes.h:165
GeanyFiletypeID id
Index in filetypes.
Definition: filetypes.h:145
gchar * mime_type
Definition: filetypes.h:164
Indentation prefs that might be different according to project or filetype.
Definition: editor.h:83
GeanyIndentType type
Whether to use tabs, spaces or both to indent.
Definition: editor.h:85
gint width
Indent width.
Definition: editor.h:84
Interface preferences.
Definition: ui_utils.h:46
gboolean statusbar_visible
whether the status bar is visible
Definition: ui_utils.h:56
gboolean show_symbol_list_expanders
whether to show expanders in the symbol list
Definition: ui_utils.h:57
gboolean compiler_tab_autoscroll
whether compiler messages window is automatically scrolled to show new messages
Definition: ui_utils.h:69
gboolean msgwin_status_visible
whether message window's status tab is visible
Definition: ui_utils.h:62
gboolean sidebar_symbol_visible
whether the symbol sidebar is visible
Definition: ui_utils.h:47
gchar * editor_font
editor font
Definition: ui_utils.h:49
gboolean sidebar_openfiles_visible
whether the open file list is visible
Definition: ui_utils.h:48
gboolean msgwin_compiler_visible
whether message window's compiler tab is visible
Definition: ui_utils.h:63
gboolean msgwin_scribble_visible
whether message window's scribble tab is visible
Definition: ui_utils.h:65
gboolean msgwin_messages_visible
whether message window's messages tab is visible
Definition: ui_utils.h:64
Important widgets in the main window.
Definition: ui_utils.h:79
GtkWidget * window
Main window.
Definition: ui_utils.h:80
GtkWidget * notebook
Document notebook.
Definition: ui_utils.h:83
GtkWidget * editor_menu
Popup editor menu.
Definition: ui_utils.h:84
GtkWidget * progressbar
Progress bar widget in the status bar to show progress of various actions.
Definition: ui_utils.h:88
GtkWidget * sidebar_notebook
Sidebar notebook.
Definition: ui_utils.h:82
gboolean suppress_status_messages
Definition: prefs.h:36
Structure for representing a project.
Definition: project.h:35
gchar * file_name
Where the project file is stored (in UTF-8).
Definition: project.h:38
gchar * name
The name of the project.
Definition: project.h:36
GtkWidget * menubar
Definition: ui_utils.c:110
GQueue * recent_queue
Definition: ui_utils.c:109
void(* activate_cb)(GtkMenuItem *, gpointer)
Definition: ui_utils.c:112
GtkWidget * toolbar
Definition: ui_utils.c:111
const gchar * popup_item
Definition: ui_utils.c:2293
const gchar * menubar_item
Definition: ui_utils.c:2292
const gchar * menu
Definition: ui_utils.c:2291
Defines internationalization macros.
#define _(String)
Definition: support.h:42
#define N_(String)
Definition: support.h:43
#define GETTEXT_PACKAGE
Definition: support.h:37
const gchar * icon_name
Definition: symbols.c:91
gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname)
Definition: symbols.c:2504
Tag-related functions.
GtkWidget * toolbar_get_widget_by_name(const gchar *name)
Definition: toolbar.c:124
GtkAction * toolbar_get_action_by_name(const gchar *name)
Definition: toolbar.c:152
Toolbar (prefs).
static void on_menu_insert_date_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: ui_utils.c:762
void ui_init_toolbar_widgets(void)
Definition: ui_utils.c:2232
void ui_update_statusbar(GeanyDocument *doc, gint pos)
Definition: ui_utils.c:324
static const gchar * ui_guess_object_name(GObject *obj)
Definition: ui_utils.c:2362
void ui_set_fullscreen(void)
Definition: ui_utils.c:440
void ui_table_add_row(GtkTable *table, gint row,...)
Packs all GtkWidgets passed after the row argument into a table, using one widget per cell.
Definition: ui_utils.c:2066
void ui_init_builder(void)
Definition: ui_utils.c:2433
void ui_widget_show_hide(GtkWidget *widget, gboolean show)
Definition: ui_utils.c:987
static void add_css_config_file_item(void)
Definition: ui_utils.c:2569
void ui_create_insert_menu_items(void)
Definition: ui_utils.c:646
static GtkWidget * project_dialog
Definition: ui_utils.c:82
static void insert_include(GeanyDocument *doc, gint pos, const gchar *include)
Definition: ui_utils.c:571
static void on_editor_menu_show(GtkWidget *widget, GeanySharedMenu *items)
Definition: ui_utils.c:2300
GtkWidget * save_buttons[4]
Definition: ui_utils.c:95
void ui_sidebar_show_hide(void)
Definition: ui_utils.c:1000
static gint find_recent_file_item(gconstpointer list_data, gconstpointer user_data)
Definition: ui_utils.c:1280
void ui_update_menu_copy_items(GeanyDocument *doc)
Definition: ui_utils.c:523
void ui_update_popup_goto_items(gboolean enable)
Definition: ui_utils.c:504
const gchar * ui_lookup_stock_label(const gchar *stock_id)
Finds the label text associated with stock_id.
Definition: ui_utils.c:3114
GtkWidget * create_toolbar_popup_menu1(void)
Definition: ui_utils.c:2398
static void init_document_widgets(void)
Definition: ui_utils.c:864
static guint progress_bar_timer_id
Definition: ui_utils.c:2780
void ui_dialog_set_primary_button_order(GtkDialog *dialog, gint response,...)
Definition: ui_utils.c:1523
GtkWidget * popup_goto_items[4]
Definition: ui_utils.c:90
static GtkWidget * edit_menu1
Definition: ui_utils.c:80
static gchar * run_file_chooser(const gchar *title, GtkFileChooserAction action, const gchar *utf8_path)
Definition: ui_utils.c:1964
static GtkWidget * toolbar_popup_menu1
Definition: ui_utils.c:79
void ui_statusbar_showhide(gboolean state)
Definition: ui_utils.c:2046
static void create_config_files_menu(void)
Definition: ui_utils.c:2176
void ui_add_document_sensitive(GtkWidget *widget)
Adds a widget to the list of widgets that should be set sensitive/insensitive when some documents are...
Definition: ui_utils.c:976
void ui_label_set_markup(GtkLabel *label, const gchar *format,...)
Definition: ui_utils.c:2894
void ui_progress_bar_start(const gchar *text)
Starts a constantly pulsing progressbar in the right corner of the statusbar (if the statusbar is vis...
Definition: ui_utils.c:2822
void ui_init(void)
Definition: ui_utils.c:2578
static gboolean ui_tree_view_query_tooltip_cb(GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer data)
Definition: ui_utils.c:1826
static void auto_separator_update(GeanyAutoSeparator *autosep)
Definition: ui_utils.c:2651
static void insert_date_items(GtkMenu *me, GtkMenu *mp, gchar *label)
Definition: ui_utils.c:768
void ui_update_tab_status(GeanyDocument *doc)
Definition: ui_utils.c:1745
gint ui_get_gtk_settings_integer(const gchar *property_name, gint default_value)
Reads an integer from the GTK default settings registry (see http://library.gnome....
Definition: ui_utils.c:3022
void ui_create_recent_menus(void)
Definition: ui_utils.c:1168
static void on_auto_separator_item_show_hide(GtkWidget *widget, gpointer user_data)
Definition: ui_utils.c:2665
static void recent_file_loaded(const gchar *utf8_filename, GeanyRecentFiles *grf)
Definition: ui_utils.c:1350
GtkWidget * create_edit_menu1(void)
Definition: ui_utils.c:2380
#define add_doc_widget(widget_name)
Definition: ui_utils.c:858
static gboolean sort_menu(gpointer data)
Definition: ui_utils.c:2169
GtkWidget * popup_copy_items[3]
Definition: ui_utils.c:91
GtkWidget * ui_dialog_vbox_new(GtkDialog *dialog)
Makes a fixed border for dialogs without increasing the button box border.
Definition: ui_utils.c:1499
gboolean ui_tree_view_find_next(GtkTreeView *treeview, TVMatchCallback cb)
Definition: ui_utils.c:1812
gpointer ui_builder_get_object(const gchar *name)
Definition: ui_utils.c:2773
gboolean ui_tree_view_find_previous(GtkTreeView *treeview, TVMatchCallback cb)
Definition: ui_utils.c:1819
void ui_set_editor_font(const gchar *font_name)
Definition: ui_utils.c:413
GtkWidget * create_project_dialog(void)
Definition: ui_utils.c:2392
void ui_menu_add_document_items(GtkMenu *menu, GeanyDocument *active, GCallback callback)
<simplesect kind="geany:skip"></simplesect> Adds a list of document items to menu.
Definition: ui_utils.c:2929
gboolean ui_is_keyval_enter_or_return(guint keyval)
Checks whether the passed keyval is the Enter or Return key.
Definition: ui_utils.c:3009
gboolean ui_encodings_combo_box_set_active_encoding(GtkComboBox *combo, gint enc)
Definition: ui_utils.c:3203
static void insert_include_items(GtkMenu *me, GtkMenu *mp, gchar **includes, gchar *label)
Definition: ui_utils.c:613
void ui_update_popup_copy_items(GeanyDocument *doc)
Definition: ui_utils.c:486
GIcon * ui_get_mime_icon(const gchar *mime_type)
Definition: ui_utils.c:3058
void ui_widget_set_tooltip_text(GtkWidget *widget, const gchar *text)
Sets text as the contents of the tooltip for widget.
Definition: ui_utils.c:2724
void ui_init_prefs(void)
Definition: ui_utils.c:2332
static GtkWidget * progress_bar_create(void)
Definition: ui_utils.c:2783
void ui_save_buttons_toggle(gboolean enable)
Definition: ui_utils.c:830
void ui_add_recent_project_file(const gchar *utf8_filename)
Definition: ui_utils.c:1257
GtkWidget * ui_path_box_new(const gchar *title, GtkFileChooserAction action, GtkEntry *entry)
Creates a GtkHBox with entry packed into it and an open button which runs a file chooser,...
Definition: ui_utils.c:1917
GtkWidget * menu_copy_items[3]
Definition: ui_utils.c:92
static void init_recent_files(void)
Definition: ui_utils.c:2262
void ui_combo_box_prepend_text_once(GtkComboBoxText *combo, const gchar *text)
Definition: ui_utils.c:1730
GtkWidget * create_prefs_dialog(void)
Definition: ui_utils.c:2386
static void on_editor_menu_hide(GtkWidget *widget, GeanySharedMenu *items)
Definition: ui_utils.c:2315
static gchar * create_statusbar_statistics(GeanyDocument *doc, guint line, guint vcol, guint pos)
Definition: ui_utils.c:188
#define foreach_menu(item, array)
Definition: ui_utils.c:2297
void ui_set_window_title(GeanyDocument *doc)
Definition: ui_utils.c:366
static GtkWidget * window1
Definition: ui_utils.c:78
static GtkWidget * ui_get_top_parent(GtkWidget *widget)
Definition: ui_utils.c:2410
GtkWidget * undo_items[3]
Definition: ui_utils.c:94
void ui_swap_sidebar_pos(void)
Definition: ui_utils.c:2241
static gboolean tree_view_find(GtkTreeView *treeview, TVMatchCallback cb, gboolean down)
Definition: ui_utils.c:1771
static void add_to_size_group(GtkWidget *widget, gpointer size_group)
Definition: ui_utils.c:1641
static void insert_date(GeanyDocument *doc, gint pos, const gchar *date_style)
Definition: ui_utils.c:695
static gboolean tree_model_iter_get_next(GtkTreeModel *model, GtkTreeIter *iter, gboolean down)
Definition: ui_utils.c:1753
static GeanyRecentFiles * recent_get_recent_files(void)
Definition: ui_utils.c:1137
void ui_hbutton_box_copy_layout(GtkButtonBox *master, GtkButtonBox *copy)
Definition: ui_utils.c:1651
static void add_recent_file_menu_item(const gchar *utf8_filename, GeanyRecentFiles *grf, GtkWidget *menu)
Definition: ui_utils.c:1331
gboolean ui_tree_model_iter_any_next(GtkTreeModel *model, GtkTreeIter *iter, gboolean down)
Definition: ui_utils.c:3130
void ui_entry_add_activate_backward_signal(GtkEntry *entry)
Definition: ui_utils.c:1613
GtkWidget * ui_create_encodings_combo_box(gboolean has_detect, gint default_enc)
Definition: ui_utils.c:3165
static void free_on_closure_notify(gpointer data, GClosure *closure)
Definition: ui_utils.c:2136
gchar * ui_menu_item_get_text(GtkMenuItem *menu_item)
Definition: ui_utils.c:1264
static GtkWidget * prefs_dialog
Definition: ui_utils.c:81
static void on_popup_insert_date_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: ui_utils.c:756
GeanyMainWidgets main_widgets
Definition: ui_utils.c:72
static void recent_create_menu(GeanyRecentFiles *grf)
Definition: ui_utils.c:1111
void ui_menu_copy_items_set_sensitive(gboolean sensitive)
Definition: ui_utils.c:513
void ui_entry_add_clear_icon(GtkEntry *entry)
Adds a small clear icon to the right end of the passed entry.
Definition: ui_utils.c:1604
static void recent_project_activate_cb(GtkMenuItem *menuitem, gpointer user_data)
GtkWidget * config_files_menu
Definition: ui_utils.c:96
GtkWidget * redo_items[3]
Definition: ui_utils.c:93
static void set_statusbar(const gchar *text, gboolean allow_override)
Definition: ui_utils.c:134
static void load_css_theme(const gchar *fn, guint priority)
Definition: ui_utils.c:2507
void ui_set_statusbar(gboolean log, const gchar *format,...)
Displays text on the statusbar.
Definition: ui_utils.c:168
void ui_auto_separator_add_ref(GeanyAutoSeparator *autosep, GtkWidget *item)
Definition: ui_utils.c:2695
void ui_document_show_hide(GeanyDocument *doc)
Definition: ui_utils.c:1029
void ui_focus_current_document(void)
Definition: ui_utils.c:3100
gint ui_encodings_combo_box_get_active_encoding(GtkComboBox *combo)
Definition: ui_utils.c:3187
void ui_progress_bar_stop(void)
Stops a running progress bar and hides the widget again.
Definition: ui_utils.c:2842
void ui_update_view_editor_menu_items(void)
Definition: ui_utils.c:1453
static void init_css_styles(void)
Definition: ui_utils.c:2527
UIPrefs ui_prefs
Definition: ui_utils.c:74
void ui_combo_box_add_to_history(GtkComboBoxText *combo_entry, const gchar *text, gint history_len)
Prepends text to the drop down list, removing a duplicate element in the list if found.
Definition: ui_utils.c:1697
GtkWidget * menu_insert_include_items[2]
Definition: ui_utils.c:89
void ui_add_recent_document(GeanyDocument *doc)
Definition: ui_utils.c:1232
void ui_document_buttons_update(void)
Definition: ui_utils.c:946
GtkWidget * ui_button_new_with_image(const gchar *stock_id, const gchar *text)
Creates a GtkButton with custom text and a stock image similar to gtk_button_new_from_stock().
Definition: ui_utils.c:1552
void ui_update_fold_items(void)
Definition: ui_utils.c:562
static gint compare_menu_item_labels(gconstpointer a, gconstpointer b)
Definition: ui_utils.c:2854
void ui_toggle_editor_features(GeanyUIEditorFeatures feature)
Definition: ui_utils.c:1423
GtkWidget * create_window1(void)
Definition: ui_utils.c:2404
static void ui_menu_move(GtkWidget *menu, GtkWidget *old, GtkWidget *new)
Definition: ui_utils.c:2280
void ui_add_config_file_menu_item(const gchar *real_path, const gchar *label, GtkContainer *parent)
Definition: ui_utils.c:2144
void ui_update_recent_project_menu(void)
Definition: ui_utils.c:1296
GtkWidget * ui_image_menu_item_new(const gchar *stock_id, const gchar *label)
Creates a GtkImageMenuItem with a stock image and a custom label.
Definition: ui_utils.c:1574
static void add_stock_icons(const GtkStockItem *items, gsize count)
Definition: ui_utils.c:2197
static struct @125 widgets
GtkWidget * ui_label_new_bold(const gchar *text)
Definition: ui_utils.c:2909
void ui_widget_set_sensitive(GtkWidget *widget, gboolean set)
Definition: ui_utils.c:125
void ui_menu_add_document_items_sorted(GtkMenu *menu, GeanyDocument *active, GCallback callback, GCompareFunc compare_func)
<simplesect kind="geany:skip"></simplesect> Adds a list of document items to menu.
Definition: ui_utils.c:2952
static void on_menu_insert_include_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: ui_utils.c:607
void ui_set_search_entry_background(GtkWidget *widget, gboolean success)
Definition: ui_utils.c:1105
static void ui_path_box_open_clicked(GtkButton *button, gpointer user_data)
Definition: ui_utils.c:2002
static void ui_menu_sort_by_label(GtkMenu *menu)
Definition: ui_utils.c:2877
static void on_auto_separator_item_destroy(GtkWidget *widget, gpointer user_data)
Definition: ui_utils.c:2677
static gboolean tree_model_find_text(GtkTreeModel *model, GtkTreeIter *iter, gint column, const gchar *text)
Definition: ui_utils.c:1668
GtkWidget * ui_lookup_widget(GtkWidget *widget, const gchar *widget_name)
Returns a widget from a name in a component, usually created by Glade.
Definition: ui_utils.c:2743
static GeanyRecentFiles * recent_get_recent_projects(void)
Definition: ui_utils.c:1153
void ui_init_stock_items(void)
Definition: ui_utils.c:2218
void ui_finalize_builder(void)
Definition: ui_utils.c:2632
static gboolean progress_bar_pulse(gpointer data)
Definition: ui_utils.c:2795
void ui_tree_view_set_tooltip_text_column(GtkTreeView *tree_view, gint column)
Adds text tooltips to a tree view.
Definition: ui_utils.c:1876
void ui_editable_insert_text_callback(GtkEditable *editable, gchar *new_text, gint new_text_len, gint *position, gpointer data)
Definition: ui_utils.c:3036
void ui_widget_modify_font_from_string(GtkWidget *widget, const gchar *str)
Modifies the font of a widget using gtk_widget_modify_font().
Definition: ui_utils.c:1894
GtkWidget * ui_frame_new_with_alignment(const gchar *label_text, GtkWidget **alignment)
Creates a GNOME HIG-style frame (with no border and indented child alignment).
Definition: ui_utils.c:1475
static void on_doc_sensitive_widget_destroy(GtkWidget *widget, G_GNUC_UNUSED gpointer user_data)
Definition: ui_utils.c:962
void ui_setup_open_button_callback(GtkWidget *open_btn, const gchar *title, GtkFileChooserAction action, GtkEntry *entry)
Definition: ui_utils.c:1950
#define add_doc_toolitem(widget_name)
Definition: ui_utils.c:861
static void recent_file_activate_cb(GtkMenuItem *menuitem, gpointer user_data)
void ui_update_popup_reundo_items(GeanyDocument *doc)
Definition: ui_utils.c:453
static void on_popup_insert_include_activate(GtkMenuItem *menuitem, gpointer user_data)
Definition: ui_utils.c:601
void ui_update_insert_include_item(GeanyDocument *doc, gint item)
Definition: ui_utils.c:547
static void on_config_file_clicked(GtkWidget *widget, gpointer user_data)
Definition: ui_utils.c:2084
UIWidgets ui_widgets
Definition: ui_utils.c:75
struct GeanySharedMenu GeanySharedMenu
GeanyInterfacePrefs interface_prefs
Definition: ui_utils.c:71
void ui_create_insert_date_menu_items(void)
Definition: ui_utils.c:784
#define DEFAULT_STATUSBAR_TEMPLATE
Definition: ui_utils.c:61
static void update_recent_menu(GeanyRecentFiles *grf)
Definition: ui_utils.c:1385
static GtkBuilder * builder
Definition: ui_utils.c:77
GPtrArray * document_buttons
Definition: ui_utils.c:88
static void menu_reorder_child(GtkMenu *menu, GtkWidget *child, gint position)
Definition: ui_utils.c:1319
@ RECENT_FILE_PROJECT
Definition: ui_utils.c:103
@ RECENT_FILE_FILE
Definition: ui_utils.c:102
static void entry_clear_icon_release_cb(GtkEntry *entry, gint icon_pos, GdkEvent *event, gpointer data)
Definition: ui_utils.c:1585
static void add_recent_file(const gchar *utf8_filename, GeanyRecentFiles *grf, const GtkRecentData *rdata)
Definition: ui_utils.c:1202
User Interface general utility functions.
#define GEANY_STOCK_CLOSE_ALL
Definition: ui_utils.h:97
#define GEANY_STOCK_SAVE_ALL
Definition: ui_utils.h:96
#define GEANY_STOCK_BUILD
Definition: ui_utils.h:98
gint utils_str_casecmp(const gchar *s1, const gchar *s2)
A replacement function for g_strncasecmp() to compare strings case-insensitive.
Definition: utils.c:506
gchar * utils_get_utf8_from_locale(const gchar *locale_text)
Converts the given string (in locale encoding) into UTF-8 encoding.
Definition: utils.c:1272
gchar * utils_get_date_time(const gchar *format, time_t *time_to_use)
Retrieves a formatted date/time string from strftime().
Definition: utils.c:736
void utils_beep(void)
Definition: utils.c:918
gboolean utils_str_equal(const gchar *a, const gchar *b)
NULL-safe string comparison.
Definition: utils.c:599
const gchar * utils_get_eol_short_name(gint eol_mode)
Definition: utils.c:382
void utils_free_pointers(gsize arg_count,...)
Definition: utils.c:1293
gchar * utils_get_locale_from_utf8(const gchar *utf8_text)
Converts the given UTF-8 encoded string into locale encoding.
Definition: utils.c:1243
General utility functions, non-GTK related.
#define foreach_list(node, list)
Iterates all the nodes in list.
Definition: utils.h:115
#define SETPTR(ptr, result)
Assigns result to ptr, then frees the old value.
Definition: utils.h:50
#define EMPTY(ptr)
Returns TRUE if ptr is NULL or *ptr is FALSE.
Definition: utils.h:38