[geany/geany] 35cc44: Merge branch 'gtk3-support'

Colomban Wendling git-noreply at xxxxx
Sun Mar 10 16:20:25 UTC 2013


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Sun, 10 Mar 2013 16:20:25 UTC
Commit:      35cc441b74dc8103144d09c429f5da5c11770680
             https://github.com/geany/geany/commit/35cc441b74dc8103144d09c429f5da5c11770680

Log Message:
-----------
Merge branch 'gtk3-support'

Conflicts:
	src/ui_utils.c


Modified Paths:
--------------
    Makefile.am
    configure.ac
    data/geany.css
    plugins/filebrowser.c
    plugins/saveactions.c
    plugins/splitwindow.c
    src/Makefile.am
    src/build.c
    src/callbacks.c
    src/dialogs.c
    src/document.c
    src/editor.c
    src/gb.c
    src/geanywraplabel.c
    src/gtkcompat.h
    src/keybindings.c
    src/notebook.c
    src/plugindata.h
    src/search.c
    src/sidebar.c
    src/socket.c
    src/stash.c
    src/toolbar.c
    src/ui_utils.c
    src/ui_utils.h
    src/vte.c

Modified: Makefile.am
7 files changed, 6 insertions(+), 1 deletions(-)
===================================================================
@@ -24,8 +24,13 @@ SYS_DATA_FILES = \
 	$(srcdir)/data/templates/* \
 	$(srcdir)/data/templates/files/* \
 	$(srcdir)/data/colorschemes/* \
-	$(top_srcdir)/data/geany.glade \
+	$(top_srcdir)/data/geany.glade
+
+if GTK3
+	$(top_srcdir)/data/geany.css
+else
 	$(top_srcdir)/data/geany.gtkrc
+endif
 
 EXTRA_DIST = \
 	autogen.sh \


Modified: configure.ac
17 files changed, 15 insertions(+), 2 deletions(-)
===================================================================
@@ -56,14 +56,27 @@ GEANY_CHECK_REVISION([dnl force debug mode for a SVN working copy
 					  CFLAGS="-g -DGEANY_DEBUG $CFLAGS"])
 
 
+AC_ARG_ENABLE([gtk3],
+		[AS_HELP_STRING([--enable-gtk3],
+						[compile with GTK3 support (experimental) [default=no]])],
+		[enable_gtk3=$enableval],
+		[enable_gtk3=no])
+
+AS_IF([test "x$enable_gtk3" = xyes],
+	  [gtk_package=gtk+-3.0
+	   gtk_min_version=3.0],
+	  [gtk_package=gtk+-2.0
+	   gtk_min_version=2.16])
+AM_CONDITIONAL([GTK3], [test "x$gtk_package" = "xgtk+-3.0"])
+
 # GTK/GLib/GIO checks
-gtk_modules="gtk+-2.0 >= 2.16 glib-2.0 >= 2.20"
+gtk_modules="$gtk_package >= $gtk_min_version glib-2.0 >= 2.20"
 gtk_modules_private="gio-2.0 >= 2.20 gmodule-2.0"
 PKG_CHECK_MODULES([GTK], [$gtk_modules $gtk_modules_private])
 AC_SUBST([DEPENDENCIES], [$gtk_modules])
 AC_SUBST([GTK_CFLAGS])
 AC_SUBST([GTK_LIBS])
-GTK_VERSION=`$PKG_CONFIG --modversion gtk+-2.0`
+GTK_VERSION=`$PKG_CONFIG --modversion $gtk_package`
 GEANY_STATUS_ADD([Using GTK version], [${GTK_VERSION}])
 # GTHREAD checks
 gthread_modules="gthread-2.0"


Modified: data/geany.css
36 files changed, 36 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,36 @@
+/* custom GTK3 CSS for Geany */
+
+/* make close button on the editor's tabs smaller */
+#geany-close-tab-button {
+	-GtkWidget-focus-padding: 0;
+	-GtkWidget-focus-line-width: 0;
+	-GtkButton-default-border: 0;
+	-GtkButton-default-outside-border: 0;
+	-GtkButton-inner-border: 0;
+	padding: 0;
+}
+
+/* use monospaced font in search entries for easier reading of regexp (#1907117) */
+#GeanyDialogSearch GtkEntry {
+	font-family: monospace;
+}
+
+/* set red background for GtkEntries showing unmatched searches */
+#geany-search-entry-no-match {
+	color: #fff;
+	background: #ff6666;
+}
+#geany-search-entry-no-match:selected {
+	background-color: #771111;
+}
+
+/* document status colors */
+#geany-document-status-changed {
+	color: #ff0000;
+}
+#geany-document-status-disk-changed {
+	color: #ff7f00;
+}
+#geany-document-status-readonly {
+	color: #007f00;
+}


Modified: plugins/filebrowser.c
9 files changed, 5 insertions(+), 4 deletions(-)
===================================================================
@@ -26,6 +26,7 @@
 #endif
 
 #include "geanyplugin.h"
+#include "gtkcompat.h"
 #include <string.h>
 
 #include <gdk/gdkkeysyms.h>
@@ -280,7 +281,7 @@ static void refresh(void)
 	utf8_dir = utils_get_utf8_from_locale(current_dir);
 	gtk_entry_set_text(GTK_ENTRY(path_entry), utf8_dir);
 	gtk_widget_set_tooltip_text(path_entry, utf8_dir);
-	ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(path_combo), utf8_dir, 0);
+	ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(path_combo), utf8_dir, 0);
 	g_free(utf8_dir);
 
 	add_top_level_entry();	/* ".." item */
@@ -803,7 +804,7 @@ static void on_filter_activate(GtkEntry *entry, gpointer user_data)
 	{
 		clear_filter();
 	}
-	ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(filter_combo), NULL, 0);
+	ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(filter_combo), NULL, 0);
 	refresh();
 }
 
@@ -897,7 +898,7 @@ static GtkWidget *make_filterbar(void)
 
 	label = gtk_label_new(_("Filter:"));
 
-	filter_combo = gtk_combo_box_entry_new_text();
+	filter_combo = gtk_combo_box_text_new_with_entry();
 	filter_entry = gtk_bin_get_child(GTK_BIN(filter_combo));
 
 	ui_entry_add_clear_icon(GTK_ENTRY(filter_entry));
@@ -1091,7 +1092,7 @@ void plugin_init(GeanyData *data)
 	filterbar = make_filterbar();
 	gtk_box_pack_start(GTK_BOX(file_view_vbox), filterbar, FALSE, FALSE, 0);
 
-	path_combo = gtk_combo_box_entry_new_text();
+	path_combo = gtk_combo_box_text_new_with_entry();
 	gtk_box_pack_start(GTK_BOX(file_view_vbox), path_combo, FALSE, FALSE, 2);
 	g_signal_connect(path_combo, "changed", G_CALLBACK(ui_combo_box_changed), NULL);
 	path_entry = gtk_bin_get_child(GTK_BIN(path_combo));


Modified: plugins/saveactions.c
11 files changed, 6 insertions(+), 5 deletions(-)
===================================================================
@@ -25,6 +25,7 @@
 #endif
 
 #include "geanyplugin.h"
+#include "gtkcompat.h"
 
 #include <unistd.h>
 #include <errno.h>
@@ -429,8 +430,8 @@ static void configure_response_cb(GtkDialog *dialog, gint response, G_GNUC_UNUSE
 			GTK_TOGGLE_BUTTON(pref_widgets.autosave_save_all_radio2));
 
 		g_free(instantsave_default_ft);
-		instantsave_default_ft = gtk_combo_box_get_active_text(
-			GTK_COMBO_BOX(pref_widgets.instantsave_ft_combo));
+		instantsave_default_ft = gtk_combo_box_text_get_active_text(
+			GTK_COMBO_BOX_TEXT(pref_widgets.instantsave_ft_combo));
 
 		text_dir = gtk_entry_get_text(GTK_ENTRY(pref_widgets.backupcopy_entry_dir));
 		text_time = gtk_entry_get_text(GTK_ENTRY(pref_widgets.backupcopy_entry_time));
@@ -529,7 +530,7 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 	vbox = gtk_vbox_new(FALSE, 6);
 
 	notebook = gtk_notebook_new();
-	GTK_WIDGET_UNSET_FLAGS(notebook, GTK_CAN_FOCUS);
+	gtk_widget_set_can_focus(notebook, FALSE);
 	gtk_container_set_border_width(GTK_CONTAINER(notebook), 5);
 	gtk_box_pack_start(GTK_BOX(vbox), notebook, FALSE, TRUE, 0);
 
@@ -620,13 +621,13 @@ GtkWidget *plugin_configure(GtkDialog *dialog)
 		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 		gtk_box_pack_start(GTK_BOX(inner_vbox), label, FALSE, FALSE, 0);
 
-		pref_widgets.instantsave_ft_combo = combo = gtk_combo_box_new_text();
+		pref_widgets.instantsave_ft_combo = combo = gtk_combo_box_text_new();
 		i = 0;
 		foreach_slist(node, filetypes_get_sorted_by_name())
 		{
 			GeanyFiletype *ft = node->data;
 
-			gtk_combo_box_append_text(GTK_COMBO_BOX(combo), ft->name);
+			gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ft->name);
 
 			if (utils_str_equal(ft->name, instantsave_default_ft))
 				gtk_combo_box_set_active(GTK_COMBO_BOX(combo), i);


Modified: plugins/splitwindow.c
5 files changed, 3 insertions(+), 2 deletions(-)
===================================================================
@@ -26,6 +26,7 @@
 #endif
 
 #include "geanyplugin.h"
+#include "gtkcompat.h"
 #include <string.h>
 
 
@@ -300,8 +301,8 @@ static void split_view(gboolean horizontal)
 	GtkWidget *parent = gtk_widget_get_parent(notebook);
 	GtkWidget *pane, *toolbar, *box;
 	GeanyDocument *doc = document_get_current();
-	gint width = notebook->allocation.width / 2;
-	gint height = notebook->allocation.height / 2;
+	gint width = gtk_widget_get_allocated_width(notebook) / 2;
+	gint height = gtk_widget_get_allocated_height(notebook) / 2;
 
 	g_return_if_fail(doc);
 	g_return_if_fail(edit_window.editor == NULL);


Modified: src/Makefile.am
2 files changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -20,6 +20,7 @@ SRCS = \
 	geanymenubuttonaction.c geanymenubuttonaction.h \
 	geanyobject.c geanyobject.h \
 	geanywraplabel.c geanywraplabel.h \
+	gtkcompat.h \
 	highlighting.c highlighting.h \
 	highlightingmappings.h \
 	keybindings.c keybindings.h \
@@ -59,6 +60,7 @@ geany_include_HEADERS = \
 	encodings.h \
 	filetypes.h \
 	geany.h \
+	gtkcompat.h \
 	highlighting.h \
 	keybindings.h \
 	msgwindow.h \


Modified: src/build.c
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -61,6 +61,7 @@
 #include "win32.h"
 #include "toolbar.h"
 #include "geanymenubuttonaction.h"
+#include "gtkcompat.h"
 
 /* g_spawn_async_with_pipes doesn't work on Windows */
 #ifdef G_OS_WIN32
@@ -1922,7 +1923,7 @@ static void on_label_button_clicked(GtkWidget *wid, gpointer user_data)
 	const gchar *old = gtk_button_get_label(GTK_BUTTON(wid));
 	gchar *str;
 
-	if (GTK_WIDGET_TOPLEVEL(top_level) && GTK_IS_WINDOW(top_level))
+	if (gtk_widget_is_toplevel(top_level) && GTK_IS_WINDOW(top_level))
 		str = dialogs_show_input(_("Set menu item label"), GTK_WINDOW(top_level), NULL, old);
 	else
 		str = dialogs_show_input(_("Set menu item label"), NULL, NULL, old);


Modified: src/callbacks.c
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -65,6 +65,7 @@
 #include "toolbar.h"
 #include "highlighting.h"
 #include "pluginutils.h"
+#include "gtkcompat.h"
 
 
 #ifdef HAVE_VTE
@@ -1811,7 +1812,7 @@ G_MODULE_EXPORT void on_back_activate(GtkMenuItem *menuitem, gpointer user_data)
 
 G_MODULE_EXPORT gboolean on_motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
 {
-	if (prefs.auto_focus && ! GTK_WIDGET_HAS_FOCUS(widget))
+	if (prefs.auto_focus && ! gtk_widget_has_focus(widget))
 		gtk_widget_grab_focus(widget);
 
 	return FALSE;


Modified: src/dialogs.c
25 files changed, 20 insertions(+), 5 deletions(-)
===================================================================
@@ -55,6 +55,7 @@
 #include "build.h"
 #include "main.h"
 #include "project.h"
+#include "gtkcompat.h"
 
 
 enum
@@ -319,7 +320,7 @@ static GtkWidget *add_file_open_extra_widget(GtkWidget *dialog)
 					(GtkAttachOptions) (0), 4, 5);
 	/* the ebox is for the tooltip, because gtk_combo_box can't show tooltips */
 	filetype_ebox = gtk_event_box_new();
-	filetype_combo = gtk_combo_box_new_text();
+	filetype_combo = gtk_combo_box_text_new();
 	gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(filetype_combo), 2);
 	gtk_widget_set_tooltip_text(filetype_ebox,
 		_("Explicitly defines a filetype for the file, if it would not be detected by filename extension.\nNote if you choose multiple files, they will all be opened with the chosen filetype."));
@@ -377,7 +378,7 @@ static GtkWidget *create_open_file_dialog(void)
 	gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), add_file_open_extra_widget(dialog));
 	filetype_combo = ui_lookup_widget(dialog, "filetype_combo");
 
-	gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo), _("Detect by file extension"));
+	gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(filetype_combo), _("Detect by file extension"));
 	/* add FileFilters(start with "All Files") */
 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),
 				filetypes_create_file_filter(filetypes[GEANY_FILETYPES_NONE]));
@@ -390,7 +391,7 @@ static GtkWidget *create_open_file_dialog(void)
 
 		if (G_UNLIKELY(ft->id == GEANY_FILETYPES_NONE))
 			continue;
-		gtk_combo_box_append_text(GTK_COMBO_BOX(filetype_combo), ft->title);
+		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(filetype_combo), ft->title);
 		gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filetypes_create_file_filter(ft));
 	}
 	gtk_combo_box_set_active(GTK_COMBO_BOX(filetype_combo), 0);
@@ -820,6 +821,20 @@ gboolean dialogs_show_unsaved_file(GeanyDocument *doc)
 
 
 #ifndef G_OS_WIN32
+/* Use GtkFontChooserDialog on GTK3.2 for consistency, and because
+ * GtkFontSelectionDialog is somewhat broken on 3.4 */
+#if GTK_CHECK_VERSION(3, 2, 0)
+#	undef GTK_FONT_SELECTION_DIALOG
+#	define GTK_FONT_SELECTION_DIALOG				GTK_FONT_CHOOSER_DIALOG
+
+#	define gtk_font_selection_dialog_new(title) \
+		gtk_font_chooser_dialog_new((title), NULL)
+#	define gtk_font_selection_dialog_get_font_name(dlg) \
+		gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dlg))
+#	define gtk_font_selection_dialog_set_font_name(dlg, font) \
+		gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dlg), (font))
+#endif
+
 static void
 on_font_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
 {
@@ -926,7 +941,7 @@ void dialogs_show_open_font()
 		if (persistent)
 		{
 			GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(dialog), "combo");
-			ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(combo), str, 0);
+			ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(combo), str, 0);
 		}
 		input_cb(str);
 	}
@@ -950,7 +965,7 @@ static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox,
 
 	if (persistent)	/* remember previous entry text in a combo box */
 	{
-		GtkWidget *combo = gtk_combo_box_entry_new_text();
+		GtkWidget *combo = gtk_combo_box_text_new_with_entry();
 
 		entry = gtk_bin_get_child(GTK_BIN(combo));
 		ui_entry_add_clear_icon(GTK_ENTRY(entry));


Modified: src/document.c
20 files changed, 20 insertions(+), 0 deletions(-)
===================================================================
@@ -2771,6 +2771,25 @@ const GdkColor *document_get_status_color(GeanyDocument *doc)
 		return NULL;
 	if (! document_status_styles[status].loaded)
 	{
+#if GTK_CHECK_VERSION(3, 0, 0)
+		GdkRGBA color;
+		GtkWidgetPath *path = gtk_widget_path_new();
+		GtkStyleContext *ctx = gtk_style_context_new();
+		gtk_widget_path_append_type(path, GTK_TYPE_WINDOW);
+		gtk_widget_path_append_type(path, GTK_TYPE_BOX);
+		gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
+		gtk_widget_path_append_type(path, GTK_TYPE_LABEL);
+		gtk_widget_path_iter_set_name(path, -1, document_status_styles[status].name);
+		gtk_style_context_set_screen(ctx, gtk_widget_get_screen(GTK_WIDGET(doc->editor->sci)));
+		gtk_style_context_set_path(ctx, path);
+		gtk_style_context_get_color(ctx, GTK_STATE_NORMAL, &color);
+		document_status_styles[status].color.red   = 0xffff * color.red;
+		document_status_styles[status].color.green = 0xffff * color.green;
+		document_status_styles[status].color.blue  = 0xffff * color.blue;
+		document_status_styles[status].loaded = TRUE;
+		gtk_widget_path_unref(path);
+		g_object_unref(ctx);
+#else
 		GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(doc->editor->sci));
 		gchar *path = g_strconcat("GeanyMainWindow.GtkHBox.GtkNotebook.",
 				document_status_styles[status].name, NULL);
@@ -2779,6 +2798,7 @@ const GdkColor *document_get_status_color(GeanyDocument *doc)
 		document_status_styles[status].color = style->fg[GTK_STATE_NORMAL];
 		document_status_styles[status].loaded = TRUE;
 		g_free(path);
+#endif
 	}
 	return &document_status_styles[status].color;
 }


Modified: src/editor.c
15 files changed, 14 insertions(+), 1 deletions(-)
===================================================================
@@ -60,6 +60,7 @@
 #include "projectprivate.h"
 #include "main.h"
 #include "highlighting.h"
+#include "gtkcompat.h"
 
 
 /* Note: use sciwrappers.h instead where possible.
@@ -192,7 +193,7 @@ static void on_snippet_keybinding_activate(gchar *key)
 	const gchar *s;
 	GHashTable *specials;
 
-	if (!doc || !GTK_WIDGET_HAS_FOCUS(doc->editor->sci))
+	if (!doc || !gtk_widget_has_focus(GTK_WIDGET(doc->editor->sci)))
 		return;
 
 	s = snippets_find_completion_by_name(doc->file_type->name, key);
@@ -4645,6 +4646,14 @@ static gboolean on_editor_expose_event(GtkWidget *widget, GdkEventExpose *event,
 }
 
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+static gboolean on_editor_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
+{
+	return on_editor_expose_event(widget, NULL, user_data);
+}
+#endif
+
+
 static void setup_sci_keys(ScintillaObject *sci)
 {
 	/* disable some Scintilla keybindings to be able to redefine them cleanly */
@@ -4768,7 +4777,11 @@ static ScintillaObject *create_new_sci(GeanyEditor *editor)
 		g_signal_connect(sci, "scroll-event", G_CALLBACK(on_editor_scroll_event), editor);
 		g_signal_connect(sci, "motion-notify-event", G_CALLBACK(on_motion_event), NULL);
 		g_signal_connect(sci, "focus-in-event", G_CALLBACK(on_editor_focus_in), editor);
+#if GTK_CHECK_VERSION(3, 0, 0)
+		g_signal_connect(sci, "draw", G_CALLBACK(on_editor_draw), editor);
+#else
 		g_signal_connect(sci, "expose-event", G_CALLBACK(on_editor_expose_event), editor);
+#endif
 	}
 	return sci;
 }


Modified: src/gb.c
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -29,6 +29,7 @@
 #include <signal.h>
 #include <unistd.h>
 #include <gdk-pixbuf/gdk-pixdata.h>
+#include "gtkcompat.h"
 
 #define MAX_PICS 10
 #define LOOP_DELAY 200000	/* micro seconds */
@@ -191,7 +192,7 @@ static GtkWidget *create_help_dialog(GtkWindow *parent)
 	okbutton1 = gtk_button_new_from_stock(GTK_STOCK_OK);
 	gtk_widget_show(okbutton1);
 	gtk_dialog_add_action_widget(GTK_DIALOG(help_dialog), okbutton1, GTK_RESPONSE_OK);
-	GTK_WIDGET_SET_FLAGS(okbutton1, GTK_CAN_DEFAULT);
+	gtk_widget_set_can_default(okbutton1, TRUE);
 
 	return help_dialog;
 }


Modified: src/geanywraplabel.c
99 files changed, 96 insertions(+), 3 deletions(-)
===================================================================
@@ -30,7 +30,6 @@
 #include "geanywraplabel.h"
 
 
-
 struct _GeanyWrapLabelClass
 {
 	GtkLabelClass parent_class;
@@ -49,9 +48,22 @@ struct _GeanyWrapLabel
 };
 
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+static gboolean geany_wrap_label_draw(GtkWidget *widget, cairo_t *cr);
+static void geany_wrap_label_get_preferred_width (GtkWidget *widget,
+		gint *minimal_width, gint *natural_width);
+static void geany_wrap_label_get_preferred_height (GtkWidget *widget,
+		gint *minimal_height, gint *natural_height);
+static void geany_wrap_label_get_preferred_width_for_height (GtkWidget *widget,
+		gint height, gint *minimal_width, gint *natural_width);
+static void geany_wrap_label_get_preferred_height_for_width (GtkWidget *widget,
+		gint width, gint *minimal_height, gint *natural_height);
+static GtkSizeRequestMode geany_wrap_label_get_request_mode(GtkWidget *widget);
+#else
+static gboolean geany_wrap_label_expose		(GtkWidget *widget, GdkEventExpose *event);
 static void geany_wrap_label_size_request	(GtkWidget *widget, GtkRequisition *req);
+#endif
 static void geany_wrap_label_size_allocate	(GtkWidget *widget, GtkAllocation *alloc);
-static gboolean geany_wrap_label_expose		(GtkWidget *widget, GdkEventExpose *event);
 static void geany_wrap_label_set_wrap_width	(GtkWidget *widget, gint width);
 static void geany_wrap_label_label_notify	(GObject *object, GParamSpec *pspec, gpointer data);
 
@@ -62,9 +74,18 @@ static void geany_wrap_label_class_init(GeanyWrapLabelClass *klass)
 {
 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
 
-	widget_class->size_request = geany_wrap_label_size_request;
 	widget_class->size_allocate = geany_wrap_label_size_allocate;
+#if GTK_CHECK_VERSION(3, 0, 0)
+	widget_class->draw = geany_wrap_label_draw;
+	widget_class->get_preferred_width = geany_wrap_label_get_preferred_width;
+	widget_class->get_preferred_width_for_height = geany_wrap_label_get_preferred_width_for_height;
+	widget_class->get_preferred_height = geany_wrap_label_get_preferred_height;
+	widget_class->get_preferred_height_for_width = geany_wrap_label_get_preferred_height_for_width;
+	widget_class->get_request_mode = geany_wrap_label_get_request_mode;
+#else
+	widget_class->size_request = geany_wrap_label_size_request;
 	widget_class->expose_event = geany_wrap_label_expose;
+#endif
 
 	g_type_class_add_private(klass, sizeof (GeanyWrapLabelPrivate));
 }
@@ -119,6 +140,67 @@ static void geany_wrap_label_label_notify(GObject *object, GParamSpec *pspec, gp
 }
 
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+/* makes sure the layout is setup for rendering and chains to parent renderer */
+static gboolean geany_wrap_label_draw(GtkWidget *widget, cairo_t *cr)
+{
+	GeanyWrapLabel *self = GEANY_WRAP_LABEL(widget);
+	PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget));
+
+	pango_layout_set_width(layout, self->priv->wrap_width * PANGO_SCALE);
+	pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
+
+	return (* GTK_WIDGET_CLASS(geany_wrap_label_parent_class)->draw)(widget, cr);
+}
+
+
+static void geany_wrap_label_get_preferred_width (GtkWidget *widget,
+		gint *minimal_width, gint *natural_width)
+{
+	*minimal_width = *natural_width = 0;
+}
+
+
+static void geany_wrap_label_get_preferred_width_for_height (GtkWidget *widget,
+		gint height, gint *minimal_width, gint *natural_width)
+{
+	PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget));;
+
+	pango_layout_set_height(layout, height * PANGO_SCALE);
+	pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
+	pango_layout_get_pixel_size(layout, natural_width, NULL);
+
+	*minimal_width = 0;
+}
+
+
+static void geany_wrap_label_get_preferred_height (GtkWidget *widget,
+		gint *minimal_height, gint *natural_height)
+{
+	*minimal_height = *natural_height = GEANY_WRAP_LABEL(widget)->priv->wrap_height;
+}
+
+
+static void geany_wrap_label_get_preferred_height_for_width (GtkWidget *widget,
+		gint width, gint *minimal_height, gint *natural_height)
+{
+	PangoLayout *layout = gtk_label_get_layout(GTK_LABEL(widget));
+
+	pango_layout_set_width(layout, width * PANGO_SCALE);
+	pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
+	pango_layout_get_pixel_size(layout, NULL, natural_height);
+
+	*minimal_height = *natural_height;
+}
+
+
+static GtkSizeRequestMode geany_wrap_label_get_request_mode(GtkWidget *widget)
+{
+	return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+}
+
+#else /* GTK3 */
+
 /* makes sure the layout is setup for rendering and chains to parent renderer */
 static gboolean geany_wrap_label_expose(GtkWidget *widget, GdkEventExpose *event)
 {
@@ -139,6 +221,7 @@ static void geany_wrap_label_size_request(GtkWidget *widget, GtkRequisition *req
 	req->width = 0;
 	req->height = GEANY_WRAP_LABEL(widget)->priv->wrap_height;
 }
+#endif /* GTK3 */
 
 
 /* Sets the wrap width to the width allocated to us. */
@@ -147,6 +230,16 @@ static void geany_wrap_label_size_allocate(GtkWidget *widget, GtkAllocation *all
 	(* GTK_WIDGET_CLASS(geany_wrap_label_parent_class)->size_allocate)(widget, alloc);
 
 	geany_wrap_label_set_wrap_width(widget, alloc->width);
+
+#if GTK_CHECK_VERSION(3, 0, 0)
+{
+	/* ask the parent to recompute our size, because it seems GTK3 size
+	 * caching is too aggressive */
+	GtkWidget *parent = gtk_widget_get_parent(widget);
+	if (GTK_IS_CONTAINER(parent))
+		gtk_container_check_resize(GTK_CONTAINER(parent));
+}
+#endif
 }
 
 


Modified: src/gtkcompat.h
128 files changed, 128 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,128 @@
+/*
+ *      gtkcompat.h - this file is part of Geany, a fast and lightweight IDE
+ *
+ *      Copyright 2012 Colomban Wendling <ban(at)herbesfolles(dot)org>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License along
+ *      with this program; if not, write to the Free Software Foundation, Inc.,
+ *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Compatibility macros to support older GTK+ versions */
+
+#ifndef GTK_COMPAT_H
+#define GTK_COMPAT_H
+
+#include <gtk/gtk.h>
+#if GTK_CHECK_VERSION(3, 0, 0)
+#	include <gdk/gdkkeysyms-compat.h>
+#endif
+
+G_BEGIN_DECLS
+
+
+/* GtkComboBoxText */
+/* This is actually available in GTK 2.24, but we expose GtkComboBoxText in the
+ * API so we don't want the type to change for no good reason (although this
+ * should probably be harmless since it's only a derivated type).  However, since
+ * a plugin needs to be rebuilt and tuned to work with GTK3 we don't mind that
+ * a type changes between the GTK2 and GTK3 version */
+#if ! GTK_CHECK_VERSION(3, 0, 0)
+/* undef those not to get warnings about redefinitions under GTK 2.24 */
+#	undef GTK_COMBO_BOX_TEXT
+#	undef GTK_COMBO_BOX_TEXT_CLASS
+#	undef GTK_COMBO_BOX_TEXT_GET_CLASS
+#	undef GTK_IS_COMBO_BOX_TEXT
+#	undef GTK_IS_COMBO_BOX_TEXT_CLASS
+#	undef GTK_TYPE_COMBO_BOX_TEXT
+
+#	define GTK_COMBO_BOX_TEXT					GTK_COMBO_BOX
+#	define GTK_COMBO_BOX_TEXT_CLASS				GTK_COMBO_BOX_CLASS
+#	define GTK_COMBO_BOX_TEXT_GET_CLASS			GTK_COMBO_BOX_GET_CLASS
+#	define GTK_IS_COMBO_BOX_TEXT				GTK_IS_COMBO_BOX
+#	define GTK_IS_COMBO_BOX_TEXT_CLASS			GTK_IS_COMBO_BOX_CLASS
+#	define GTK_TYPE_COMBO_BOX_TEXT				GTK_TYPE_COMBO_BOX
+#	define GtkComboBoxText						GtkComboBox
+#	define gtk_combo_box_text_new				gtk_combo_box_new_text
+#	define gtk_combo_box_text_new_with_entry	gtk_combo_box_entry_new_text
+#	define gtk_combo_box_text_append_text		gtk_combo_box_append_text
+#	define gtk_combo_box_text_insert_text		gtk_combo_box_insert_text
+#	define gtk_combo_box_text_prepend_text		gtk_combo_box_prepend_text
+#	define gtk_combo_box_text_remove			gtk_combo_box_remove_text
+#	define gtk_combo_box_text_get_active_text	gtk_combo_box_get_active_text
+#endif
+
+/* GtkDialog */
+/* GTK 2.22 deprecated dialog separators and 3.0 removed them
+ * We keep those however in case 2.16 has separators by default */
+#if GTK_CHECK_VERSION(3, 0, 0)
+#	define gtk_dialog_set_has_separator(dialog, setting)	/* nothing */
+#	define GTK_DIALOG_NO_SEPARATOR							0
+#endif
+
+/* GtkWidget */
+#if ! GTK_CHECK_VERSION(2, 18, 0)
+#	define compat_widget_set_flag(widget, flag, enable) \
+		((enable) ? GTK_WIDGET_SET_FLAGS((widget), (flag)) : GTK_WIDGET_UNSET_FLAGS((widget), (flag)))
+#	define gtk_widget_set_can_default(widget, can_default) \
+		compat_widget_set_flag((widget), GTK_CAN_DEFAULT, (can_default))
+#	define gtk_widget_is_toplevel(widget)		GTK_WIDGET_TOPLEVEL(widget)
+#	define gtk_widget_is_sensitive(widget)		GTK_WIDGET_IS_SENSITIVE(widget)
+#	define gtk_widget_has_focus(widget)			GTK_WIDGET_HAS_FOCUS(widget)
+#	define gtk_widget_get_sensitive(widget)		GTK_WIDGET_SENSITIVE(widget)
+#	define gtk_widget_set_has_window(widget, has_window) \
+		compat_widget_set_flag((widget), GTK_NO_WINDOW, !(has_window))
+#	define gtk_widget_set_can_focus(widget, can_focus) \
+		compat_widget_set_flag((widget), GTK_CAN_FOCUS, (can_focus))
+#endif
+#if ! GTK_CHECK_VERSION(2, 20, 0)
+#	define gtk_widget_get_mapped(widget)	GTK_WIDGET_MAPPED(widget)
+#endif
+#if ! GTK_CHECK_VERSION(3, 0, 0)
+#	define gtk_widget_get_allocated_height(widget)	(((GtkWidget *) (widget))->allocation.height)
+#	define gtk_widget_get_allocated_width(widget)	(((GtkWidget *) (widget))->allocation.width)
+#endif
+
+
+/* Mappings below only prevent some deprecation warnings on GTK3 for things
+ * that didn't exist on GTK2.  That's not future-proof. */
+#if GTK_CHECK_VERSION(3, 0, 0)
+/* Gtk[VH]Box */
+#	define compat_gtk_box_new(orientation, homogeneous, spacing) \
+		g_object_new(GTK_TYPE_BOX, \
+					 "orientation", (orientation), \
+					 "homogeneous", (homogeneous), \
+					 "spacing", (spacing), \
+					 NULL)
+#	define gtk_vbox_new(homogeneous, spacing) \
+		compat_gtk_box_new(GTK_ORIENTATION_VERTICAL, (homogeneous), (spacing))
+#	define gtk_hbox_new(homogeneous, spacing) \
+		compat_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, (homogeneous), (spacing))
+/* Gtk[VH]ButtonBox */
+#	define gtk_vbutton_box_new()	gtk_button_box_new(GTK_ORIENTATION_VERTICAL)
+#	define gtk_hbutton_box_new()	gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL)
+/* Gtk[VH]Separator */
+#	define gtk_vseparator_new()	gtk_separator_new(GTK_ORIENTATION_VERTICAL)
+#	define gtk_hseparator_new()	gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
+/* Gtk[VH]Paned */
+#	define gtk_vpaned_new()	gtk_paned_new(GTK_ORIENTATION_VERTICAL)
+#	define gtk_hpaned_new()	gtk_paned_new(GTK_ORIENTATION_HORIZONTAL)
+/* Gtk[VH]Scrollbar */
+#	define gtk_vscrollbar_new(adj)	gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, (adj))
+#	define gtk_hscrollbar_new(adj)	gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, (adj))
+#endif
+
+
+G_END_DECLS
+
+#endif /* GTK_COMPAT_H */


Modified: src/keybindings.c
23 files changed, 18 insertions(+), 5 deletions(-)
===================================================================
@@ -56,6 +56,7 @@
 #include "geanywraplabel.h"
 #include "main.h"
 #include "search.h"
+#include "gtkcompat.h"
 #ifdef HAVE_VTE
 # include "vte.h"
 #endif
@@ -1072,12 +1073,20 @@ static gboolean check_menu_key(GeanyDocument *doc, guint keyval, guint state, gu
 static gboolean on_menu_expose_event(GtkWidget *widget, GdkEventExpose *event,
 		gpointer user_data)
 {
-	if (!GTK_WIDGET_SENSITIVE(widget))
+	if (!gtk_widget_get_sensitive(widget))
 		gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
 	return FALSE;
 }
 
 
+#if GTK_CHECK_VERSION(3, 0, 0)
+static gboolean on_menu_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
+{
+	return on_menu_expose_event(widget, NULL, user_data);
+}
+#endif
+
+
 static gboolean set_sensitive(gpointer widget)
 {
 	gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
@@ -1122,7 +1131,11 @@ static gboolean check_vte(GdkModifierType state, guint keyval)
 		/* make the menubar sensitive before it is redrawn */
 		static gboolean connected = FALSE;
 		if (!connected)
+#if GTK_CHECK_VERSION(3, 0, 0)
+			g_signal_connect(widget, "draw", G_CALLBACK(on_menu_draw), NULL);
+#else
 			g_signal_connect(widget, "expose-event", G_CALLBACK(on_menu_expose_event), NULL);
+#endif
 	}
 
 	widget = main_widgets.editor_menu;
@@ -1508,7 +1521,7 @@ static gboolean cb_func_build_action(guint key_id)
 	if (doc == NULL)
 		return TRUE;
 
-	if (!GTK_WIDGET_IS_SENSITIVE(ui_lookup_widget(main_widgets.window, "menu_build1")))
+	if (!gtk_widget_is_sensitive(ui_lookup_widget(main_widgets.window, "menu_build1")))
 		return TRUE;
 
 	menu_items = build_get_menu_items(doc->file_type->id);
@@ -1548,7 +1561,7 @@ static gboolean cb_func_build_action(guint key_id)
 	/* Note: For Build menu items it's OK (at the moment) to assume they are in the correct
 	 * sensitive state, but some other menus don't update the sensitive status until
 	 * they are redrawn. */
-	if (item && GTK_WIDGET_IS_SENSITIVE(item))
+	if (item && gtk_widget_is_sensitive(item))
 		gtk_menu_item_activate(GTK_MENU_ITEM(item));
 	return TRUE;
 }
@@ -1631,7 +1644,7 @@ static gboolean cb_func_switch_action(guint key_id)
 			if (doc != NULL)
 			{
 				GtkWidget *sci = GTK_WIDGET(doc->editor->sci);
-				if (GTK_WIDGET_HAS_FOCUS(sci))
+				if (gtk_widget_has_focus(sci))
 					ui_update_statusbar(doc, -1);
 				else
 					gtk_widget_grab_focus(sci);
@@ -1861,7 +1874,7 @@ static gboolean cb_func_goto_action(guint key_id)
 				GtkWidget *wid = toolbar_get_widget_child_by_name("GotoEntry");
 
 				/* use toolbar item if shown & not in the drop down overflow menu */
-				if (wid && GTK_WIDGET_MAPPED(wid))
+				if (wid && gtk_widget_get_mapped(wid))
 				{
 					gtk_widget_grab_focus(wid);
 					return TRUE;


Modified: src/notebook.c
11 files changed, 6 insertions(+), 5 deletions(-)
===================================================================
@@ -38,6 +38,7 @@
 #include "utils.h"
 #include "keybindings.h"
 #include "main.h"
+#include "gtkcompat.h"
 
 #define GEANY_DND_NOTEBOOK_TAB_TYPE	"geany_dnd_notebook_tab"
 
@@ -376,11 +377,11 @@ static gboolean is_position_on_tab_bar(GtkNotebook *notebook, GdkEventButton *ev
 		case GTK_POS_TOP:
 		case GTK_POS_BOTTOM:
 		{
-			if (event->y >= 0 && event->y <= tab->allocation.height)
+			if (event->y >= 0 && event->y <= gtk_widget_get_allocated_height(tab))
 			{
 				if (! gtk_notebook_show_arrows(notebook) || (
 					x > scroll_arrow_hlength &&
-					x < nb->allocation.width - scroll_arrow_hlength))
+					x < gtk_widget_get_allocated_width(nb) - scroll_arrow_hlength))
 					return TRUE;
 			}
 			break;
@@ -388,11 +389,11 @@ static gboolean is_position_on_tab_bar(GtkNotebook *notebook, GdkEventButton *ev
 		case GTK_POS_LEFT:
 		case GTK_POS_RIGHT:
 		{
-			if (event->x >= 0 && event->x <= tab->allocation.width)
+			if (event->x >= 0 && event->x <= gtk_widget_get_allocated_width(tab))
 			{
 				if (! gtk_notebook_show_arrows(notebook) || (
 					y > scroll_arrow_vlength &&
-					y < nb->allocation.height - scroll_arrow_vlength))
+					y < gtk_widget_get_allocated_height(nb) - scroll_arrow_vlength))
 					return TRUE;
 			}
 		}
@@ -666,7 +667,7 @@ gint notebook_new_tab(GeanyDocument *this)
 	/* get button press events for the tab label and the space between it and
 	 * the close button, if any */
 	ebox = gtk_event_box_new();
-	GTK_WIDGET_SET_FLAGS(ebox, GTK_NO_WINDOW);
+	gtk_widget_set_has_window(ebox, FALSE);
 	g_signal_connect(ebox, "button-press-event", G_CALLBACK(notebook_tab_click), page);
 	/* focus the current document after clicking on a tab */
 	g_signal_connect_after(ebox, "button-release-event",


Modified: src/plugindata.h
12 files changed, 10 insertions(+), 2 deletions(-)
===================================================================
@@ -41,6 +41,7 @@
 
 #include "editor.h"	/* GeanyIndentType */
 #include "build.h"  /* GeanyBuildGroup, GeanyBuildSource, GeanyBuildCmdEntries enums */
+#include "gtkcompat.h"
 
 
 /** The Application Programming Interface (API) version, incremented
@@ -56,12 +57,19 @@
  */
 #define GEANY_API_VERSION 216
 
+/* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
+ * with GTK3-linked Geany leads to crash */
+#if GTK_CHECK_VERSION(3, 0, 0)
+#	define GEANY_ABI_SHIFT 8
+#else
+#	define GEANY_ABI_SHIFT 0
+#endif
 /** The Application Binary Interface (ABI) version, incremented whenever
  * existing fields in the plugin data types have to be changed or reordered.
  * Changing this forces all plugins to be recompiled before Geany can load them. */
 /* This should usually stay the same if fields are only appended, assuming only pointers to
  * structs and not structs themselves are declared by plugins. */
-#define GEANY_ABI_VERSION 69
+#define GEANY_ABI_VERSION (69 << GEANY_ABI_SHIFT)
 
 
 /** Defines a function to check the plugin is safe to load.
@@ -476,7 +484,7 @@
 	void		(*ui_widget_modify_font_from_string) (GtkWidget *widget, const gchar *str);
 	gboolean	(*ui_is_keyval_enter_or_return) (guint keyval);
 	gint		(*ui_get_gtk_settings_integer) (const gchar *property_name, gint default_value);
-	void		(*ui_combo_box_add_to_history) (GtkComboBoxEntry *combo_entry,
+	void		(*ui_combo_box_add_to_history) (GtkComboBoxText *combo_entry,
 				const gchar *text, gint history_len);
 	void		(*ui_menu_add_document_items_sorted) (GtkMenu *menu, struct GeanyDocument *active,
 				GCallback callback, GCompareFunc compare_func);


Modified: src/search.c
40 files changed, 20 insertions(+), 20 deletions(-)
===================================================================
@@ -41,6 +41,7 @@
 #include "keyfile.h"
 #include "stash.h"
 #include "toolbar.h"
+#include "gtkcompat.h"
 
 #include <unistd.h>
 #include <string.h>
@@ -455,7 +456,7 @@ static void create_find_dialog(void)
 	label = gtk_label_new_with_mnemonic(_("_Search for:"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
-	entry = gtk_combo_box_entry_new_text();
+	entry = gtk_combo_box_text_new_with_entry();
 	ui_entry_add_clear_icon(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry))));
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
 	gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry))), 50);
@@ -551,7 +552,7 @@ void search_show_find_dialog(void)
 	else
 	{
 		/* only set selection if the dialog is not already visible */
-		if (! GTK_WIDGET_VISIBLE(find_dlg.dialog) && sel)
+		if (! gtk_widget_get_visible(find_dlg.dialog) && sel)
 			gtk_entry_set_text(GTK_ENTRY(find_dlg.entry), sel);
 		gtk_widget_grab_focus(find_dlg.entry);
 		set_dialog_position(find_dlg.dialog, find_dlg.position);
@@ -617,14 +618,14 @@ static void create_replace_dialog(void)
 	label_replace = gtk_label_new_with_mnemonic(_("Replace wit_h:"));
 	gtk_misc_set_alignment(GTK_MISC(label_replace), 0, 0.5);
 
-	entry_find = gtk_combo_box_entry_new_text();
+	entry_find = gtk_combo_box_text_new_with_entry();
 	ui_entry_add_clear_icon(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_find))));
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label_find), entry_find);
 	gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_find))), 50);
 	ui_hookup_widget(replace_dlg.dialog, entry_find, "entry_find");
 	replace_dlg.find_entry = gtk_bin_get_child(GTK_BIN(entry_find));
 
-	entry_replace = gtk_combo_box_entry_new_text();
+	entry_replace = gtk_combo_box_text_new_with_entry();
 	ui_entry_add_clear_icon(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_replace))));
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label_replace), entry_replace);
 	gtk_entry_set_width_chars(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(entry_replace))), 50);
@@ -725,7 +726,7 @@ void search_show_replace_dialog(void)
 	else
 	{
 		/* only set selection if the dialog is not already visible */
-		if (! GTK_WIDGET_VISIBLE(replace_dlg.dialog) && sel)
+		if (! gtk_widget_get_visible(replace_dlg.dialog) && sel)
 			gtk_entry_set_text(GTK_ENTRY(replace_dlg.find_entry), sel);
 		if (sel != NULL) /* when we have a selection, reset the entry widget's background colour */
 			ui_set_search_entry_background(replace_dlg.find_entry, TRUE);
@@ -853,7 +854,7 @@ static void create_fif_dialog(void)
 	label = gtk_label_new_with_mnemonic(_("_Search for:"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
 
-	combo = gtk_combo_box_entry_new_text();
+	combo = gtk_combo_box_text_new_with_entry();
 	entry = gtk_bin_get_child(GTK_BIN(combo));
 	ui_entry_add_clear_icon(GTK_ENTRY(entry));
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
@@ -877,7 +878,7 @@ static void create_fif_dialog(void)
 	ui_hookup_widget(fif_dlg.dialog, combo_files_mode, "combo_files_mode");
 	fif_dlg.files_mode_combo = combo_files_mode;
 
-	fcombo = gtk_combo_box_entry_new_text();
+	fcombo = gtk_combo_box_text_new_with_entry();
 	entry = gtk_bin_get_child(GTK_BIN(fcombo));
 	ui_entry_add_clear_icon(GTK_ENTRY(entry));
 	gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
@@ -896,7 +897,7 @@ static void create_fif_dialog(void)
 	label1 = gtk_label_new_with_mnemonic(_("_Directory:"));
 	gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
 
-	dir_combo = gtk_combo_box_entry_new_text();
+	dir_combo = gtk_combo_box_text_new_with_entry();
 	entry = gtk_bin_get_child(GTK_BIN(dir_combo));
 	ui_entry_add_clear_icon(GTK_ENTRY(entry));
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label1), entry);
@@ -914,11 +915,11 @@ static void create_fif_dialog(void)
 	label2 = gtk_label_new_with_mnemonic(_("E_ncoding:"));
 	gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
 
-	e_combo = gtk_combo_box_new_text();
+	e_combo = gtk_combo_box_text_new();
 	for (i = 0; i < GEANY_ENCODINGS_MAX; i++)
 	{
 		encoding_string = encodings_to_string(&encodings[i]);
-		gtk_combo_box_append_text(GTK_COMBO_BOX(e_combo), encoding_string);
+		gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(e_combo), encoding_string);
 		g_free(encoding_string);
 	}
 	gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(e_combo), 3);
@@ -1024,7 +1025,7 @@ void search_show_find_in_files_dialog(const gchar *dir)
 	stash_group_display(fif_prefs, fif_dlg.dialog);
 
 	/* only set selection if the dialog is not already visible, or has just been created */
-	if (doc && ! sel && ! GTK_WIDGET_VISIBLE(fif_dlg.dialog))
+	if (doc && ! sel && ! gtk_widget_get_visible(fif_dlg.dialog))
 		sel = editor_get_default_selection(doc->editor, search_prefs.use_current_word, NULL);
 
 	entry = gtk_bin_get_child(GTK_BIN(fif_dlg.search_combo));
@@ -1036,7 +1037,7 @@ void search_show_find_in_files_dialog(const gchar *dir)
 	 * (in create_fif_dialog() it would fail if a project is opened after dialog creation) */
 	if (app->project != NULL && NZV(app->project->base_path))
 	{
-		ui_combo_box_prepend_text_once(GTK_COMBO_BOX(fif_dlg.dir_combo),
+		ui_combo_box_prepend_text_once(GTK_COMBO_BOX_TEXT(fif_dlg.dir_combo),
 			app->project->base_path);
 	}
 
@@ -1055,8 +1056,7 @@ void search_show_find_in_files_dialog(const gchar *dir)
 			if (doc == last_doc && cur_dir && utils_str_equal(cur_dir, last_cur_dir))
 			{
 				/* in case the user now wants the current directory, add it to history */
-				ui_combo_box_add_to_history(
-					GTK_COMBO_BOX_ENTRY(fif_dlg.dir_combo), cur_dir, 0);
+				ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(fif_dlg.dir_combo), cur_dir, 0);
 				SETPTR(cur_dir, NULL);
 			}
 			else
@@ -1241,7 +1241,7 @@ gint search_mark_all(GeanyDocument *doc, const gchar *search_text, gint flags)
 			if (! utils_str_replace_escape(search_data.text, FALSE))
 				goto fail;
 		}
-		ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(user_data), search_data.original_text, 0);
+		ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(user_data), search_data.original_text, 0);
 
 		switch (response)
 		{
@@ -1378,9 +1378,9 @@ static void replace_in_session(GeanyDocument *doc,
 			goto fail;
 	}
 
-	ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(
+	ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(
 		gtk_widget_get_parent(replace_dlg.find_entry)), original_find, 0);
-	ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(
+	ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(
 		gtk_widget_get_parent(replace_dlg.replace_entry)), original_replace, 0);
 
 	switch (response)
@@ -1520,9 +1520,9 @@ static GString *get_grep_options(void)
 
 			if (search_find_in_files(search_text, locale_dir, opts->str, enc))
 			{
-				ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(search_combo), search_text, 0);
-				ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(fif_dlg.files_combo), NULL, 0);
-				ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(dir_combo), utf8_dir, 0);
+				ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(search_combo), search_text, 0);
+				ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(fif_dlg.files_combo), NULL, 0);
+				ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(dir_combo), utf8_dir, 0);
 				gtk_widget_hide(fif_dlg.dialog);
 			}
 			g_free(locale_dir);


Modified: src/sidebar.c
8 files changed, 8 insertions(+), 0 deletions(-)
===================================================================
@@ -588,16 +588,24 @@ void sidebar_add_common_menu_items(GtkMenu *menu)
 
 	item = gtk_check_menu_item_new_with_mnemonic(_("Show S_ymbol List"));
 	gtk_container_add(GTK_CONTAINER(menu), item);
+#if GTK_CHECK_VERSION(3, 0, 0)
+	g_signal_connect(item, "draw", G_CALLBACK(on_sidebar_display_symbol_list_show), NULL);
+#else
 	g_signal_connect(item, "expose-event",
 			G_CALLBACK(on_sidebar_display_symbol_list_show), NULL);
+#endif
 	gtk_widget_show(item);
 	g_signal_connect(item, "activate",
 			G_CALLBACK(on_list_symbol_activate), NULL);
 
 	item = gtk_check_menu_item_new_with_mnemonic(_("Show _Document List"));
 	gtk_container_add(GTK_CONTAINER(menu), item);
+#if GTK_CHECK_VERSION(3, 0, 0)
+	g_signal_connect(item, "draw", G_CALLBACK(on_sidebar_display_open_files_show), NULL);
+#else
 	g_signal_connect(item, "expose-event",
 			G_CALLBACK(on_sidebar_display_open_files_show), NULL);
+#endif
 	gtk_widget_show(item);
 	g_signal_connect(item, "activate",
 			G_CALLBACK(on_list_document_activate), NULL);


Modified: src/socket.c
10 files changed, 8 insertions(+), 2 deletions(-)
===================================================================
@@ -663,12 +663,18 @@ gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpoint
 	if (popup)
 	{
 #ifdef GDK_WINDOWING_X11
+		GdkWindow *x11_window = gtk_widget_get_window(window);
+
 		/* Set the proper interaction time on the window. This seems necessary to make
 		 * gtk_window_present() really bring the main window into the foreground on some
 		 * window managers like Gnome's metacity.
 		 * Code taken from Gedit. */
-		gdk_x11_window_set_user_time(gtk_widget_get_window(window),
-			gdk_x11_get_server_time(gtk_widget_get_window(window)));
+#	if GTK_CHECK_VERSION(3, 0, 0)
+		if (GDK_IS_X11_WINDOW(x11_window))
+#	endif
+		{
+			gdk_x11_window_set_user_time(x11_window, gdk_x11_get_server_time(x11_window));
+		}
 #endif
 		gtk_window_present(GTK_WINDOW(window));
 #ifdef G_OS_WIN32


Modified: src/stash.c
24 files changed, 22 insertions(+), 2 deletions(-)
===================================================================
@@ -85,6 +85,26 @@
 #include "stash.h"
 
 
+/* GTK3 removed ComboBoxEntry, but we need a value to differentiate combo box with and
+ * without entries, and it must not collide with other GTypes */
+#ifdef GTK_TYPE_COMBO_BOX_ENTRY
+#	define TYPE_COMBO_BOX_ENTRY GTK_TYPE_COMBO_BOX_ENTRY
+#else /* !GTK_TYPE_COMBO_BOX_ENTRY */
+#	define TYPE_COMBO_BOX_ENTRY get_combo_box_entry_type()
+static GType get_combo_box_entry_type(void)
+{
+	static volatile gsize type = 0;
+	if (g_once_init_enter(&type))
+	{
+		GType g_type = g_type_register_static_simple(GTK_TYPE_COMBO_BOX, "dummy-combo-box-entry",
+				sizeof(GtkComboBoxClass), NULL, sizeof(GtkComboBox), NULL, G_TYPE_FLAG_ABSTRACT);
+		g_once_init_leave(&type, g_type);
+	}
+	return type;
+}
+#endif /* !GTK_TYPE_COMBO_BOX_ENTRY */
+
+
 struct StashPref
 {
 	GType setting_type;			/* e.g. G_TYPE_INT */
@@ -696,7 +716,7 @@ static void pref_action(PrefAction action, StashGroup *group, GtkWidget *owner)
 			handle_spin_button(widget, entry, action);
 		else if (entry->widget_type == GTK_TYPE_COMBO_BOX)
 			handle_combo_box(widget, entry, action);
-		else if (entry->widget_type == GTK_TYPE_COMBO_BOX_ENTRY)
+		else if (entry->widget_type == TYPE_COMBO_BOX_ENTRY)
 			handle_combo_box_entry(widget, entry, action);
 		else if (entry->widget_type == GTK_TYPE_ENTRY)
 			handle_entry(widget, entry, action);
@@ -861,7 +881,7 @@ void stash_group_add_combo_box_entry(StashGroup *group, gchar **setting,
 		const gchar *key_name, const gchar *default_value, StashWidgetID widget_id)
 {
 	add_widget_pref(group, G_TYPE_STRING, setting, key_name, (gpointer)default_value,
-		GTK_TYPE_COMBO_BOX_ENTRY, widget_id);
+		TYPE_COMBO_BOX_ENTRY, widget_id);
 }
 
 


Modified: src/toolbar.c
3 files changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -395,6 +395,9 @@ GtkWidget *toolbar_init(void)
 	gtk_ui_manager_insert_action_group(uim, group, 0);
 
 	toolbar = toolbar_reload(NULL);
+#if GTK_CHECK_VERSION(3, 0, 0)
+	gtk_style_context_add_class(gtk_widget_get_style_context(toolbar), "primary-toolbar");
+#endif
 
 	gtk_settings = gtk_widget_get_settings(GTK_WIDGET(toolbar));
 	if (gtk_settings != NULL)


Modified: src/ui_utils.c
43 files changed, 32 insertions(+), 11 deletions(-)
===================================================================
@@ -55,6 +55,7 @@
 #include "main.h"
 #include "stash.h"
 #include "keyfile.h"
+#include "gtkcompat.h"
 
 
 GeanyInterfacePrefs	interface_prefs;
@@ -1312,7 +1313,7 @@ GtkWidget *ui_dialog_vbox_new(GtkDialog *dialog)
 	GtkWidget *vbox = gtk_vbox_new(FALSE, 12);	/* need child vbox to set a separate border. */
 
 	gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
-	gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox);
+	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0);
 	return vbox;
 }
 
@@ -1465,7 +1466,7 @@ static gboolean tree_model_find_text(GtkTreeModel *model,
  * @param combo_entry .
  * @param text Text to add, or @c NULL for current entry text.
  * @param history_len Max number of items, or @c 0 for default. */
-void ui_combo_box_add_to_history(GtkComboBoxEntry *combo_entry,
+void ui_combo_box_add_to_history(GtkComboBoxText *combo_entry,
 		const gchar *text, gint history_len)
 {
 	GtkComboBox *combo = GTK_COMBO_BOX(combo_entry);
@@ -1484,7 +1485,7 @@ void ui_combo_box_add_to_history(GtkComboBoxEntry *combo_entry,
 	{
 		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 	}
-	gtk_combo_box_prepend_text(combo, text);
+	gtk_combo_box_text_prepend_text(combo_entry, text);
 
 	/* limit history */
 	path = gtk_tree_path_new_from_indices(history_len, -1);
@@ -1496,18 +1497,18 @@ void ui_combo_box_add_to_history(GtkComboBoxEntry *combo_entry,
 }
 
 
-/* Same as gtk_combo_box_prepend_text(), except that text is only prepended if it not already
+/* Same as gtk_combo_box_text_prepend_text(), except that text is only prepended if it not already
  * exists in the combo's model. */
-void ui_combo_box_prepend_text_once(GtkComboBox *combo, const gchar *text)
+void ui_combo_box_prepend_text_once(GtkComboBoxText *combo, const gchar *text)
 {
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 
-	model = gtk_combo_box_get_model(combo);
+	model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
 	if (tree_model_find_text(model, &iter, 0, text))
 		return;	/* don't prepend duplicate */
 
-	gtk_combo_box_prepend_text(combo, text);
+	gtk_combo_box_text_prepend_text(combo, text);
 }
 
 
@@ -1911,7 +1912,7 @@ void ui_swap_sidebar_pos(void)
 	g_object_unref(left);
 	g_object_unref(right);
 
-	gtk_paned_set_position(GTK_PANED(pane), pane->allocation.width
+	gtk_paned_set_position(GTK_PANED(pane), gtk_widget_get_allocated_width(pane)
 		- gtk_paned_get_position(GTK_PANED(pane)));
 }
 
@@ -2160,10 +2161,30 @@ void ui_init_builder(void)
 
 static void init_custom_style(void)
 {
+#if GTK_CHECK_VERSION(3, 0, 0)
+	gchar *css_file = g_build_filename(app->datadir, "geany.css", NULL);
+	GtkCssProvider *css = gtk_css_provider_new();
+	GError *error = NULL;
+
+	if (! gtk_css_provider_load_from_path(css, css_file, &error))
+	{
+		g_warning("Failed to load custom CSS: %s", error->message);
+		g_error_free(error);
+	}
+	else
+	{
+		gtk_style_context_add_provider_for_screen(gdk_screen_get_default(),
+			GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+	}
+
+	g_object_unref(css);
+	g_free(css_file);
+#else
 	gchar *gtkrc_file = g_build_filename(app->datadir, "geany.gtkrc", NULL);
 
 	gtk_rc_parse(gtkrc_file);
 	g_free(gtkrc_file);
+#endif
 }
 
 
@@ -2263,7 +2284,7 @@ static void on_auto_separator_item_show_hide(GtkWidget *widget, gpointer user_da
 {
 	GeanyAutoSeparator *autosep = user_data;
 
-	if (GTK_WIDGET_VISIBLE(widget))
+	if (gtk_widget_get_visible(widget))
 		autosep->show_count++;
 	else
 		autosep->show_count--;
@@ -2277,7 +2298,7 @@ static void on_auto_separator_item_destroy(GtkWidget *widget, gpointer user_data
 
 	autosep->item_count--;
 	autosep->item_count = MAX(autosep->item_count, 0);
-	/* GTK_WIDGET_VISIBLE won't work now the widget is being destroyed,
+	/* gtk_widget_get_visible() won't work now the widget is being destroyed,
 	 * so assume widget was visible */
 	autosep->show_count--;
 	autosep->show_count = MAX(autosep->item_count, 0);
@@ -2296,7 +2317,7 @@ void ui_auto_separator_add_ref(GeanyAutoSeparator *autosep, GtkWidget *item)
 		g_signal_connect(autosep->widget, "destroy",
 			G_CALLBACK(gtk_widget_destroyed), &autosep->widget);
 
-	if (GTK_WIDGET_VISIBLE(item))
+	if (gtk_widget_get_visible(item))
 		autosep->show_count++;
 
 	autosep->item_count++;


Modified: src/ui_utils.h
6 files changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -22,6 +22,8 @@
 #ifndef GEANY_UI_UTILS_H
 #define GEANY_UI_UTILS_H 1
 
+#include "gtkcompat.h"
+
 G_BEGIN_DECLS
 
 
@@ -188,10 +190,10 @@
 
 void ui_hbutton_box_copy_layout(GtkButtonBox *master, GtkButtonBox *copy);
 
-void ui_combo_box_add_to_history(GtkComboBoxEntry *combo_entry,
+void ui_combo_box_add_to_history(GtkComboBoxText *combo_entry,
 		const gchar *text, gint history_len);
 
-void ui_combo_box_prepend_text_once(GtkComboBox *combo, const gchar *text);
+void ui_combo_box_prepend_text_once(GtkComboBoxText *combo, const gchar *text);
 
 GtkWidget *ui_path_box_new(const gchar *title, GtkFileChooserAction action, GtkEntry *entry);
 


Modified: src/vte.c
13 files changed, 10 insertions(+), 3 deletions(-)
===================================================================
@@ -49,6 +49,7 @@
 #include "geanywraplabel.h"
 #include "editor.h"
 #include "sciwrappers.h"
+#include "gtkcompat.h"
 
 
 VteInfo vte_info;
@@ -200,8 +201,14 @@ void vte_init(void)
 	if (module == NULL)
 	{
 		gint i;
-		const gchar *sonames[] = {  "libvte.so", "libvte.so.4",
-									"libvte.so.8", "libvte.so.9", NULL };
+		const gchar *sonames[] = {
+#if GTK_CHECK_VERSION(3, 0, 0)
+			"libvte2_90.so", "libvte2_90.so.9",
+#else
+			"libvte.so", "libvte.so.4", "libvte.so.8", "libvte.so.9",
+#endif
+			NULL
+		};
 
 		for (i = 0; sonames[i] != NULL && module == NULL; i++)
 		{
@@ -253,7 +260,7 @@ static void create_vte(void)
 
 	vc->vte = vte = vf->vte_terminal_new();
 	scrollbar = gtk_vscrollbar_new(GTK_ADJUSTMENT(VTE_TERMINAL(vte)->adjustment));
-	GTK_WIDGET_UNSET_FLAGS(scrollbar, GTK_CAN_FOCUS);
+	gtk_widget_set_can_focus(scrollbar, FALSE);
 
 	/* create menu now so copy/paste shortcuts work */
 	vc->menu = vte_create_popup_menu();



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list