summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorJohannes Schmid <jhs@gnome.org>2009-10-28 10:57:46 +0100
committerJohannes Schmid <jhs@gnome.org>2009-10-28 10:57:46 +0100
commitc229306a18f6453c144397bfbbf2284afa9731eb (patch)
treefd37ba747b10ec03b968762f01386ab0d7b926c3 /gtk
parent249be999a6699752980a5e16e45b45c4db18dabf (diff)
parent4ff709c24b8d4b3e26b3d513fde0676e9c43f897 (diff)
downloadgtk+-c229306a18f6453c144397bfbbf2284afa9731eb.tar.gz
Merge branch 'master' into toolpalette
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am66
-rwxr-xr-xgtk/compose-parse.py47
-rw-r--r--gtk/gtk.h8
-rw-r--r--gtk/gtk.symbols78
-rw-r--r--gtk/gtkaboutdialog.c87
-rw-r--r--gtk/gtkaboutdialog.h17
-rw-r--r--gtk/gtkaccelgroup.c32
-rw-r--r--gtk/gtkaccelgroup.h26
-rw-r--r--gtk/gtkaccessible.c7
-rw-r--r--gtk/gtkactivatable.c1
-rw-r--r--gtk/gtkassistant.c35
-rw-r--r--gtk/gtkbuilderparser.c13
-rw-r--r--gtk/gtkbutton.h4
-rw-r--r--gtk/gtkcelleditable.c29
-rw-r--r--gtk/gtkcellrenderer.c215
-rw-r--r--gtk/gtkcellrenderer.h23
-rw-r--r--gtk/gtkcellrendereraccel.c5
-rw-r--r--gtk/gtkcellrendererspin.c19
-rw-r--r--gtk/gtkcellrendererspinner.c389
-rw-r--r--gtk/gtkcellrendererspinner.h67
-rw-r--r--gtk/gtkcellrenderertoggle.c43
-rw-r--r--gtk/gtkcellrenderertoggle.h20
-rw-r--r--gtk/gtkcellview.c2
-rw-r--r--gtk/gtkclist.c14
-rw-r--r--gtk/gtkcombo.c4
-rw-r--r--gtk/gtkcombobox.c104
-rw-r--r--gtk/gtkcomboboxentry.c5
-rw-r--r--gtk/gtkcurve.c2
-rw-r--r--gtk/gtkcurve.h16
-rw-r--r--gtk/gtkcustompaperunixdialog.c9
-rw-r--r--gtk/gtkcustompaperunixdialog.h4
-rw-r--r--gtk/gtkdialog.c43
-rw-r--r--gtk/gtkdialog.h2
-rw-r--r--gtk/gtkdnd-quartz.c134
-rw-r--r--gtk/gtkentry.c228
-rw-r--r--gtk/gtkentrybuffer.c50
-rw-r--r--gtk/gtkentrybuffer.h6
-rw-r--r--gtk/gtkfilechooser.c62
-rw-r--r--gtk/gtkfilechooser.h4
-rw-r--r--gtk/gtkfilechooserbutton.c13
-rw-r--r--gtk/gtkfilechooserdefault.c3144
-rw-r--r--gtk/gtkfilechooserdialog.c9
-rw-r--r--gtk/gtkfilechooserprivate.h69
-rw-r--r--gtk/gtkfilechooserutils.c3
-rw-r--r--gtk/gtkfilechooserutils.h3
-rw-r--r--gtk/gtkfilesel.c12
-rw-r--r--gtk/gtkfilesystemmodel.c2998
-rw-r--r--gtk/gtkfilesystemmodel.h71
-rw-r--r--gtk/gtkgamma.c2
-rw-r--r--gtk/gtkgamma.h16
-rw-r--r--gtk/gtkiconfactory.c481
-rw-r--r--gtk/gtkicontheme.c2
-rw-r--r--gtk/gtkiconview.c139
-rw-r--r--gtk/gtkiconview.h3
-rw-r--r--gtk/gtkimage.c21
-rw-r--r--gtk/gtkimagemenuitem.c1
-rw-r--r--gtk/gtkimcontextsimple.c5
-rw-r--r--gtk/gtkimcontextsimpleseqs.h91
-rw-r--r--gtk/gtkimmodule.c10
-rw-r--r--gtk/gtkimmulticontext.c75
-rw-r--r--gtk/gtkinfobar.c5
-rw-r--r--gtk/gtkinputdialog.h8
-rw-r--r--gtk/gtkkeyhash.c6
-rw-r--r--gtk/gtklabel.c28
-rw-r--r--gtk/gtkliststore.c22
-rw-r--r--gtk/gtkmain.c27
-rw-r--r--gtk/gtkmain.h4
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtkmenu.c6
-rw-r--r--gtk/gtkmountoperation-x11.c11
-rw-r--r--gtk/gtkmountoperation.c19
-rw-r--r--gtk/gtknotebook.c15
-rw-r--r--gtk/gtknotebook.h2
-rw-r--r--gtk/gtkpagesetupunixdialog.c22
-rw-r--r--gtk/gtkprintbackend.c164
-rw-r--r--gtk/gtkprintbackend.h16
-rw-r--r--gtk/gtkprintcontext.c16
-rw-r--r--gtk/gtkprinteroption.c18
-rw-r--r--gtk/gtkprinteroption.h41
-rw-r--r--gtk/gtkprinteroptionwidget.c6
-rw-r--r--gtk/gtkprintoperation-unix.c56
-rw-r--r--gtk/gtkprintoperation-win32.c5
-rw-r--r--gtk/gtkprintoperation.c254
-rw-r--r--gtk/gtkprintoperation.h1
-rw-r--r--gtk/gtkprintsettings.c10
-rw-r--r--gtk/gtkprintunixdialog.c268
-rw-r--r--gtk/gtkprivate.h9
-rw-r--r--gtk/gtkradiobutton.c4
-rw-r--r--gtk/gtkrange.c46
-rw-r--r--gtk/gtkrange.h4
-rw-r--r--gtk/gtkrc.c16
-rw-r--r--gtk/gtkrc.key.mac240
-rw-r--r--gtk/gtkscale.c3
-rw-r--r--gtk/gtksearchenginetracker.c95
-rw-r--r--gtk/gtkselection.c2
-rw-r--r--gtk/gtksettings.c59
-rw-r--r--gtk/gtksizegroup.c8
-rw-r--r--gtk/gtksocket.c27
-rw-r--r--gtk/gtkspinner.c627
-rw-r--r--gtk/gtkspinner.h65
-rw-r--r--gtk/gtkstatusbar.c35
-rw-r--r--gtk/gtkstatusicon.c26
-rw-r--r--gtk/gtkstock.c1
-rw-r--r--gtk/gtkstyle.c118
-rw-r--r--gtk/gtkstyle.h18
-rw-r--r--gtk/gtktestutils.c2
-rw-r--r--gtk/gtktextbuffer.c11
-rw-r--r--gtk/gtktextlayout.c63
-rw-r--r--gtk/gtktextview.c35
-rw-r--r--gtk/gtktoolbutton.c10
-rw-r--r--gtk/gtktoolitem.c16
-rw-r--r--gtk/gtktoolshell.c1
-rw-r--r--gtk/gtktooltip.c60
-rw-r--r--gtk/gtktooltip.h3
-rw-r--r--gtk/gtktreemodelfilter.c349
-rw-r--r--gtk/gtktreemodelsort.c171
-rw-r--r--gtk/gtktreeprivate.h14
-rw-r--r--gtk/gtktreestore.c40
-rw-r--r--gtk/gtktreeview.c402
-rw-r--r--gtk/gtktreeviewcolumn.c34
-rw-r--r--gtk/gtktypeutils.c4
-rw-r--r--gtk/gtkviewport.c18
-rw-r--r--gtk/gtkviewport.h1
-rw-r--r--gtk/gtkwidget.c600
-rw-r--r--gtk/gtkwidget.h57
-rw-r--r--gtk/gtkwindow.c31
-rw-r--r--gtk/makefile.msc.in4
-rw-r--r--gtk/tests/Makefile.am12
-rw-r--r--gtk/tests/builder.c12
-rw-r--r--gtk/tests/defaultvalue.c9
-rw-r--r--gtk/tests/expander.c94
-rw-r--r--gtk/tests/filtermodel.c3000
-rw-r--r--gtk/tests/liststore.c80
-rw-r--r--gtk/tests/textbuffer.c37
-rw-r--r--gtk/tests/treestore.c80
-rw-r--r--gtk/tests/treeview-scrolling.c129
-rw-r--r--gtk/tests/treeview.c165
-rw-r--r--gtk/updateiconcache.c22
138 files changed, 11429 insertions, 5659 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index f34ba852d5..4b1ceded26 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -178,6 +178,7 @@ gtk_public_h_sources = \
gtkcellrendererpixbuf.h \
gtkcellrendererprogress.h \
gtkcellrendererspin.h \
+ gtkcellrendererspinner.h\
gtkcellrenderertext.h \
gtkcellrenderertoggle.h \
gtkcellview.h \
@@ -190,7 +191,6 @@ gtk_public_h_sources = \
gtkcombobox.h \
gtkcomboboxentry.h \
gtkcontainer.h \
- gtkcurve.h \
gtkdebug.h \
gtkdialog.h \
gtkdnd.h \
@@ -211,7 +211,6 @@ gtk_public_h_sources = \
gtkfontbutton.h \
gtkfontsel.h \
gtkframe.h \
- gtkgamma.h \
gtkgc.h \
gtkhandlebox.h \
gtkhbbox.h \
@@ -232,7 +231,6 @@ gtk_public_h_sources = \
gtkimmodule.h \
gtkimmulticontext.h \
gtkinfobar.h \
- gtkinputdialog.h \
gtkinvisible.h \
gtkitem.h \
gtklabel.h \
@@ -289,6 +287,7 @@ gtk_public_h_sources = \
gtksizegroup.h \
gtksocket.h \
gtkspinbutton.h \
+ gtkspinner.h \
gtkstatusbar.h \
gtkstatusicon.h \
gtkstock.h \
@@ -435,6 +434,7 @@ gtk_base_c_sources = \
gtkcellrendererpixbuf.c \
gtkcellrendererprogress.c \
gtkcellrendererspin.c \
+ gtkcellrendererspinner.c\
gtkcellrenderertext.c \
gtkcellrenderertoggle.c \
gtkcellview.c \
@@ -446,7 +446,6 @@ gtk_base_c_sources = \
gtkcombobox.c \
gtkcomboboxentry.c \
gtkcontainer.c \
- gtkcurve.c \
gtkdialog.c \
gtkdrawingarea.c \
gtkeditable.c \
@@ -471,7 +470,6 @@ gtk_base_c_sources = \
gtkfontbutton.c \
gtkfontsel.c \
gtkframe.c \
- gtkgamma.c \
gtkgc.c \
gtkhandlebox.c \
gtkhbbox.c \
@@ -559,6 +557,7 @@ gtk_base_c_sources = \
gtkshow.c \
gtksocket.c \
gtkspinbutton.c \
+ gtkspinner.c \
gtkstatusbar.c \
gtkstatusicon.c \
gtkstock.c \
@@ -634,7 +633,10 @@ gtk_public_h_sources += \
gtkclist.h \
gtkcombo.h \
gtkctree.h \
+ gtkcurve.h \
gtkfilesel.h \
+ gtkgamma.h \
+ gtkinputdialog.h \
gtkitemfactory.h \
gtklist.h \
gtklistitem.h \
@@ -650,7 +652,9 @@ gtk_base_c_sources += \
gtkclist.c \
gtkcombo.c \
gtkctree.c \
+ gtkcurve.c \
gtkfilesel.c \
+ gtkgamma.c \
gtkitemfactory.c \
gtklist.c \
gtklistitem.c \
@@ -915,8 +919,19 @@ if DISABLE_EXPLICIT_DEPS
$(SHELL) $(top_srcdir)/sanitize-la.sh $(DESTDIR)$(libdir)/$(gtktargetlib)
endif
+if USE_QUARTZ
+install-mac-key-theme:
+ $(mkinstalldirs) $(DESTDIR)$(datadir)/themes/Mac/gtk-2.0-key
+ $(INSTALL_DATA) $(srcdir)/gtkrc.key.mac $(DESTDIR)$(datadir)/themes/Mac/gtk-2.0-key/gtkrc
+uninstall-mac-key-theme:
+ rm -f $(DESTDIR)$(datadir)/themes/Mac/gtk-2.0-key/gtkrc
+else
+install-mac-key-theme:
+uninstall-mac-key-theme:
+endif
+
# Install a RC file for the default GTK+ theme, and key themes
-install-data-local: install-ms-lib install-def-file
+install-data-local: install-ms-lib install-def-file install-mac-key-theme
$(mkinstalldirs) $(DESTDIR)$(datadir)/themes/Raleigh/gtk-2.0
$(INSTALL_DATA) $(srcdir)/gtkrc.default $(DESTDIR)$(datadir)/themes/Raleigh/gtk-2.0/gtkrc
$(mkinstalldirs) $(DESTDIR)$(datadir)/themes/Default/gtk-2.0-key
@@ -924,7 +939,7 @@ install-data-local: install-ms-lib install-def-file
$(mkinstalldirs) $(DESTDIR)$(datadir)/themes/Emacs/gtk-2.0-key
$(INSTALL_DATA) $(srcdir)/gtkrc.key.emacs $(DESTDIR)$(datadir)/themes/Emacs/gtk-2.0-key/gtkrc
-uninstall-local: uninstall-ms-lib uninstall-def-file
+uninstall-local: uninstall-ms-lib uninstall-def-file uninstall-mac-key-theme
rm -f $(DESTDIR)$(datadir)/themes/Raleigh/gtk-2.0/gtkrc
rm -f $(DESTDIR)$(datadir)/themes/Default/gtk-2.0-key/gtkrc
rm -f $(DESTDIR)$(datadir)/themes/Emacs/gtk-2.0-key/gtkrc
@@ -951,8 +966,42 @@ LDADDS = \
bin_PROGRAMS = \
gtk-query-immodules-2.0 \
gtk-update-icon-cache
+
bin_SCRIPTS = gtk-builder-convert
+if OS_WIN32
+
+# Workaround for UAC silliness: programs with "update" in their name
+# are believed to be installers and require elevated privileges to be
+# used... Use a manifest file to tell Windows that
+# gtk-update-icon-cache.exe doesn't require any special privileges.
+
+GTK_UPDATE_ICON_CACHE_MANIFEST = gtk-update-icon-cache.exe.manifest
+
+bin_SCRIPTS += \
+ $(GTK_UPDATE_ICON_CACHE_MANIFEST)
+
+gtk-update-icon-cache.exe.manifest:
+ (echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' ; \
+ echo '<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">' ; \
+ echo ' <assemblyIdentity version="1.0.0.0"' ; \
+ echo ' processorArchitecture="'$(LIB_EXE_MACHINE_FLAG)'"' ; \
+ echo ' name="gtk-update-icon-cache.exe"' ; \
+ echo ' type="win32"/>' ; \
+ echo ' <!-- Identify the application security requirements. -->' ; \
+ echo ' <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">' ; \
+ echo ' <security>' ; \
+ echo ' <requestedPrivileges>' ; \
+ echo ' <requestedExecutionLevel' ; \
+ echo ' level="asInvoker"' ; \
+ echo ' uiAccess="false"/>' ; \
+ echo ' </requestedPrivileges>' ; \
+ echo ' </security>' ; \
+ echo ' </trustInfo>' ; \
+ echo '</assembly>' ) >$@
+
+endif
+
gtk_query_immodules_2_0_DEPENDENCIES = $(DEPS)
gtk_query_immodules_2_0_LDADD = $(LDADDS)
@@ -1271,7 +1320,7 @@ gtk_update_icon_cache_program = \
endif
gtkbuiltincache.h: @REBUILD@ stamp-icons
- $(MAKE) $(AM_MAKEFLAGS) gtk-update-icon-cache$(EXEEXT)
+ $(MAKE) $(AM_MAKEFLAGS) gtk-update-icon-cache$(EXEEXT) $(GTK_UPDATE_ICON_CACHE_MANIFEST)
$(gtk_update_icon_cache_program) --force --ignore-theme-index \
--source builtin_icons stock-icons > gtkbuiltincache.h.tmp && \
mv gtkbuiltincache.h.tmp gtkbuiltincache.h
@@ -1298,6 +1347,7 @@ EXTRA_DIST += \
gtkrc.default \
gtkrc.key.default \
gtkrc.key.emacs \
+ gtkrc.key.mac \
makefile.msc \
makefile.msc.in \
makegtkalias.pl \
diff --git a/gtk/compose-parse.py b/gtk/compose-parse.py
index dfa94925fd..2aa13569b9 100755
--- a/gtk/compose-parse.py
+++ b/gtk/compose-parse.py
@@ -425,30 +425,61 @@ except:
""" Look if there is a lookaside (supplementary) compose file in the current
directory, and if so, open, then merge with upstream Compose file.
"""
+xorg_compose_sequences_raw = []
+for seq in composefile.readlines():
+ xorg_compose_sequences_raw.append(seq)
+
try:
composefile_lookaside = open(FILENAME_COMPOSE_SUPPLEMENTARY, 'r')
+ for seq in composefile_lookaside.readlines():
+ xorg_compose_sequences_raw.append(seq)
except IOError, (errno, strerror):
- if not opt_quiet:
+ if opt_verbose:
print "I/O error(%s): %s" % (errno, strerror)
print "Did not find lookaside compose file. Continuing..."
except:
print "Unexpected error: ", sys.exc_info()[0]
sys.exit(-1)
-xorg_compose_sequences_raw = []
-for seq in composefile.readlines():
- xorg_compose_sequences_raw.append(seq)
-for seq in composefile_lookaside.readlines():
- xorg_compose_sequences_raw.append(seq)
-
""" Parse the compose file in xorg_compose_sequences"""
xorg_compose_sequences = []
xorg_compose_sequences_algorithmic = []
linenum_compose = 0
+comment_nest_depth = 0
for line in xorg_compose_sequences_raw:
linenum_compose += 1
line = line.strip()
- if line is "" or match("^XCOMM", line) or match("^#", line):
+ if match("^XCOMM", line) or match("^#", line):
+ continue
+
+ line = sub(r"\/\*([^\*]*|[\*][^/])\*\/", "", line)
+
+ comment_start = line.find("/*")
+
+ if comment_start >= 0:
+ if comment_nest_depth == 0:
+ line = line[:comment_start]
+ else:
+ line = ""
+
+ comment_nest_depth += 1
+ else:
+ comment_end = line.find("*/")
+
+ if comment_end >= 0:
+ comment_nest_depth -= 1
+
+ if comment_nest_depth < 0:
+ print "Invalid comment %(linenum_compose)d in %(filename)s: \
+ Closing '*/' without opening '/*'" % { "linenum_compose": linenum_compose, "filename": filename_compose }
+ exit(-1)
+
+ if comment_nest_depth > 0:
+ line = ""
+ else:
+ line = line[comment_end + 2:]
+
+ if line is "":
continue
#line = line[:-1]
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 2fd216fcc0..07952be6c6 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -59,6 +59,7 @@
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrendererprogress.h>
#include <gtk/gtkcellrendererspin.h>
+#include <gtk/gtkcellrendererspinner.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkcellrenderertoggle.h>
#include <gtk/gtkcellview.h>
@@ -71,7 +72,6 @@
#include <gtk/gtkcombobox.h>
#include <gtk/gtkcomboboxentry.h>
#include <gtk/gtkcontainer.h>
-#include <gtk/gtkcurve.h>
#include <gtk/gtkdebug.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkdnd.h>
@@ -92,7 +92,6 @@
#include <gtk/gtkfontbutton.h>
#include <gtk/gtkfontsel.h>
#include <gtk/gtkframe.h>
-#include <gtk/gtkgamma.h>
#include <gtk/gtkgc.h>
#include <gtk/gtkhandlebox.h>
#include <gtk/gtkhbbox.h>
@@ -112,7 +111,6 @@
#include <gtk/gtkimcontextsimple.h>
#include <gtk/gtkimmulticontext.h>
#include <gtk/gtkinfobar.h>
-#include <gtk/gtkinputdialog.h>
#include <gtk/gtkinvisible.h>
#include <gtk/gtkitem.h>
#include <gtk/gtklabel.h>
@@ -168,6 +166,7 @@
#include <gtk/gtksizegroup.h>
#include <gtk/gtksocket.h>
#include <gtk/gtkspinbutton.h>
+#include <gtk/gtkspinner.h>
#include <gtk/gtkstatusbar.h>
#include <gtk/gtkstatusicon.h>
#include <gtk/gtkstock.h>
@@ -226,7 +225,10 @@
#include <gtk/gtkclist.h>
#include <gtk/gtkcombo.h>
#include <gtk/gtkctree.h>
+#include <gtk/gtkcurve.h>
#include <gtk/gtkfilesel.h>
+#include <gtk/gtkgamma.h>
+#include <gtk/gtkinputdialog.h>
#include <gtk/gtkitemfactory.h>
#include <gtk/gtklist.h>
#include <gtk/gtklistitem.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index a53fb5abbf..214832753c 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -541,7 +541,9 @@ gtk_button_box_set_layout
#if IN_HEADER(__GTK_BUTTON_H__)
#if IN_FILE(__GTK_BUTTON_C__)
gtk_button_clicked
+#ifndef GTK_DISABLE_DEPRECATED
gtk_button_enter
+#endif
gtk_button_get_alignment
gtk_button_get_focus_on_click
gtk_button_get_image
@@ -551,13 +553,17 @@ gtk_button_get_relief
gtk_button_get_type G_GNUC_CONST
gtk_button_get_use_stock
gtk_button_get_use_underline
+#ifndef GTK_DISABLE_DEPRECATED
gtk_button_leave
+#endif
gtk_button_new
gtk_button_new_from_stock
gtk_button_new_with_label
gtk_button_new_with_mnemonic
+#ifndef GTK_DISABLE_DEPRECATED
gtk_button_pressed
gtk_button_released
+#endif
gtk_button_set_alignment
gtk_button_set_focus_on_click
gtk_button_set_image
@@ -624,11 +630,19 @@ gtk_cell_renderer_activate
#ifndef GTK_DISABLE_DEPRECATED
gtk_cell_renderer_editing_canceled
#endif
+gtk_cell_renderer_get_alignment
gtk_cell_renderer_get_fixed_size
+gtk_cell_renderer_get_padding
+gtk_cell_renderer_get_sensitive
gtk_cell_renderer_get_size
gtk_cell_renderer_get_type G_GNUC_CONST
+gtk_cell_renderer_get_visible
gtk_cell_renderer_render
+gtk_cell_renderer_set_alignment
gtk_cell_renderer_set_fixed_size
+gtk_cell_renderer_set_padding
+gtk_cell_renderer_set_sensitive
+gtk_cell_renderer_set_visible
gtk_cell_renderer_start_editing
gtk_cell_renderer_stop_editing
#endif
@@ -662,6 +676,13 @@ gtk_cell_renderer_spin_new
#endif
#endif
+#if IN_HEADER(__GTK_CELL_RENDERER_SPINNER_H__)
+#if IN_FILE(__GTK_CELL_RENDERER_SPINNER_C__)
+gtk_cell_renderer_spinner_get_type G_GNUC_CONST
+gtk_cell_renderer_spinner_new
+#endif
+#endif
+
#if IN_HEADER(__GTK_CELL_RENDERER_PROGRESS_H__)
#if IN_FILE(__GTK_CELL_RENDERER_PROGRESS_C__)
gtk_cell_renderer_progress_get_type G_GNUC_CONST
@@ -679,10 +700,12 @@ gtk_cell_renderer_text_set_fixed_height_from_font
#if IN_HEADER(__GTK_CELL_RENDERER_TOGGLE_H__)
#if IN_FILE(__GTK_CELL_RENDERER_TOGGLE_C__)
+gtk_cell_renderer_toggle_get_activatable
gtk_cell_renderer_toggle_get_active
gtk_cell_renderer_toggle_get_radio
gtk_cell_renderer_toggle_get_type G_GNUC_CONST
gtk_cell_renderer_toggle_new
+gtk_cell_renderer_toggle_set_activatable
gtk_cell_renderer_toggle_set_active
gtk_cell_renderer_toggle_set_radio
#endif
@@ -1088,6 +1111,7 @@ gtk_ctree_unselect_recursive
#if IN_HEADER(__GTK_CURVE_H__)
#if IN_FILE(__GTK_CURVE_C__)
+#ifndef GTK_DISABLE_DEPRECATED
gtk_curve_get_type G_GNUC_CONST
gtk_curve_get_vector
gtk_curve_new
@@ -1098,6 +1122,7 @@ gtk_curve_set_range
gtk_curve_set_vector
#endif
#endif
+#endif
#if IN_HEADER(__GTK_WINDOW_DECORATE_H__)
#if IN_FILE(__GTK_WINDOW_DECORATE_C__)
@@ -1116,6 +1141,7 @@ gtk_dialog_add_buttons G_GNUC_NULL_TERMINATED
gtk_dialog_get_action_area
gtk_dialog_get_content_area
gtk_dialog_get_has_separator
+gtk_dialog_get_widget_for_response
gtk_dialog_get_response_for_widget
gtk_dialog_get_type G_GNUC_CONST
gtk_dialog_new
@@ -1266,6 +1292,7 @@ gtk_paint_resize_grip
gtk_paint_shadow
gtk_paint_shadow_gap
gtk_paint_slider
+gtk_paint_spinner
gtk_paint_tab
gtk_paint_vline
gtk_border_new G_GNUC_MALLOC
@@ -1521,6 +1548,8 @@ gtk_file_chooser_get_select_multiple
gtk_file_chooser_get_show_hidden
gtk_file_chooser_set_do_overwrite_confirmation
gtk_file_chooser_get_do_overwrite_confirmation
+gtk_file_chooser_set_create_folders
+gtk_file_chooser_get_create_folders
gtk_file_chooser_get_type G_GNUC_CONST
gtk_file_chooser_get_uri
gtk_file_chooser_get_uris
@@ -1752,10 +1781,12 @@ gtk_frame_set_shadow_type
#if IN_HEADER(__GTK_GAMMA_CURVE_H__)
#if IN_FILE(__GTK_GAMMA_CURVE_C__)
+#ifndef GTK_DISABLE_DEPRECATED
gtk_gamma_curve_get_type G_GNUC_CONST
gtk_gamma_curve_new
#endif
#endif
+#endif
#if IN_HEADER(__GTK_GC_H__)
#if IN_FILE(__GTK_GC_C__)
@@ -1976,6 +2007,7 @@ gtk_icon_theme_set_search_path_utf8
gtk_icon_view_get_column_spacing
gtk_icon_view_get_columns
gtk_icon_view_get_cursor
+gtk_icon_view_get_item_padding
gtk_icon_view_get_item_width
gtk_icon_view_get_margin
gtk_icon_view_get_markup_column
@@ -2003,6 +2035,7 @@ gtk_icon_view_select_path
gtk_icon_view_set_column_spacing
gtk_icon_view_set_columns
gtk_icon_view_set_cursor
+gtk_icon_view_set_item_padding
gtk_icon_view_set_item_width
gtk_icon_view_set_margin
gtk_icon_view_set_markup_column
@@ -2405,10 +2438,12 @@ gtk_main_quit
#if IN_HEADER(__GTK_INPUTDIALOG_H__)
#if IN_FILE(__GTK_INPUTDIALOG_C__)
+#ifndef GTK_DISABLE_DEPRECATED
gtk_input_dialog_get_type G_GNUC_CONST
gtk_input_dialog_new
#endif
#endif
+#endif
#if IN_HEADER(__gtk_marshal_MARSHAL_H__)
#if IN_FILE(__gtk_marshal_MARSHAL_C__)
@@ -2605,7 +2640,9 @@ gtk_notebook_popup_enable
gtk_notebook_prepend_page
gtk_notebook_prepend_page_menu
gtk_notebook_prev_page
+#ifndef GTK_DISABLE_DEPRECATED
gtk_notebook_query_tab_label_packing
+#endif
gtk_notebook_remove_page
gtk_notebook_reorder_child
gtk_notebook_set_current_page
@@ -2621,7 +2658,9 @@ gtk_notebook_set_scrollable
gtk_notebook_set_show_border
gtk_notebook_set_show_tabs
gtk_notebook_set_tab_label
+#ifndef GTK_DISABLE_DEPRECATED
gtk_notebook_set_tab_label_packing
+#endif
gtk_notebook_set_tab_label_text
gtk_notebook_set_tab_pos
gtk_notebook_set_window_creation_hook
@@ -2943,6 +2982,8 @@ gtk_printer_option_clear_has_conflict
gtk_printer_option_set_boolean
gtk_printer_option_allocate_choices
gtk_printer_option_choices_from_array
+gtk_printer_option_set_activates_default
+gtk_printer_option_get_activates_default
#endif
#endif
#endif
@@ -3004,6 +3045,7 @@ gtk_print_operation_set_allow_async
gtk_print_operation_set_default_page_setup
gtk_print_operation_get_default_page_setup
gtk_print_operation_set_print_settings
+gtk_print_operation_get_n_pages_to_print
gtk_print_operation_get_print_settings
gtk_print_operation_set_job_name
gtk_print_operation_set_n_pages
@@ -3277,6 +3319,7 @@ gtk_radio_tool_button_set_group
#if IN_FILE(__GTK_RANGE_C__)
gtk_range_get_adjustment
gtk_range_get_fill_level
+gtk_range_get_flippable
gtk_range_get_inverted
gtk_range_get_lower_stepper_sensitivity
gtk_range_get_restrict_to_fill_level
@@ -3287,6 +3330,7 @@ gtk_range_get_upper_stepper_sensitivity
gtk_range_get_value
gtk_range_set_adjustment
gtk_range_set_fill_level
+gtk_range_set_flippable
gtk_range_set_increments
gtk_range_set_inverted
gtk_range_set_lower_stepper_sensitivity
@@ -3782,6 +3826,15 @@ gtk_spin_button_update
#endif
#endif
+#if IN_HEADER(__GTK_SPINNER_H__)
+#if IN_FILE(__GTK_SPINNER_C__)
+gtk_spinner_get_type G_GNUC_CONST
+gtk_spinner_new
+gtk_spinner_start
+gtk_spinner_stop
+#endif
+#endif
+
#if IN_HEADER(__GTK_STATUSBAR_H__)
#if IN_FILE(__GTK_STATUSBAR_C__)
gtk_statusbar_get_context_id
@@ -4396,6 +4449,7 @@ gtk_tooltip_set_custom
gtk_tooltip_set_icon
gtk_tooltip_set_icon_from_stock
gtk_tooltip_set_icon_from_icon_name
+gtk_tooltip_set_icon_from_gicon
gtk_tooltip_set_markup
gtk_tooltip_set_text
gtk_tooltip_set_tip_area
@@ -4877,6 +4931,7 @@ gtk_viewport_get_hadjustment
gtk_viewport_get_shadow_type
gtk_viewport_get_type G_GNUC_CONST
gtk_viewport_get_vadjustment
+gtk_viewport_get_bin_window
gtk_viewport_new
gtk_viewport_set_hadjustment
gtk_viewport_set_shadow_type
@@ -4954,7 +5009,9 @@ gtk_widget_error_bell
gtk_widget_event
gtk_widget_freeze_child_notify
gtk_widget_get_accessible
+gtk_widget_get_allocation
gtk_widget_get_ancestor
+gtk_widget_get_app_paintable
gtk_widget_get_child_requisition
gtk_widget_get_child_visible
gtk_widget_get_clipboard
@@ -4966,6 +5023,7 @@ gtk_widget_get_default_style
gtk_widget_get_default_visual
gtk_widget_get_direction
gtk_widget_get_display
+gtk_widget_get_double_buffered
gtk_widget_get_events
gtk_widget_get_extension_events
gtk_widget_get_has_tooltip
@@ -4976,20 +5034,27 @@ gtk_widget_get_pango_context
gtk_widget_get_parent
gtk_widget_get_parent_window
gtk_widget_get_pointer
+gtk_widget_get_receives_default
gtk_widget_get_root_window
gtk_widget_get_screen
+gtk_widget_get_sensitive
gtk_widget_get_settings
gtk_widget_get_size_request
gtk_widget_get_snapshot
+gtk_widget_get_state
gtk_widget_get_style
gtk_widget_get_tooltip_markup
gtk_widget_get_tooltip_text
gtk_widget_get_tooltip_window
gtk_widget_get_toplevel
gtk_widget_get_type G_GNUC_CONST
+gtk_widget_get_visible
gtk_widget_get_visual
gtk_widget_grab_default
gtk_widget_grab_focus
+gtk_widget_has_default
+gtk_widget_has_focus
+gtk_widget_has_grab
gtk_widget_has_screen
gtk_widget_hide
gtk_widget_hide_all
@@ -4997,6 +5062,9 @@ gtk_widget_hide_on_delete
gtk_widget_intersect
gtk_widget_is_ancestor
gtk_widget_is_focus
+gtk_widget_is_sensitive
+gtk_widget_is_toplevel
+gtk_widget_is_drawable
gtk_widget_keynav_failed
gtk_widget_list_accel_closures
gtk_widget_list_mnemonic_labels
@@ -5039,6 +5107,7 @@ gtk_widget_reset_rc_styles
gtk_widget_reset_shapes
gtk_widget_send_expose
gtk_widget_set_accel_path
+gtk_widget_set_allocation
gtk_widget_set_app_paintable
gtk_widget_set_child_visible
gtk_widget_set_colormap
@@ -5054,6 +5123,7 @@ gtk_widget_set_name
gtk_widget_set_no_show_all
gtk_widget_set_parent
gtk_widget_set_parent_window
+gtk_widget_set_receives_default
gtk_widget_set_redraw_on_allocate
gtk_widget_set_scroll_adjustments
gtk_widget_set_sensitive
@@ -5063,6 +5133,8 @@ gtk_widget_set_style
gtk_widget_set_tooltip_markup
gtk_widget_set_tooltip_text
gtk_widget_set_tooltip_window
+gtk_widget_set_visible
+gtk_widget_set_window
gtk_widget_shape_combine_mask
gtk_widget_input_shape_combine_mask
gtk_widget_show
@@ -5080,6 +5152,12 @@ gtk_widget_unmap
gtk_widget_unparent
gtk_widget_unrealize
gtk_widget_get_window
+gtk_widget_set_has_window
+gtk_widget_get_has_window
+gtk_widget_set_can_default
+gtk_widget_get_can_default
+gtk_widget_set_can_focus
+gtk_widget_get_can_focus
#endif
#endif
diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c
index 91d30fe344..af7f2cd734 100644
--- a/gtk/gtkaboutdialog.c
+++ b/gtk/gtkaboutdialog.c
@@ -57,6 +57,67 @@
#include "gtkalias.h"
+
+/**
+ * SECTION:gtkaboutdialog
+ * @Short_description: Display information about an application
+ * @Title: GtkAboutDialog
+ * @See_also:#GTK_STOCK_ABOUT
+ *
+ * The #GtkAboutDialog offers a simple way to display information about
+ * a program like its logo, name, copyright, website and license. It is
+ * also possible to give credits to the authors, documenters, translators
+ * and artists who have worked on the program. An about dialog is typically
+ * opened when the user selects the <literal>About</literal> option from
+ * the <literal>Help</literal> menu. All parts of the dialog are optional.
+ *
+ * About dialog often contain links and email addresses. #GtkAboutDialog
+ * supports this by offering global hooks, which are called when the user
+ * clicks on a link or email address, see gtk_about_dialog_set_email_hook()
+ * and gtk_about_dialog_set_url_hook(). Email addresses in the
+ * authors, documenters and artists properties are recognized by looking for
+ * <literal>&lt;user@<!-- -->host&gt;</literal>, URLs are
+ * recognized by looking for <literal>http://url</literal>, with
+ * <literal>url</literal> extending to the next space, tab or line break.
+ *
+ * <para id="gtk-about-dialog-hook-setup">
+ * Since 2.18 #GtkAboutDialog provides default website and email hooks that
+ * use gtk_show_uri().
+ * </para>
+ *
+ * If you want provide your own hooks overriding the default ones, it is
+ * important to do so before setting the website and email URL properties,
+ * like this:
+ * <informalexample><programlisting>
+ * gtk_about_dialog_set_url_hook (GTK_ABOUT_DIALOG (dialog), launch_url, NULL, NULL);
+ * gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), app_url);
+ * </programlisting></informalexample>
+ * To disable the default hooks, you can pass %NULL as the hook func. Then,
+ * the #GtkAboutDialog widget will not display the website or the
+ * email addresses as clickable.
+ *
+ * To make constructing a #GtkAboutDialog as convenient as possible, you can
+ * use the function gtk_show_about_dialog() which constructs and shows a dialog
+ * and keeps it around so that it can be shown again.
+ *
+ * Note that GTK+ sets a default title of <literal>_("About &percnt;s")</literal>
+ * on the dialog window (where &percnt;s is replaced by the name of the
+ * application, but in order to ensure proper translation of the title,
+ * applications should set the title property explicitly when constructing
+ * a #GtkAboutDialog, as shown in the following example:
+ * <informalexample><programlisting>
+ * gtk_show_about_dialog (NULL,
+ * "program-name", "ExampleCode",
+ * "logo", example_logo,
+ * "title" _("About ExampleCode"),
+ * NULL);
+ * </programlisting></informalexample>
+ * Note that prior to GTK+ 2.12, the #GtkAboutDialog:program-name property
+ * was called "name". This was changed to avoid the conflict with the
+ * #GtkWidget:name property.
+ */
+
+
static GdkColor default_link_color = { 0, 0, 0, 0xeeee };
static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
@@ -131,8 +192,6 @@ static void gtk_about_dialog_set_property (GObject
static void gtk_about_dialog_show (GtkWidget *widge);
static void update_name_version (GtkAboutDialog *about);
static GtkIconSet * icon_set_new_from_pixbufs (GList *pixbufs);
-static void activate_url (GtkWidget *widget,
- gpointer data);
static void follow_if_link (GtkAboutDialog *about,
GtkTextView *text_view,
GtkTextIter *iter);
@@ -1695,30 +1754,6 @@ gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about,
}
static void
-activate_url (GtkWidget *widget,
- gpointer data)
-{
- GtkAboutDialog *about = GTK_ABOUT_DIALOG (data);
- const gchar *url = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget));
- GtkAboutDialogActivateLinkFunc url_hook;
- gpointer url_hook_data;
-
- if (activate_url_hook_set)
- {
- url_hook = activate_url_hook;
- url_hook_data = activate_url_hook_data;
- }
- else
- {
- url_hook = default_url_hook;
- url_hook_data = NULL;
- }
-
- if (url_hook)
- url_hook (about, url, url_hook_data);
-}
-
-static void
follow_if_link (GtkAboutDialog *about,
GtkTextView *text_view,
GtkTextIter *iter)
diff --git a/gtk/gtkaboutdialog.h b/gtk/gtkaboutdialog.h
index 02f2fbec03..efb50b1cf0 100644
--- a/gtk/gtkaboutdialog.h
+++ b/gtk/gtkaboutdialog.h
@@ -43,6 +43,12 @@ G_BEGIN_DECLS
typedef struct _GtkAboutDialog GtkAboutDialog;
typedef struct _GtkAboutDialogClass GtkAboutDialogClass;
+/**
+ * GtkAboutDialog:
+ *
+ * The <structname>GtkAboutDialog</structname> struct contains
+ * only private fields and should not be directly accessed.
+ */
struct _GtkAboutDialog
{
GtkDialog parent_instance;
@@ -118,6 +124,17 @@ G_CONST_RETURN gchar *gtk_about_dialog_get_logo_icon_name (GtkAboutDialog
void gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about,
const gchar *icon_name);
+/**
+ * GtkAboutDialogActivateLinkFunc:
+ * @about: the #GtkAboutDialog in which the link was activated
+ * @link_: the URL or email address to which the activated link points
+ * @data: user data that was passed when the function was registered
+ * with gtk_about_dialog_set_email_hook() or
+ * gtk_about_dialog_set_url_hook()
+ *
+ * The type of a function which is called when a URL or email
+ * link is activated.
+ */
typedef void (* GtkAboutDialogActivateLinkFunc) (GtkAboutDialog *about,
const gchar *link_,
gpointer data);
diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c
index b26fd63a05..29e34eb3f3 100644
--- a/gtk/gtkaccelgroup.c
+++ b/gtk/gtkaccelgroup.c
@@ -37,6 +37,31 @@
#include "gtkmarshalers.h"
#include "gtkalias.h"
+/**
+ * SECTION:gtkaccelgroup
+ * @Short_description: Groups of global keyboard accelerators for an entire GtkWindow
+ * @Title: Accelerator Groups
+ * @See_also:gtk_window_add_accel_group(), gtk_accel_map_change_entry(),
+ * gtk_item_factory_new(), gtk_label_new_with_mnemonic()
+ *
+ * A #GtkAccelGroup represents a group of keyboard accelerators,
+ * typically attached to a toplevel #GtkWindow (with
+ * gtk_window_add_accel_group()). Usually you won't need to create a
+ * #GtkAccelGroup directly; instead, when using #GtkItemFactory, GTK+
+ * automatically sets up the accelerators for your menus in the item
+ * factory's #GtkAccelGroup.
+ *
+ *
+ * Note that <firstterm>accelerators</firstterm> are different from
+ * <firstterm>mnemonics</firstterm>. Accelerators are shortcuts for
+ * activating a menu item; they appear alongside the menu item they're a
+ * shortcut for. For example "Ctrl+Q" might appear alongside the "Quit"
+ * menu item. Mnemonics are shortcuts for GUI elements such as text
+ * entries or buttons; they appear as underlined characters. See
+ * gtk_label_new_with_mnemonic(). Menu items can have both accelerators
+ * and mnemonics, of course.
+ */
+
/* --- prototypes --- */
static void gtk_accel_group_finalize (GObject *object);
@@ -665,11 +690,14 @@ gtk_accel_group_connect_by_path (GtkAccelGroup *accel_group,
/**
* gtk_accel_group_disconnect:
* @accel_group: the accelerator group to remove an accelerator from
- * @closure: the closure to remove from this accelerator group
+ * @closure: the closure to remove from this accelerator group, or %NULL
+ * to remove all closures
* @returns: %TRUE if the closure was found and got disconnected
*
* Removes an accelerator previously installed through
* gtk_accel_group_connect().
+ *
+ * Since 2.20 @closure can be %NULL.
*/
gboolean
gtk_accel_group_disconnect (GtkAccelGroup *accel_group,
@@ -680,7 +708,7 @@ gtk_accel_group_disconnect (GtkAccelGroup *accel_group,
g_return_val_if_fail (GTK_IS_ACCEL_GROUP (accel_group), FALSE);
for (i = 0; i < accel_group->n_accels; i++)
- if (accel_group->priv_accels[i].closure == closure)
+ if (accel_group->priv_accels[i].closure == closure || !closure)
{
g_object_ref (accel_group);
quick_accel_remove (accel_group, i);
diff --git a/gtk/gtkaccelgroup.h b/gtk/gtkaccelgroup.h
index 80780dba5a..b1e874491e 100644
--- a/gtk/gtkaccelgroup.h
+++ b/gtk/gtkaccelgroup.h
@@ -66,10 +66,23 @@ typedef gboolean (*GtkAccelGroupActivate) (GtkAccelGroup *accel_group,
guint keyval,
GdkModifierType modifier);
+/**
+ * GtkAccelGroupFindFunc:
+ * @key:
+ * @closure:
+ * @data:
+ *
+ * Since: 2.2
+ */
typedef gboolean (*GtkAccelGroupFindFunc) (GtkAccelKey *key,
GClosure *closure,
gpointer data);
+/**
+ * GtkAccelGroup:
+ *
+ * An object representing and maintaining a group of accelerators.
+ */
struct _GtkAccelGroup
{
GObject parent;
@@ -180,7 +193,20 @@ struct _GtkAccelGroupEntry
#ifndef GTK_DISABLE_DEPRECATED
+/**
+ * gtk_accel_group_ref:
+ *
+ * Deprecated equivalent of g_object_ref().
+ *
+ * Returns: the accel group that was passed in
+ */
#define gtk_accel_group_ref g_object_ref
+
+/**
+ * gtk_accel_group_unref:
+ *
+ * Deprecated equivalent of g_object_unref().
+ */
#define gtk_accel_group_unref g_object_unref
#endif /* GTK_DISABLE_DEPRECATED */
diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c
index 1a781e7a58..e3d6ea3c14 100644
--- a/gtk/gtkaccessible.c
+++ b/gtk/gtkaccessible.c
@@ -25,6 +25,13 @@
#include "gtkaccessible.h"
#include "gtkalias.h"
+/**
+ * SECTION:gtkaccessible
+ * @Short_description: Accessibility support for widgets
+ * @Title: GtkAccessible
+ */
+
+
static void gtk_accessible_real_connect_widget_destroyed (GtkAccessible *accessible);
G_DEFINE_TYPE (GtkAccessible, gtk_accessible, ATK_TYPE_OBJECT)
diff --git a/gtk/gtkactivatable.c b/gtk/gtkactivatable.c
index 65c166b87e..4f92e524ea 100644
--- a/gtk/gtkactivatable.c
+++ b/gtk/gtkactivatable.c
@@ -20,6 +20,7 @@
/**
* SECTION:gtkactivatable
* @Short_Description: An interface for activatable widgets
+ * @Title: GtkActivatable
*
* Activatable widgets can be connected to a #GtkAction and reflects
* the state of its action. A #GtkActivatable can also provide feedback
diff --git a/gtk/gtkassistant.c b/gtk/gtkassistant.c
index b7ed75641d..a2e2f7ae3a 100644
--- a/gtk/gtkassistant.c
+++ b/gtk/gtkassistant.c
@@ -483,6 +483,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
case GTK_ASSISTANT_PAGE_INTRO:
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
+ gtk_widget_grab_default (assistant->forward);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->forward);
gtk_widget_hide (assistant->back);
@@ -494,6 +495,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->back, TRUE);
gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
+ gtk_widget_grab_default (assistant->apply);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->apply);
@@ -505,6 +507,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->back, TRUE);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
+ gtk_widget_grab_default (assistant->forward);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->forward);
@@ -514,6 +517,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
break;
case GTK_ASSISTANT_PAGE_SUMMARY:
gtk_widget_set_sensitive (assistant->close, TRUE);
+ gtk_widget_grab_default (assistant->close);
gtk_widget_show (assistant->close);
gtk_widget_hide (assistant->cancel);
gtk_widget_hide (assistant->back);
@@ -525,6 +529,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
+ gtk_widget_grab_default (assistant->forward);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->forward);
@@ -640,10 +645,10 @@ on_assistant_apply (GtkWidget *widget,
{
gboolean success;
- success = compute_next_step (assistant);
-
g_signal_emit (assistant, signals [APPLY], 0);
+ success = compute_next_step (assistant);
+
/* if the assistant hasn't switched to another page, just emit
* the CLOSE signal, it't the last page in the assistant flow
*/
@@ -752,6 +757,9 @@ gtk_assistant_init (GtkAssistant *assistant)
assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
+ GTK_WIDGET_SET_FLAGS (assistant->close, GTK_CAN_DEFAULT);
+ GTK_WIDGET_SET_FLAGS (assistant->apply, GTK_CAN_DEFAULT);
+ GTK_WIDGET_SET_FLAGS (assistant->forward, GTK_CAN_DEFAULT);
priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (priv->size_group, assistant->close);
@@ -1222,6 +1230,7 @@ gtk_assistant_map (GtkWidget *widget)
GtkAssistant *assistant = GTK_ASSISTANT (widget);
GtkAssistantPrivate *priv = assistant->priv;
GList *page_node;
+ GtkAssistantPage *page;
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
@@ -1233,7 +1242,8 @@ gtk_assistant_map (GtkWidget *widget)
gtk_widget_map (priv->sidebar_image);
/* if there's no default page, pick the first one */
- if (!priv->current_page && priv->pages)
+ page = NULL;
+ if (!priv->current_page)
{
page_node = priv->pages;
@@ -1241,22 +1251,13 @@ gtk_assistant_map (GtkWidget *widget)
page_node = page_node->next;
if (page_node)
- priv->current_page = page_node->data;
+ page = page_node->data;
}
- if (priv->current_page &&
- GTK_WIDGET_VISIBLE (priv->current_page->page) &&
- !GTK_WIDGET_MAPPED (priv->current_page->page))
- {
- set_assistant_buttons_state ((GtkAssistant *) widget);
- set_assistant_header_image ((GtkAssistant*) widget);
- set_assistant_sidebar_image ((GtkAssistant*) widget);
-
- g_signal_emit (widget, signals [PREPARE], 0, priv->current_page->page);
- gtk_widget_set_child_visible (priv->current_page->page, TRUE);
- gtk_widget_map (priv->current_page->page);
- gtk_widget_map (priv->current_page->title);
- }
+ if (page &&
+ GTK_WIDGET_VISIBLE (page->page) &&
+ !GTK_WIDGET_MAPPED (page->page))
+ set_current_page (assistant, page);
GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
}
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index f6f12a5bf6..b4f6855136 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -380,7 +380,12 @@ parse_object (GMarkupParseContext *context,
data->inside_requested_object = TRUE;
}
else
- return;
+ {
+ g_free (object_class);
+ g_free (object_id);
+ g_free (constructor);
+ return;
+ }
}
object_info = g_slice_new0 (ObjectInfo);
@@ -404,7 +409,8 @@ parse_object (GMarkupParseContext *context,
return;
}
- g_hash_table_insert (data->object_ids, object_id, GINT_TO_POINTER (line));
+
+ g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line));
}
static void
@@ -1128,7 +1134,8 @@ _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
data->builder = builder;
data->filename = filename;
data->domain = g_strdup (domain);
- data->object_ids = g_hash_table_new (g_str_hash, g_str_equal);
+ data->object_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify)g_free, NULL);
data->requested_objects = NULL;
if (requested_objs)
diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h
index 1243e2abb5..7a67ddcf91 100644
--- a/gtk/gtkbutton.h
+++ b/gtk/gtkbutton.h
@@ -93,11 +93,15 @@ GtkWidget* gtk_button_new (void);
GtkWidget* gtk_button_new_with_label (const gchar *label);
GtkWidget* gtk_button_new_from_stock (const gchar *stock_id);
GtkWidget* gtk_button_new_with_mnemonic (const gchar *label);
+#ifndef GTK_DISABLE_DEPRECATED
void gtk_button_pressed (GtkButton *button);
void gtk_button_released (GtkButton *button);
+#endif
void gtk_button_clicked (GtkButton *button);
+#ifndef GTK_DISABLE_DEPRECATED
void gtk_button_enter (GtkButton *button);
void gtk_button_leave (GtkButton *button);
+#endif
void gtk_button_set_relief (GtkButton *button,
GtkReliefStyle newstyle);
diff --git a/gtk/gtkcelleditable.c b/gtk/gtkcelleditable.c
index 933622410e..38457cae9f 100644
--- a/gtk/gtkcelleditable.c
+++ b/gtk/gtkcelleditable.c
@@ -21,10 +21,11 @@
#include "config.h"
#include "gtkcelleditable.h"
#include "gtkmarshalers.h"
+#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
-static void gtk_cell_editable_base_init (gpointer g_class);
+static void gtk_cell_editable_base_init (GtkCellEditableIface *iface);
GType
gtk_cell_editable_get_type (void)
@@ -35,12 +36,12 @@ gtk_cell_editable_get_type (void)
{
const GTypeInfo cell_editable_info =
{
- sizeof (GtkCellEditableIface), /* class_size */
- gtk_cell_editable_base_init, /* base_init */
- NULL, /* base_finalize */
+ sizeof (GtkCellEditableIface), /* class_size */
+ (GBaseInitFunc) gtk_cell_editable_base_init, /* base_init */
+ NULL, /* base_finalize */
NULL,
- NULL, /* class_finalize */
- NULL, /* class_data */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
0,
0,
NULL
@@ -57,13 +58,27 @@ gtk_cell_editable_get_type (void)
}
static void
-gtk_cell_editable_base_init (gpointer g_class)
+gtk_cell_editable_base_init (GtkCellEditableIface *iface)
{
static gboolean initialized = FALSE;
if (! initialized)
{
/**
+ * GtkCellEditable:editing-canceled:
+ *
+ * Indicates whether editing on the cell has been canceled.
+ *
+ * Since: 2.20
+ **/
+ g_object_interface_install_property (iface,
+ g_param_spec_boolean ("editing-canceled",
+ P_("Editing Canceled"),
+ P_("Indicates that editing has been canceled"),
+ FALSE,
+ GTK_PARAM_READABLE));
+
+ /**
* GtkCellEditable::editing-done:
* @cell_editable: the object on which the signal was emitted
*
diff --git a/gtk/gtkcellrenderer.c b/gtk/gtkcellrenderer.c
index c41a7f857b..e4af9a1303 100644
--- a/gtk/gtkcellrenderer.c
+++ b/gtk/gtkcellrenderer.c
@@ -684,7 +684,7 @@ gtk_cell_renderer_start_editing (GtkCellRenderer *cell,
* @cell: A #GtkCellRenderer
* @width: the width of the cell renderer, or -1
* @height: the height of the cell renderer, or -1
- *
+ *
* Sets the renderer size to be explicit, independent of the properties set.
**/
void
@@ -718,9 +718,9 @@ gtk_cell_renderer_set_fixed_size (GtkCellRenderer *cell,
/**
* gtk_cell_renderer_get_fixed_size:
* @cell: A #GtkCellRenderer
- * @width: location to fill in with the fixed width of the widget, or %NULL
- * @height: location to fill in with the fixed height of the widget, or %NULL
- *
+ * @width: location to fill in with the fixed width of the cell, or %NULL
+ * @height: location to fill in with the fixed height of the cell, or %NULL
+ *
* Fills in @width and @height with the appropriate size of @cell.
**/
void
@@ -731,9 +731,212 @@ gtk_cell_renderer_get_fixed_size (GtkCellRenderer *cell,
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
if (width)
- (* width) = cell->width;
+ *width = cell->width;
if (height)
- (* height) = cell->height;
+ *height = cell->height;
+}
+
+/**
+ * gtk_cell_renderer_set_alignment:
+ * @cell: A #GtkCellRenderer
+ * @xalign: the x alignment of the cell renderer
+ * @yalign: the y alignment of the cell renderer
+ *
+ * Sets the renderer's alignment within its available space.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_set_alignment (GtkCellRenderer *cell,
+ gfloat xalign,
+ gfloat yalign)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+ g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
+ g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
+
+ if ((xalign != cell->xalign) || (yalign != cell->yalign))
+ {
+ g_object_freeze_notify (G_OBJECT (cell));
+
+ if (xalign != cell->xalign)
+ {
+ cell->xalign = xalign;
+ g_object_notify (G_OBJECT (cell), "xalign");
+ }
+
+ if (yalign != cell->yalign)
+ {
+ cell->yalign = yalign;
+ g_object_notify (G_OBJECT (cell), "yalign");
+ }
+
+ g_object_thaw_notify (G_OBJECT (cell));
+ }
+}
+
+/**
+ * gtk_cell_renderer_get_alignment:
+ * @cell: A #GtkCellRenderer
+ * @xalign: location to fill in with the x alignment of the cell, or %NULL
+ * @yalign: location to fill in with the y alignment of the cell, or %NULL
+ *
+ * Fills in @xalign and @yalign with the appropriate values of @cell.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_get_alignment (GtkCellRenderer *cell,
+ gfloat *xalign,
+ gfloat *yalign)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+ if (xalign)
+ *xalign = cell->xalign;
+ if (yalign)
+ *yalign = cell->yalign;
+}
+
+/**
+ * gtk_cell_renderer_set_padding:
+ * @cell: A #GtkCellRenderer
+ * @xpad: the x padding of the cell renderer
+ * @ypad: the y padding of the cell renderer
+ *
+ * Sets the renderer's padding.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_set_padding (GtkCellRenderer *cell,
+ gint xpad,
+ gint ypad)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+ g_return_if_fail (xpad >= 0 && xpad >= 0);
+
+ if ((xpad != cell->xpad) || (ypad != cell->ypad))
+ {
+ g_object_freeze_notify (G_OBJECT (cell));
+
+ if (xpad != cell->xpad)
+ {
+ cell->xpad = xpad;
+ g_object_notify (G_OBJECT (cell), "xpad");
+ }
+
+ if (ypad != cell->ypad)
+ {
+ cell->ypad = ypad;
+ g_object_notify (G_OBJECT (cell), "ypad");
+ }
+
+ g_object_thaw_notify (G_OBJECT (cell));
+ }
+}
+
+/**
+ * gtk_cell_renderer_get_padding:
+ * @cell: A #GtkCellRenderer
+ * @xpad: location to fill in with the x padding of the cell, or %NULL
+ * @ypad: location to fill in with the y padding of the cell, or %NULL
+ *
+ * Fills in @xpad and @ypad with the appropriate values of @cell.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_get_padding (GtkCellRenderer *cell,
+ gint *xpad,
+ gint *ypad)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+ if (xpad)
+ *xpad = cell->xpad;
+ if (ypad)
+ *ypad = cell->ypad;
+}
+
+/**
+ * gtk_cell_renderer_set_visible:
+ * @cell: A #GtkCellRenderer
+ * @visible: the visibility of the cell
+ *
+ * Sets the cell renderer's visibility.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_set_visible (GtkCellRenderer *cell,
+ gboolean visible)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+ if (cell->visible != visible)
+ {
+ cell->visible = visible ? TRUE : FALSE;
+ g_object_notify (G_OBJECT (cell), "visible");
+ }
+}
+
+/**
+ * gtk_cell_renderer_get_visible:
+ * @cell: A #GtkCellRenderer
+ *
+ * Returns the cell renderer's visibility.
+ *
+ * Returns: %TRUE if the cell renderer is visible
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_cell_renderer_get_visible (GtkCellRenderer *cell)
+{
+ g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
+
+ return cell->visible;
+}
+
+/**
+ * gtk_cell_renderer_set_sensitive:
+ * @cell: A #GtkCellRenderer
+ * @sensitive: the sensitivity of the cell
+ *
+ * Sets the cell renderer's sensitivity.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_set_sensitive (GtkCellRenderer *cell,
+ gboolean sensitive)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+ if (cell->sensitive != sensitive)
+ {
+ cell->sensitive = sensitive ? TRUE : FALSE;
+ g_object_notify (G_OBJECT (cell), "sensitive");
+ }
+}
+
+/**
+ * gtk_cell_renderer_get_sensitive:
+ * @cell: A #GtkCellRenderer
+ *
+ * Returns the cell renderer's sensitivity.
+ *
+ * Returns: %TRUE if the cell renderer is sensitive
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_cell_renderer_get_sensitive (GtkCellRenderer *cell)
+{
+ g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
+
+ return cell->sensitive;
}
/**
diff --git a/gtk/gtkcellrenderer.h b/gtk/gtkcellrenderer.h
index 8b54292692..aece202ae9 100644
--- a/gtk/gtkcellrenderer.h
+++ b/gtk/gtkcellrenderer.h
@@ -152,6 +152,7 @@ GtkCellEditable *gtk_cell_renderer_start_editing (GtkCellRenderer *cell,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
+
void gtk_cell_renderer_set_fixed_size (GtkCellRenderer *cell,
gint width,
gint height);
@@ -159,6 +160,28 @@ void gtk_cell_renderer_get_fixed_size (GtkCellRenderer *cell,
gint *width,
gint *height);
+void gtk_cell_renderer_set_alignment (GtkCellRenderer *cell,
+ gfloat xalign,
+ gfloat yalign);
+void gtk_cell_renderer_get_alignment (GtkCellRenderer *cell,
+ gfloat *xalign,
+ gfloat *yalign);
+
+void gtk_cell_renderer_set_padding (GtkCellRenderer *cell,
+ gint xpad,
+ gint ypad);
+void gtk_cell_renderer_get_padding (GtkCellRenderer *cell,
+ gint *xpad,
+ gint *ypad);
+
+void gtk_cell_renderer_set_visible (GtkCellRenderer *cell,
+ gboolean visible);
+gboolean gtk_cell_renderer_get_visible (GtkCellRenderer *cell);
+
+void gtk_cell_renderer_set_sensitive (GtkCellRenderer *cell,
+ gboolean sensitive);
+gboolean gtk_cell_renderer_get_sensitive (GtkCellRenderer *cell);
+
/* For use by cell renderer implementations only */
#ifndef GTK_DISABLE_DEPRECATED
void gtk_cell_renderer_editing_canceled (GtkCellRenderer *cell);
diff --git a/gtk/gtkcellrendereraccel.c b/gtk/gtkcellrendereraccel.c
index f3e229688b..dedbfdae64 100644
--- a/gtk/gtkcellrendereraccel.c
+++ b/gtk/gtkcellrendereraccel.c
@@ -24,6 +24,7 @@
#include "gtkcellrendereraccel.h"
#include "gtklabel.h"
#include "gtkeventbox.h"
+#include "gtkmain.h"
#include "gtkprivate.h"
#include "gdk/gdkkeysyms.h"
#include "gtkalias.h"
@@ -470,6 +471,7 @@ grab_key_callback (GtkWidget *widget,
edited = TRUE;
out:
+ gtk_grab_remove (accel->grab_widget);
gdk_display_keyboard_ungrab (display, event->time);
gdk_display_pointer_ungrab (display, event->time);
@@ -497,6 +499,7 @@ ungrab_stuff (GtkWidget *widget,
{
GdkDisplay *display = gtk_widget_get_display (widget);
+ gtk_grab_remove (accel->grab_widget);
gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
@@ -606,6 +609,8 @@ gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
gtk_widget_show_all (accel->edit_widget);
+ gtk_grab_add (accel->grab_widget);
+
g_signal_connect (G_OBJECT (accel->edit_widget), "unrealize",
G_CALLBACK (ungrab_stuff), accel);
diff --git a/gtk/gtkcellrendererspin.c b/gtk/gtkcellrendererspin.c
index 92b66926ad..ebd08e275c 100644
--- a/gtk/gtkcellrendererspin.c
+++ b/gtk/gtkcellrendererspin.c
@@ -271,6 +271,21 @@ gtk_cell_renderer_spin_key_press_event (GtkWidget *widget,
return FALSE;
}
+static gboolean
+gtk_cell_renderer_spin_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ /* Block 2BUTTON and 3BUTTON here, so that they won't be eaten
+ * by tree view.
+ */
+ if (event->type == GDK_2BUTTON_PRESS
+ || event->type == GDK_3BUTTON_PRESS)
+ return TRUE;
+
+ return FALSE;
+}
+
static GtkCellEditable *
gtk_cell_renderer_spin_start_editing (GtkCellRenderer *cell,
GdkEvent *event,
@@ -296,6 +311,10 @@ gtk_cell_renderer_spin_start_editing (GtkCellRenderer *cell,
spin = gtk_spin_button_new (priv->adjustment,
priv->climb_rate, priv->digits);
+ g_signal_connect (spin, "button-press-event",
+ G_CALLBACK (gtk_cell_renderer_spin_button_press_event),
+ NULL);
+
if (cell_text->text)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin),
g_ascii_strtod (cell_text->text, NULL));
diff --git a/gtk/gtkcellrendererspinner.c b/gtk/gtkcellrendererspinner.c
new file mode 100644
index 0000000000..41bf6cc117
--- /dev/null
+++ b/gtk/gtkcellrendererspinner.c
@@ -0,0 +1,389 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2009 Matthias Clasen <mclasen@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 2007. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkcellrendererspinner.h"
+#include "gtkiconfactory.h"
+#include "gtkicontheme.h"
+#include "gtkintl.h"
+#include "gtkalias.h"
+
+
+/**
+ * SECTION:gtkcellrendererspinner
+ * @Short_description: Renders a spinning animation in a cell
+ * @Title: GtkCellRendererSpinner
+ * @See_also: #GtkSpinner, #GtkCellRendererProgress
+ *
+ * GtkCellRendererSpinner renders a spinning animation in a cell, very
+ * similar to #GtkSpinner. It can often be used as an alternative
+ * to a #GtkCellRendererProgress for displaying indefinite activity,
+ * instead of actual progress.
+ *
+ * To start the animation in a cell, set the #GtkCellRendererSpinner:active
+ * property to %TRUE and increment the #GtkCellRendererSpinner:pulse property
+ * at regular intervals. The usual way to set the cell renderer properties
+ * for each cell is to bind them to columns in your tree model using e.g.
+ * gtk_tree_view_column_add_attribute().
+ */
+
+
+enum {
+ PROP_0,
+ PROP_ACTIVE,
+ PROP_PULSE,
+ PROP_SIZE
+};
+
+struct _GtkCellRendererSpinnerPrivate
+{
+ gboolean active;
+ guint pulse;
+ GtkIconSize icon_size, old_icon_size;
+ gint size;
+};
+
+#define GTK_CELL_RENDERER_SPINNER_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
+ GTK_TYPE_CELL_RENDERER_SPINNER, \
+ GtkCellRendererSpinnerPrivate))
+
+static void gtk_cell_renderer_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gtk_cell_renderer_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_cell_renderer_spinner_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+static void gtk_cell_renderer_spinner_render (GtkCellRenderer *cell,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ guint flags);
+
+G_DEFINE_TYPE (GtkCellRendererSpinner, gtk_cell_renderer_spinner, GTK_TYPE_CELL_RENDERER)
+
+static void
+gtk_cell_renderer_spinner_class_init (GtkCellRendererSpinnerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+ object_class->get_property = gtk_cell_renderer_spinner_get_property;
+ object_class->set_property = gtk_cell_renderer_spinner_set_property;
+
+ cell_class->get_size = gtk_cell_renderer_spinner_get_size;
+ cell_class->render = gtk_cell_renderer_spinner_render;
+
+ /* GtkCellRendererSpinner:active:
+ *
+ * Whether the spinner is active (ie. shown) in the cell
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ P_("Active"),
+ P_("Whether the spinner is active (ie. shown) in the cell"),
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * GtkCellRendererSpinner:pulse:
+ *
+ * Pulse of the spinner. Increment this value to draw the next frame of the
+ * spinner animation. Usually, you would update this value in a timeout.
+ *
+ * The #GtkSpinner widget draws one full cycle of the animation per second by default.
+ * You can learn about the number of frames used by the theme
+ * by looking at the #GtkSpinner:num-steps style property and the duration
+ * of the cycle by looking at #GtkSpinner:cycle-duration.
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_PULSE,
+ g_param_spec_uint ("pulse",
+ P_("Pulse"),
+ P_("Pulse of the spinner"),
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE));
+ /**
+ * GtkCellRendererSpinner:size:
+ *
+ * The #GtkIconSize value that specifies the size of the rendered spinner.
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (object_class,
+ PROP_SIZE,
+ g_param_spec_enum ("size",
+ P_("Size"),
+ P_("The GtkIconSize value that specifies the size of the rendered spinner"),
+ GTK_TYPE_ICON_SIZE, GTK_ICON_SIZE_MENU,
+ G_PARAM_READWRITE));
+
+
+ g_type_class_add_private (object_class, sizeof (GtkCellRendererSpinnerPrivate));
+}
+
+static void
+gtk_cell_renderer_spinner_init (GtkCellRendererSpinner *cell)
+{
+ cell->priv = GTK_CELL_RENDERER_SPINNER_GET_PRIVATE (cell);
+ cell->priv->pulse = 0;
+ cell->priv->old_icon_size = GTK_ICON_SIZE_INVALID;
+ cell->priv->icon_size = GTK_ICON_SIZE_MENU;
+}
+
+/**
+ * gtk_cell_renderer_spinner_new
+ *
+ * Returns a new cell renderer which will show a spinner to indicate
+ * activity.
+ *
+ * Return value: a new #GtkCellRenderer
+ *
+ * Since: 2.20
+ */
+GtkCellRenderer *
+gtk_cell_renderer_spinner_new (void)
+{
+ return g_object_new (GTK_TYPE_CELL_RENDERER_SPINNER, NULL);
+}
+
+static void
+gtk_cell_renderer_spinner_update_size (GtkCellRendererSpinner *cell,
+ GtkWidget *widget)
+{
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ GdkScreen *screen;
+ GtkIconTheme *icon_theme;
+ GtkSettings *settings;
+
+ if (cell->priv->old_icon_size == cell->priv->icon_size)
+ return;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (widget));
+ icon_theme = gtk_icon_theme_get_for_screen (screen);
+ settings = gtk_settings_get_for_screen (screen);
+
+ if (!gtk_icon_size_lookup_for_settings (settings, priv->icon_size, &priv->size, NULL))
+ {
+ g_warning ("Invalid icon size %u\n", priv->icon_size);
+ priv->size = 24;
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, priv->active);
+ break;
+ case PROP_PULSE:
+ g_value_set_uint (value, priv->pulse);
+ break;
+ case PROP_SIZE:
+ g_value_set_enum (value, priv->icon_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (object);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ priv->active = g_value_get_boolean (value);
+ break;
+ case PROP_PULSE:
+ priv->pulse = g_value_get_uint (value);
+ break;
+ case PROP_SIZE:
+ priv->old_icon_size = priv->icon_size;
+ priv->icon_size = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_cell_renderer_spinner_get_size (GtkCellRenderer *cellr,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ gdouble align;
+ gint w, h;
+ gint xpad, ypad;
+ gfloat xalign, yalign;
+ gboolean rtl;
+
+ rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+ gtk_cell_renderer_spinner_update_size (cell, widget);
+
+ g_object_get (cellr,
+ "xpad", &xpad,
+ "ypad", &ypad,
+ "xalign", &xalign,
+ "yalign", &yalign,
+ NULL);
+ w = h = priv->size;
+
+ if (cell_area)
+ {
+ if (x_offset)
+ {
+ align = rtl ? 1.0 - xalign : xalign;
+ *x_offset = align * (cell_area->width - w);
+ *x_offset = MAX (*x_offset, 0);
+ }
+ if (y_offset)
+ {
+ align = rtl ? 1.0 - yalign : yalign;
+ *y_offset = align * (cell_area->height - h);
+ *y_offset = MAX (*y_offset, 0);
+ }
+ }
+ else
+ {
+ if (x_offset)
+ *x_offset = 0;
+ if (y_offset)
+ *y_offset = 0;
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+}
+
+static void
+gtk_cell_renderer_spinner_render (GtkCellRenderer *cellr,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ guint flags)
+{
+ GtkCellRendererSpinner *cell = GTK_CELL_RENDERER_SPINNER (cellr);
+ GtkCellRendererSpinnerPrivate *priv = cell->priv;
+ GtkStateType state;
+ GdkRectangle pix_rect;
+ GdkRectangle draw_rect;
+ gint xpad, ypad;
+
+ if (!priv->active)
+ return;
+
+ gtk_cell_renderer_spinner_get_size (cellr, widget, cell_area,
+ &pix_rect.x, &pix_rect.y,
+ &pix_rect.width, &pix_rect.height);
+
+ g_object_get (cellr,
+ "xpad", &xpad,
+ "ypad", &ypad,
+ NULL);
+ pix_rect.x += cell_area->x + xpad;
+ pix_rect.y += cell_area->y + ypad;
+ pix_rect.width -= xpad * 2;
+ pix_rect.height -= ypad * 2;
+
+ if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) ||
+ !gdk_rectangle_intersect (expose_area, &pix_rect, &draw_rect))
+ {
+ return;
+ }
+
+ state = GTK_STATE_NORMAL;
+ if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !cellr->sensitive)
+ {
+ state = GTK_STATE_INSENSITIVE;
+ }
+ else
+ {
+ if ((flags & GTK_CELL_RENDERER_SELECTED) != 0)
+ {
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_ACTIVE;
+ }
+ else
+ state = GTK_STATE_PRELIGHT;
+ }
+
+ gtk_paint_spinner (widget->style,
+ window,
+ state,
+ priv->pulse,
+ draw_rect.x, draw_rect.y,
+ draw_rect.width, draw_rect.height);
+}
+
+#define __GTK_CELL_RENDERER_SPINNER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkcellrendererspinner.h b/gtk/gtkcellrendererspinner.h
new file mode 100644
index 0000000000..45bcfcab6d
--- /dev/null
+++ b/gtk/gtkcellrendererspinner.h
@@ -0,0 +1,67 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2009 Matthias Clasen <mclasen@redhat.com>
+ * Copyright (C) 2008 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2009 Bastien Nocera <hadess@hadess.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_CELL_RENDERER_SPINNER_H__
+#define __GTK_CELL_RENDERER_SPINNER_H__
+
+#include <gtk/gtkcellrenderer.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_CELL_RENDERER_SPINNER (gtk_cell_renderer_spinner_get_type ())
+#define GTK_CELL_RENDERER_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinner))
+#define GTK_CELL_RENDERER_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinnerClass))
+#define GTK_IS_CELL_RENDERER_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_RENDERER_SPINNER))
+#define GTK_IS_CELL_RENDERER_SPINNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_RENDERER_SPINNER))
+#define GTK_CELL_RENDERER_SPINNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_RENDERER_SPINNER, GtkCellRendererSpinnerClass))
+
+typedef struct _GtkCellRendererSpinner GtkCellRendererSpinner;
+typedef struct _GtkCellRendererSpinnerClass GtkCellRendererSpinnerClass;
+typedef struct _GtkCellRendererSpinnerPrivate GtkCellRendererSpinnerPrivate;
+
+struct _GtkCellRendererSpinner
+{
+ GtkCellRenderer parent;
+ GtkCellRendererSpinnerPrivate *priv;
+};
+
+struct _GtkCellRendererSpinnerClass
+{
+ GtkCellRendererClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+};
+
+GType gtk_cell_renderer_spinner_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *gtk_cell_renderer_spinner_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_CELL_RENDERER_SPINNER_H__ */
diff --git a/gtk/gtkcellrenderertoggle.c b/gtk/gtkcellrenderertoggle.c
index 5cc826ca9b..d097bb0847 100644
--- a/gtk/gtkcellrenderertoggle.c
+++ b/gtk/gtkcellrenderertoggle.c
@@ -349,7 +349,7 @@ gtk_cell_renderer_toggle_render (GtkCellRenderer *cell,
else
shadow = celltoggle->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
- if (!cell->sensitive)
+ if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !cell->sensitive)
{
state = GTK_STATE_INSENSITIVE;
}
@@ -482,5 +482,46 @@ gtk_cell_renderer_toggle_set_active (GtkCellRendererToggle *toggle,
g_object_set (toggle, "active", setting ? TRUE : FALSE, NULL);
}
+/**
+ * gtk_cell_renderer_toggle_get_activatable:
+ * @toggle: a #GtkCellRendererToggle
+ *
+ * Returns whether the cell renderer is activatable. See
+ * gtk_cell_renderer_toggle_set_activatable().
+ *
+ * Return value: %TRUE if the cell renderer is activatable.
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_cell_renderer_toggle_get_activatable (GtkCellRendererToggle *toggle)
+{
+ g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE);
+
+ return toggle->activatable;
+}
+
+/**
+ * gtk_cell_renderer_toggle_set_activatable:
+ * @toggle: a #GtkCellRendererToggle.
+ * @setting: the value to set.
+ *
+ * Makes the cell renderer activatable.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_cell_renderer_toggle_set_activatable (GtkCellRendererToggle *toggle,
+ gboolean setting)
+{
+ g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle));
+
+ if (toggle->activatable != setting)
+ {
+ toggle->activatable = setting ? TRUE : FALSE;
+ g_object_notify (G_OBJECT (toggle), "activatable");
+ }
+}
+
#define __GTK_CELL_RENDERER_TOGGLE_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkcellrenderertoggle.h b/gtk/gtkcellrenderertoggle.h
index c9b85a191e..cf6a3c2f3d 100644
--- a/gtk/gtkcellrenderertoggle.h
+++ b/gtk/gtkcellrenderertoggle.h
@@ -64,16 +64,20 @@ struct _GtkCellRendererToggleClass
void (*_gtk_reserved4) (void);
};
-GType gtk_cell_renderer_toggle_get_type (void) G_GNUC_CONST;
-GtkCellRenderer *gtk_cell_renderer_toggle_new (void);
+GType gtk_cell_renderer_toggle_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *gtk_cell_renderer_toggle_new (void);
-gboolean gtk_cell_renderer_toggle_get_radio (GtkCellRendererToggle *toggle);
-void gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle,
- gboolean radio);
+gboolean gtk_cell_renderer_toggle_get_radio (GtkCellRendererToggle *toggle);
+void gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle,
+ gboolean radio);
-gboolean gtk_cell_renderer_toggle_get_active (GtkCellRendererToggle *toggle);
-void gtk_cell_renderer_toggle_set_active (GtkCellRendererToggle *toggle,
- gboolean setting);
+gboolean gtk_cell_renderer_toggle_get_active (GtkCellRendererToggle *toggle);
+void gtk_cell_renderer_toggle_set_active (GtkCellRendererToggle *toggle,
+ gboolean setting);
+
+gboolean gtk_cell_renderer_toggle_get_activatable (GtkCellRendererToggle *toggle);
+void gtk_cell_renderer_toggle_set_activatable (GtkCellRendererToggle *toggle,
+ gboolean setting);
G_END_DECLS
diff --git a/gtk/gtkcellview.c b/gtk/gtkcellview.c
index 3fa0ad9013..5f8fe39574 100644
--- a/gtk/gtkcellview.c
+++ b/gtk/gtkcellview.c
@@ -438,6 +438,8 @@ gtk_cell_view_expose (GtkWidget *widget,
if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
state = GTK_CELL_RENDERER_PRELIT;
+ else if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE)
+ state = GTK_CELL_RENDERER_INSENSITIVE;
else
state = 0;
diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c
index 74302d1edb..2d0f6bc32f 100644
--- a/gtk/gtkclist.c
+++ b/gtk/gtkclist.c
@@ -1401,9 +1401,9 @@ gtk_clist_column_title_passive (GtkCList *clist,
clist->column[column].button_passive = TRUE;
if (button->button_down)
- gtk_button_released (button);
+ g_signal_emit_by_name (button, "released");
if (button->in_button)
- gtk_button_leave (button);
+ g_signal_emit_by_name (button, "leave");
gtk_signal_connect (GTK_OBJECT (clist->column[column].button), "event",
G_CALLBACK (column_title_passive_func),
@@ -5925,8 +5925,14 @@ draw_rows (GtkCList *clist,
}
if (!area)
- gdk_window_clear_area (clist->clist_window, 0,
- ROW_TOP_YPIXEL (clist, i), 0, 0);
+ {
+ int w, h, y;
+ gdk_drawable_get_size (GDK_DRAWABLE (clist->clist_window), &w, &h);
+ y = ROW_TOP_YPIXEL (clist, i);
+ gdk_window_clear_area (clist->clist_window,
+ 0, y,
+ w, h - y);
+ }
}
static void
diff --git a/gtk/gtkcombo.c b/gtk/gtkcombo.c
index b1f7c29972..73c9990c8f 100644
--- a/gtk/gtkcombo.c
+++ b/gtk/gtkcombo.c
@@ -582,7 +582,7 @@ gtk_combo_popdown_list (GtkCombo *combo)
if (GTK_BUTTON (combo->button)->in_button)
{
GTK_BUTTON (combo->button)->in_button = FALSE;
- gtk_button_released (GTK_BUTTON (combo->button));
+ g_signal_emit_by_name (combo->button, "released");
}
if (GTK_WIDGET_HAS_GRAB (combo->popwin))
@@ -666,7 +666,7 @@ gtk_combo_popup_button_press (GtkWidget *button,
popup_grab_on_window (combo->popwin->window,
gtk_get_current_event_time ());
- gtk_button_pressed (GTK_BUTTON (button));
+ g_signal_emit_by_name (button, "depressed");
gtk_grab_add (combo->popwin);
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index bda2a92f22..ebe90d9fa2 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -204,7 +204,8 @@ enum {
PROP_HAS_FRAME,
PROP_FOCUS_ON_CLICK,
PROP_POPUP_SHOWN,
- PROP_BUTTON_SENSITIVITY
+ PROP_BUTTON_SENSITIVITY,
+ PROP_EDITING_CANCELED
};
static guint combo_box_signals[LAST_SIGNAL] = {0,};
@@ -379,6 +380,8 @@ static gboolean gtk_combo_box_menu_button_press (GtkWidget *widget,
gpointer user_data);
static void gtk_combo_box_menu_item_activate (GtkWidget *item,
gpointer user_data);
+
+static void gtk_combo_box_update_sensitivity (GtkComboBox *combo_box);
static void gtk_combo_box_menu_row_inserted (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
@@ -647,6 +650,10 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_END);
/* properties */
+ g_object_class_override_property (object_class,
+ PROP_EDITING_CANCELED,
+ "editing-canceled");
+
/**
* GtkComboBox:model:
*
@@ -958,58 +965,58 @@ gtk_combo_box_set_property (GObject *object,
switch (prop_id)
{
- case PROP_MODEL:
- gtk_combo_box_set_model (combo_box, g_value_get_object (value));
- break;
+ case PROP_MODEL:
+ gtk_combo_box_set_model (combo_box, g_value_get_object (value));
+ break;
- case PROP_WRAP_WIDTH:
- gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
- break;
+ case PROP_WRAP_WIDTH:
+ gtk_combo_box_set_wrap_width (combo_box, g_value_get_int (value));
+ break;
- case PROP_ROW_SPAN_COLUMN:
- gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
- break;
+ case PROP_ROW_SPAN_COLUMN:
+ gtk_combo_box_set_row_span_column (combo_box, g_value_get_int (value));
+ break;
- case PROP_COLUMN_SPAN_COLUMN:
- gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
- break;
+ case PROP_COLUMN_SPAN_COLUMN:
+ gtk_combo_box_set_column_span_column (combo_box, g_value_get_int (value));
+ break;
- case PROP_ACTIVE:
- gtk_combo_box_set_active (combo_box, g_value_get_int (value));
- break;
+ case PROP_ACTIVE:
+ gtk_combo_box_set_active (combo_box, g_value_get_int (value));
+ break;
- case PROP_ADD_TEAROFFS:
- gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
- break;
+ case PROP_ADD_TEAROFFS:
+ gtk_combo_box_set_add_tearoffs (combo_box, g_value_get_boolean (value));
+ break;
- case PROP_HAS_FRAME:
- combo_box->priv->has_frame = g_value_get_boolean (value);
- break;
+ case PROP_HAS_FRAME:
+ combo_box->priv->has_frame = g_value_get_boolean (value);
+ break;
- case PROP_FOCUS_ON_CLICK:
- gtk_combo_box_set_focus_on_click (combo_box,
- g_value_get_boolean (value));
- break;
+ case PROP_FOCUS_ON_CLICK:
+ gtk_combo_box_set_focus_on_click (combo_box,
+ g_value_get_boolean (value));
+ break;
- case PROP_TEAROFF_TITLE:
- gtk_combo_box_set_title (combo_box, g_value_get_string (value));
- break;
+ case PROP_TEAROFF_TITLE:
+ gtk_combo_box_set_title (combo_box, g_value_get_string (value));
+ break;
- case PROP_POPUP_SHOWN:
- if (g_value_get_boolean (value))
- gtk_combo_box_popup (combo_box);
- else
- gtk_combo_box_popdown (combo_box);
- break;
+ case PROP_POPUP_SHOWN:
+ if (g_value_get_boolean (value))
+ gtk_combo_box_popup (combo_box);
+ else
+ gtk_combo_box_popdown (combo_box);
+ break;
- case PROP_BUTTON_SENSITIVITY:
- gtk_combo_box_set_button_sensitivity (combo_box,
- g_value_get_enum (value));
- break;
+ case PROP_BUTTON_SENSITIVITY:
+ gtk_combo_box_set_button_sensitivity (combo_box,
+ g_value_get_enum (value));
+ break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
}
@@ -1020,6 +1027,7 @@ gtk_combo_box_get_property (GObject *object,
GParamSpec *pspec)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (object);
+ GtkComboBoxPrivate *priv = GTK_COMBO_BOX_GET_PRIVATE (combo_box);
switch (prop_id)
{
@@ -1067,6 +1075,10 @@ gtk_combo_box_get_property (GObject *object,
g_value_set_enum (value, combo_box->priv->button_sensitivity);
break;
+ case PROP_EDITING_CANCELED:
+ g_value_set_boolean (value, priv->editing_canceled);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2862,6 +2874,7 @@ gtk_combo_box_menu_setup (GtkComboBox *combo_box,
gtk_combo_box_sync_cells (combo_box, GTK_CELL_LAYOUT (priv->column));
gtk_combo_box_update_title (combo_box);
+ gtk_combo_box_update_sensitivity (combo_box);
}
static void
@@ -3215,6 +3228,11 @@ gtk_combo_box_update_sensitivity (GtkComboBox *combo_box)
}
gtk_widget_set_sensitive (combo_box->priv->button, sensitive);
+
+ /* In list-mode, we also need to update sensitivity of the event box */
+ if (GTK_IS_TREE_VIEW (combo_box->priv->tree_view)
+ && combo_box->priv->cell_view)
+ gtk_widget_set_sensitive (combo_box->priv->box, sensitive);
}
static void
@@ -3755,6 +3773,8 @@ gtk_combo_box_list_setup (GtkComboBox *combo_box)
combo_box);
gtk_widget_show (priv->tree_view);
+
+ gtk_combo_box_update_sensitivity (combo_box);
}
static void
diff --git a/gtk/gtkcomboboxentry.c b/gtk/gtkcomboboxentry.c
index 93ae5aea01..c63c08561b 100644
--- a/gtk/gtkcomboboxentry.c
+++ b/gtk/gtkcomboboxentry.c
@@ -368,9 +368,10 @@ void
gtk_combo_box_entry_set_text_column (GtkComboBoxEntry *entry_box,
gint text_column)
{
+ GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX (entry_box));
+
g_return_if_fail (text_column >= 0);
- g_return_if_fail (text_column < gtk_tree_model_get_n_columns (gtk_combo_box_get_model (GTK_COMBO_BOX (entry_box))));
- g_return_if_fail (entry_box->priv->text_column == -1);
+ g_return_if_fail (model == NULL || text_column < gtk_tree_model_get_n_columns (model));
entry_box->priv->text_column = text_column;
diff --git a/gtk/gtkcurve.c b/gtk/gtkcurve.c
index d996a2d9a0..e49e5ff8c9 100644
--- a/gtk/gtkcurve.c
+++ b/gtk/gtkcurve.c
@@ -24,6 +24,8 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#undef GTK_DISABLE_DEPRECATED
+
#include "config.h"
#include <stdlib.h>
#include <string.h>
diff --git a/gtk/gtkcurve.h b/gtk/gtkcurve.h
index 5edd59db0a..68ee716edb 100644
--- a/gtk/gtkcurve.h
+++ b/gtk/gtkcurve.h
@@ -24,19 +24,7 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-/*
- * NOTE this widget is considered too specialized/little-used for
- * GTK+, and will in the future be moved to some other package. If
- * your application needs this widget, feel free to use it, as the
- * widget does work and is useful in some applications; it's just not
- * of general interest. However, we are not accepting new features for
- * the widget, and it will eventually move out of the GTK+
- * distribution.
- */
-
-#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
+#ifndef GTK_DISABLE_DEPRECATED
#ifndef __GTK_CURVE_H__
#define __GTK_CURVE_H__
@@ -114,3 +102,5 @@ void gtk_curve_set_curve_type (GtkCurve *curve, GtkCurveType type);
G_END_DECLS
#endif /* __GTK_CURVE_H__ */
+
+#endif /* GTK_DISABLE_DEPRECATED */
diff --git a/gtk/gtkcustompaperunixdialog.c b/gtk/gtkcustompaperunixdialog.c
index 972ab1640b..9006eaba23 100644
--- a/gtk/gtkcustompaperunixdialog.c
+++ b/gtk/gtkcustompaperunixdialog.c
@@ -375,14 +375,11 @@ _gtk_custom_paper_unix_dialog_new (GtkWindow *parent,
result = g_object_new (GTK_TYPE_CUSTOM_PAPER_UNIX_DIALOG,
"title", title,
+ "transient-for", parent,
+ "modal", parent != NULL,
+ "destroy-with-parent", TRUE,
NULL);
- if (parent)
- {
- gtk_window_set_modal (GTK_WINDOW (result), TRUE);
- gtk_window_set_transient_for (GTK_WINDOW (result), parent);
- }
-
return result;
}
diff --git a/gtk/gtkcustompaperunixdialog.h b/gtk/gtkcustompaperunixdialog.h
index f1d6ae63b7..0ff3af165d 100644
--- a/gtk/gtkcustompaperunixdialog.h
+++ b/gtk/gtkcustompaperunixdialog.h
@@ -17,10 +17,6 @@
* Boston, MA 02111-1307, USA.
*/
-#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_UNIX_PRINT_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtkunixprint.h> can be included directly."
-#endif
-
#ifndef __GTK_CUSTOM_PAPER_UNIX_DIALOG_H__
#define __GTK_CUSTOM_PAPER_UNIX_DIALOG_H__
diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c
index d463306844..eb25f5224b 100644
--- a/gtk/gtkdialog.c
+++ b/gtk/gtkdialog.c
@@ -1121,6 +1121,49 @@ _gtk_dialog_set_ignore_separator (GtkDialog *dialog,
}
/**
+ * gtk_dialog_get_widget_for_response:
+ * @dialog: a #GtkDialog
+ * @response_id: the response ID used by the @dialog widget
+ *
+ * Gets the widget button that uses the given response ID in the action area
+ * of a dialog.
+ *
+ * Returns: the @widget button that uses the given @response_id, or %NULL.
+ *
+ * Since: 2.20
+ */
+GtkWidget*
+gtk_dialog_get_widget_for_response (GtkDialog *dialog,
+ gint response_id)
+{
+ GList *children;
+ GList *tmp_list;
+
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
+
+ children = gtk_container_get_children (GTK_CONTAINER (dialog->action_area));
+
+ tmp_list = children;
+ while (tmp_list != NULL)
+ {
+ GtkWidget *widget = tmp_list->data;
+ ResponseData *rd = get_response_data (widget, FALSE);
+
+ if (rd && rd->response_id == response_id)
+ {
+ g_list_free (children);
+ return widget;
+ }
+
+ tmp_list = g_list_next (tmp_list);
+ }
+
+ g_list_free (children);
+
+ return NULL;
+}
+
+/**
* gtk_dialog_get_response_for_widget:
* @dialog: a #GtkDialog
* @widget: a widget in the action area of @dialog
diff --git a/gtk/gtkdialog.h b/gtk/gtkdialog.h
index 69d2c0049f..18a18961c8 100644
--- a/gtk/gtkdialog.h
+++ b/gtk/gtkdialog.h
@@ -148,6 +148,8 @@ void gtk_dialog_set_response_sensitive (GtkDialog *dialog,
gboolean setting);
void gtk_dialog_set_default_response (GtkDialog *dialog,
gint response_id);
+GtkWidget* gtk_dialog_get_widget_for_response (GtkDialog *dialog,
+ gint response_id);
gint gtk_dialog_get_response_for_widget (GtkDialog *dialog,
GtkWidget *widget);
diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
index fd66836360..275ebba0bd 100644
--- a/gtk/gtkdnd-quartz.c
+++ b/gtk/gtkdnd-quartz.c
@@ -63,6 +63,11 @@ static GtkDragDestInfo *gtk_drag_get_dest_info (GdkDragContext *context,
gboolean create);
static void gtk_drag_source_site_destroy (gpointer data);
+static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context,
+ gboolean create);
+
+extern GdkDragContext *gdk_quartz_drag_source_context (); /* gdk/quartz/gdkdnd-quartz.c */
+
struct _GtkDragSourceSite
{
GdkModifierType start_button_mask;
@@ -89,13 +94,16 @@ struct _GtkDragSourceSite
struct _GtkDragSourceInfo
{
+ GtkWidget *source_widget;
GtkWidget *widget;
GtkTargetList *target_list; /* Targets for drag data */
GdkDragAction possible_actions; /* Actions allowed by source */
GdkDragContext *context; /* drag context */
-
+ NSEvent *nsevent; /* what started it */
gint hot_x, hot_y; /* Hot spot for drag */
GdkPixbuf *icon_pixbuf;
+ gboolean success;
+ gboolean delete;
};
struct _GtkDragDestSite
@@ -233,19 +241,24 @@ gtk_drag_get_data (GtkWidget *widget,
}
}
-
-GtkWidget *
-gtk_drag_get_source_widget (GdkDragContext *context)
-{
- return NULL;
-}
-
void
gtk_drag_finish (GdkDragContext *context,
gboolean success,
gboolean del,
guint32 time)
{
+ GtkDragSourceInfo *info;
+ GdkDragContext* source_context = gdk_quartz_drag_source_context ();
+
+ if (source_context)
+ {
+ info = gtk_drag_get_source_info (source_context, FALSE);
+ if (info)
+ {
+ info->success = success;
+ info->delete = del;
+ }
+ }
}
static void
@@ -307,6 +320,22 @@ gtk_drag_clear_source_info (GdkDragContext *context)
g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
}
+GtkWidget *
+gtk_drag_get_source_widget (GdkDragContext *context)
+{
+ GtkDragSourceInfo *info;
+ GdkDragContext* real_source_context = gdk_quartz_drag_source_context();
+
+ if (!real_source_context)
+ return NULL;
+
+ info = gtk_drag_get_source_info (real_source_context, FALSE);
+ if (!info)
+ return NULL;
+
+ return info->source_widget;
+}
+
/*************************************************************
* gtk_drag_highlight_expose:
* Callback for expose_event for highlighted widgets.
@@ -1031,6 +1060,45 @@ gtk_drag_dest_find_target (GtkWidget *widget,
return GDK_NONE;
}
+static gboolean
+gtk_drag_begin_idle (gpointer arg)
+{
+ GdkDragContext* context = (GdkDragContext*) arg;
+ GtkDragSourceInfo* info = gtk_drag_get_source_info (context, FALSE);
+ NSWindow *nswindow;
+ NSPasteboard *pasteboard;
+ GtkDragSourceOwner *owner;
+ NSPoint point;
+
+ g_assert (info != NULL);
+
+ pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
+ owner = [[GtkDragSourceOwner alloc] initWithInfo:info];
+
+ [pasteboard declareTypes:_gtk_quartz_target_list_to_pasteboard_types (info->target_list) owner:owner];
+
+ if ((nswindow = get_toplevel_nswindow (info->source_widget)) == NULL)
+ return FALSE;
+
+ /* Ref the context. It's unreffed when the drag has been aborted */
+ g_object_ref (info->context);
+
+ /* FIXME: If the event isn't a mouse event, use the global cursor position instead */
+ point = [info->nsevent locationInWindow];
+
+ [nswindow dragImage:_gtk_quartz_create_image_from_pixbuf (info->icon_pixbuf)
+ at:point
+ offset:NSMakeSize(0, 0)
+ event:info->nsevent
+ pasteboard:pasteboard
+ source:nswindow
+ slideBack:YES];
+
+ [info->nsevent release];
+
+ return FALSE;
+}
+
static GdkDragContext *
gtk_drag_begin_internal (GtkWidget *widget,
GtkDragSourceSite *site,
@@ -1042,16 +1110,13 @@ gtk_drag_begin_internal (GtkWidget *widget,
GtkDragSourceInfo *info;
GdkDragContext *context;
NSWindow *nswindow;
- NSPasteboard *pasteboard;
- GtkDragSourceOwner *owner;
- NSEvent *nsevent;
- NSPoint point;
context = gdk_drag_begin (NULL, NULL);
context->is_source = TRUE;
info = gtk_drag_get_source_info (context, TRUE);
+ info->source_widget = g_object_ref (widget);
info->widget = g_object_ref (widget);
info->target_list = target_list;
gtk_target_list_ref (target_list);
@@ -1086,13 +1151,13 @@ gtk_drag_begin_internal (GtkWidget *widget,
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
- gdk_pixbuf_fill (pixbuf, 0xffffff);
-
- gtk_drag_set_icon_pixbuf (context,
- pixbuf,
+ gdk_pixbuf_fill (pixbuf, 0xffffff);
+
+ gtk_drag_set_icon_pixbuf (context,
+ pixbuf,
0, 0);
- g_object_unref (pixbuf);
+ g_object_unref (pixbuf);
}
break;
case GTK_IMAGE_PIXBUF:
@@ -1117,31 +1182,17 @@ gtk_drag_begin_internal (GtkWidget *widget,
}
}
- gdk_pointer_ungrab (0);
-
- pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- owner = [[GtkDragSourceOwner alloc] initWithInfo:info];
-
- [pasteboard declareTypes:_gtk_quartz_target_list_to_pasteboard_types (target_list) owner:owner];
-
- /* Ref the context. It's unreffed when the drag has been aborted */
- g_object_ref (info->context);
-
nswindow = get_toplevel_nswindow (widget);
+ info->nsevent = [nswindow currentEvent];
+ [info->nsevent retain];
- /* FIXME: If the event isn't a mouse event, use the global cursor position instead */
- nsevent = [nswindow currentEvent];
- point = [nsevent locationInWindow];
+ /* drag will begin in an idle handler to avoid nested run loops */
- [nswindow dragImage:_gtk_quartz_create_image_from_pixbuf (info->icon_pixbuf)
- at:point
- offset:NSMakeSize(0, 0)
- event:nsevent
- pasteboard:pasteboard
- source:nswindow
- slideBack:YES];
+ g_idle_add_full (G_PRIORITY_HIGH_IDLE, gtk_drag_begin_idle, context, NULL);
- return info->context;
+ gdk_pointer_ungrab (0);
+
+ return context;
}
GdkDragContext *
@@ -1773,6 +1824,9 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
g_signal_emit_by_name (info->widget, "drag-end",
info->context);
+ if (info->source_widget)
+ g_object_unref (info->source_widget);
+
if (info->widget)
g_object_unref (info->widget);
@@ -1794,6 +1848,10 @@ drag_drop_finished_idle_cb (gpointer data)
static void
gtk_drag_drop_finished (GtkDragSourceInfo *info)
{
+ if (info->success && info->delete)
+ g_signal_emit_by_name (info->source_widget, "drag-data-delete",
+ info->context);
+
/* Workaround for the fact that the NS API blocks until the drag is
* over. This way the context is still valid when returning from
* drag_begin, even if it will still be quite useless. See bug #501588.
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index de10f0d834..9c885ca54d 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -216,7 +216,8 @@ enum {
PROP_TOOLTIP_TEXT_SECONDARY,
PROP_TOOLTIP_MARKUP_PRIMARY,
PROP_TOOLTIP_MARKUP_SECONDARY,
- PROP_IM_MODULE
+ PROP_IM_MODULE,
+ PROP_EDITING_CANCELED
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -237,9 +238,6 @@ typedef enum
*/
static void gtk_entry_editable_init (GtkEditableClass *iface);
static void gtk_entry_cell_editable_init (GtkCellEditableIface *iface);
-static GObject* gtk_entry_constructor (GType type,
- guint n_props,
- GObjectConstructParam *props);
static void gtk_entry_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -524,6 +522,8 @@ static void buffer_notify_max_length (GtkEntryBuffer *buffer,
GtkEntry *entry);
static void buffer_connect_signals (GtkEntry *entry);
static void buffer_disconnect_signals (GtkEntry *entry);
+static GtkEntryBuffer *get_buffer (GtkEntry *entry);
+
G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
@@ -565,7 +565,6 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class = (GtkWidgetClass*) class;
gtk_object_class = (GtkObjectClass *)class;
- gobject_class->constructor = gtk_entry_constructor;
gobject_class->dispose = gtk_entry_dispose;
gobject_class->finalize = gtk_entry_finalize;
gobject_class->set_property = gtk_entry_set_property;
@@ -624,6 +623,10 @@ gtk_entry_class_init (GtkEntryClass *class)
quark_cursor_hadjustment = g_quark_from_static_string ("gtk-hadjustment");
quark_capslock_feedback = g_quark_from_static_string ("gtk-entry-capslock-feedback");
+ g_object_class_override_property (gobject_class,
+ PROP_EDITING_CANCELED,
+ "editing-canceled");
+
g_object_class_install_property (gobject_class,
PROP_BUFFER,
g_param_spec_object ("buffer",
@@ -1233,7 +1236,7 @@ gtk_entry_class_init (GtkEntryClass *class)
GTK_PARAM_READABLE));
/**
- * GtkEntry::progress-border:
+ * GtkEntry:progress-border:
*
* The border around the progress bar in the entry.
*
@@ -1247,7 +1250,7 @@ gtk_entry_class_init (GtkEntryClass *class)
GTK_PARAM_READABLE));
/**
- * GtkEntry::invisible-char:
+ * GtkEntry:invisible-char:
*
* The invisible character is used when masking entry contents (in
* \"password mode\")"). When it is not explicitly set with the
@@ -1258,7 +1261,7 @@ gtk_entry_class_init (GtkEntryClass *class)
* This style property allows the theme to prepend a character
* to the list of candidates.
*
- * Since: 2.22
+ * Since: 2.18
*/
gtk_widget_class_install_style_property (widget_class,
g_param_spec_unichar ("invisible-char",
@@ -2023,7 +2026,7 @@ gtk_entry_get_property (GObject *object,
break;
case PROP_MAX_LENGTH:
- g_value_set_int (value, gtk_entry_buffer_get_max_length (priv->buffer));
+ g_value_set_int (value, gtk_entry_buffer_get_max_length (get_buffer (entry)));
break;
case PROP_VISIBILITY:
@@ -2075,7 +2078,7 @@ gtk_entry_get_property (GObject *object,
break;
case PROP_TEXT_LENGTH:
- g_value_set_uint (value, gtk_entry_buffer_get_length (priv->buffer));
+ g_value_set_uint (value, gtk_entry_buffer_get_length (get_buffer (entry)));
break;
case PROP_INVISIBLE_CHAR_SET:
@@ -2198,6 +2201,11 @@ gtk_entry_get_property (GObject *object,
gtk_entry_get_icon_tooltip_markup (entry, GTK_ENTRY_ICON_SECONDARY));
break;
+ case PROP_EDITING_CANCELED:
+ g_value_set_boolean (value,
+ entry->editing_canceled);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2253,34 +2261,10 @@ find_invisible_char (GtkWidget *widget)
return '*';
}
-static GObject*
-gtk_entry_constructor (GType type,
- guint n_props,
- GObjectConstructParam *props)
-{
- GObject *obj = G_OBJECT_CLASS (gtk_entry_parent_class)->constructor (type, n_props, props);
- GtkEntryPrivate *priv;
- GtkEntryBuffer *buffer;
-
- if (obj != NULL)
- {
- priv = GTK_ENTRY_GET_PRIVATE (obj);
- if (!priv->buffer)
- {
- buffer = gtk_entry_buffer_new (NULL, 0);
- gtk_entry_set_buffer (GTK_ENTRY (obj), buffer);
- g_object_unref (buffer);
- }
- }
-
- return obj;
-}
-
static void
gtk_entry_init (GtkEntry *entry)
{
GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
- GtkEntryBuffer *buffer;
GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
@@ -2320,13 +2304,6 @@ gtk_entry_init (GtkEntry *entry)
g_signal_connect (entry->im_context, "delete-surrounding",
G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
- /* need to set a buffer here, so GtkEntry subclasses can do anything
- * in their init() functions, just as it used to be before
- * GtkEntryBuffer
- */
- buffer = gtk_entry_buffer_new (NULL, 0);
- gtk_entry_set_buffer (entry, buffer);
- g_object_unref (buffer);
}
static gint
@@ -2543,8 +2520,8 @@ gtk_entry_get_display_text (GtkEntry *entry,
gint i;
priv = GTK_ENTRY_GET_PRIVATE (entry);
- text = gtk_entry_buffer_get_text (priv->buffer);
- length = gtk_entry_buffer_get_length (priv->buffer);
+ text = gtk_entry_buffer_get_text (get_buffer (entry));
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
if (end_pos < 0)
end_pos = length;
@@ -2689,9 +2666,6 @@ construct_icon_info (GtkWidget *widget,
if (GTK_WIDGET_REALIZED (widget))
realize_icon_info (widget, icon_pos);
- if (GTK_WIDGET_MAPPED (widget))
- gdk_window_show_unraised (icon_info->window);
-
return icon_info;
}
@@ -3555,6 +3529,10 @@ gtk_entry_leave_notify (GtkWidget *widget,
if (icon_info != NULL && event->window == icon_info->window)
{
+ /* a grab means that we may never see the button release */
+ if (event->mode == GDK_CROSSING_GRAB || event->mode == GDK_CROSSING_GTK_GRAB)
+ icon_info->pressed = FALSE;
+
if (should_prelight (entry, i))
{
icon_info->prelight = FALSE;
@@ -3997,7 +3975,7 @@ gtk_entry_motion_notify (GtkWidget *widget,
if (event->y < 0)
tmp_pos = 0;
else if (event->y >= height)
- tmp_pos = gtk_entry_buffer_get_length (priv->buffer);
+ tmp_pos = gtk_entry_buffer_get_length (get_buffer (entry));
else
tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
@@ -4314,7 +4292,24 @@ gtk_entry_get_chars (GtkEditable *editable,
gint start_pos,
gint end_pos)
{
- return gtk_entry_get_display_text (GTK_ENTRY (editable), start_pos, end_pos);
+ GtkEntry *entry = GTK_ENTRY (editable);
+ const gchar *text;
+ gint text_length;
+ gint start_index, end_index;
+
+ text = gtk_entry_buffer_get_text (get_buffer (entry));
+ text_length = gtk_entry_buffer_get_length (get_buffer (entry));
+
+ if (end_pos < 0)
+ end_pos = text_length;
+
+ start_pos = MIN (text_length, start_pos);
+ end_pos = MIN (text_length, end_pos);
+
+ start_index = g_utf8_offset_to_pointer (text, start_pos) - entry->text;
+ end_index = g_utf8_offset_to_pointer (text, end_pos) - entry->text;
+
+ return g_strndup (text + start_index, end_index - start_index);
}
static void
@@ -4322,11 +4317,10 @@ gtk_entry_real_set_position (GtkEditable *editable,
gint position)
{
GtkEntry *entry = GTK_ENTRY (editable);
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
guint length;
- length = gtk_entry_buffer_get_length (priv->buffer);
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
if (position < 0 || position > length)
position = length;
@@ -4350,10 +4344,9 @@ gtk_entry_set_selection_bounds (GtkEditable *editable,
gint end)
{
GtkEntry *entry = GTK_ENTRY (editable);
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
guint length;
- length = gtk_entry_buffer_get_length (priv->buffer);
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
if (start < 0)
start = length;
if (end < 0)
@@ -4559,7 +4552,7 @@ gtk_entry_real_delete_text (GtkEditable *editable,
* buffer_notify_text(), buffer_notify_length()
*/
- gtk_entry_buffer_delete_text (GTK_ENTRY_GET_PRIVATE (editable)->buffer, start_pos, end_pos - start_pos);
+ gtk_entry_buffer_delete_text (get_buffer (GTK_ENTRY (editable)), start_pos, end_pos - start_pos);
}
/* GtkEntryBuffer signal handlers
@@ -4682,23 +4675,21 @@ buffer_notify_max_length (GtkEntryBuffer *buffer,
static void
buffer_connect_signals (GtkEntry *entry)
{
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
- g_signal_connect (priv->buffer, "inserted-text", G_CALLBACK (buffer_inserted_text), entry);
- g_signal_connect (priv->buffer, "deleted-text", G_CALLBACK (buffer_deleted_text), entry);
- g_signal_connect (priv->buffer, "notify::text", G_CALLBACK (buffer_notify_text), entry);
- g_signal_connect (priv->buffer, "notify::length", G_CALLBACK (buffer_notify_length), entry);
- g_signal_connect (priv->buffer, "notify::max-length", G_CALLBACK (buffer_notify_max_length), entry);
+ g_signal_connect (get_buffer (entry), "inserted-text", G_CALLBACK (buffer_inserted_text), entry);
+ g_signal_connect (get_buffer (entry), "deleted-text", G_CALLBACK (buffer_deleted_text), entry);
+ g_signal_connect (get_buffer (entry), "notify::text", G_CALLBACK (buffer_notify_text), entry);
+ g_signal_connect (get_buffer (entry), "notify::length", G_CALLBACK (buffer_notify_length), entry);
+ g_signal_connect (get_buffer (entry), "notify::max-length", G_CALLBACK (buffer_notify_max_length), entry);
}
static void
buffer_disconnect_signals (GtkEntry *entry)
{
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
- g_signal_handlers_disconnect_by_func (priv->buffer, buffer_inserted_text, entry);
- g_signal_handlers_disconnect_by_func (priv->buffer, buffer_deleted_text, entry);
- g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_text, entry);
- g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_length, entry);
- g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_max_length, entry);
+ g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_inserted_text, entry);
+ g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_deleted_text, entry);
+ g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_text, entry);
+ g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_length, entry);
+ g_signal_handlers_disconnect_by_func (get_buffer (entry), buffer_notify_max_length, entry);
}
/* Compute the X position for an offset that corresponds to the "more important
@@ -4772,7 +4763,7 @@ gtk_entry_move_cursor (GtkEntry *entry,
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
priv = GTK_ENTRY_GET_PRIVATE (entry);
- new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (priv->buffer);
+ new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry));
break;
case GTK_MOVEMENT_DISPLAY_LINES:
case GTK_MOVEMENT_PARAGRAPHS:
@@ -4830,7 +4821,7 @@ gtk_entry_move_cursor (GtkEntry *entry,
case GTK_MOVEMENT_PARAGRAPH_ENDS:
case GTK_MOVEMENT_BUFFER_ENDS:
priv = GTK_ENTRY_GET_PRIVATE (entry);
- new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (priv->buffer);
+ new_pos = count < 0 ? 0 : gtk_entry_buffer_get_length (get_buffer (entry));
if (entry->current_pos == new_pos)
gtk_widget_error_bell (GTK_WIDGET (entry));
break;
@@ -4872,10 +4863,9 @@ gtk_entry_delete_from_cursor (GtkEntry *entry,
gint count)
{
GtkEditable *editable = GTK_EDITABLE (entry);
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
gint start_pos = entry->current_pos;
gint end_pos = entry->current_pos;
- gint old_n_bytes = gtk_entry_buffer_get_bytes (priv->buffer);
+ gint old_n_bytes = gtk_entry_buffer_get_bytes (get_buffer (entry));
_gtk_entry_reset_im_context (entry);
@@ -4941,7 +4931,7 @@ gtk_entry_delete_from_cursor (GtkEntry *entry,
break;
}
- if (gtk_entry_buffer_get_bytes (priv->buffer) == old_n_bytes)
+ if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == old_n_bytes)
gtk_widget_error_bell (GTK_WIDGET (entry));
gtk_entry_pend_cursor_blink (entry);
@@ -5826,7 +5816,6 @@ gtk_entry_get_cursor_locations (GtkEntry *entry,
gint *weak_x)
{
DisplayMode mode = gtk_entry_get_display_mode (entry);
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
/* Nothing to display at all, so no cursor is relevant */
if (mode == DISPLAY_BLANK)
@@ -5858,7 +5847,7 @@ gtk_entry_get_cursor_locations (GtkEntry *entry,
index += entry->preedit_length;
else
{
- gint preedit_len_chars = g_utf8_strlen (text, -1) - gtk_entry_buffer_get_length (priv->buffer);
+ gint preedit_len_chars = g_utf8_strlen (text, -1) - gtk_entry_buffer_get_length (get_buffer (entry));
index += preedit_len_chars * g_unichar_to_utf8 (entry->invisible_char, NULL);
}
}
@@ -6062,11 +6051,10 @@ gtk_entry_move_logically (GtkEntry *entry,
gint start,
gint count)
{
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
gint new_pos = start;
guint length;
- length = gtk_entry_buffer_get_length (priv->buffer);
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
/* Prevent any leak of information */
if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL)
@@ -6109,11 +6097,10 @@ gtk_entry_move_forward_word (GtkEntry *entry,
gint start,
gboolean allow_whitespace)
{
- GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
gint new_pos = start;
guint length;
- length = gtk_entry_buffer_get_length (priv->buffer);
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
/* Prevent any leak of information */
if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL)
@@ -6257,7 +6244,7 @@ paste_received (GtkClipboard *clipboard,
length = truncate_multiline (text);
/* only complete if the selection is at the end */
- popup_completion = (gtk_entry_buffer_get_length (priv->buffer) ==
+ popup_completion = (gtk_entry_buffer_get_length (get_buffer (entry)) ==
MAX (entry->current_pos, entry->selection_bound));
if (completion)
@@ -6587,11 +6574,28 @@ gtk_entry_new_with_max_length (gint max)
max = CLAMP (max, 0, GTK_ENTRY_BUFFER_MAX_SIZE);
entry = g_object_new (GTK_TYPE_ENTRY, NULL);
- gtk_entry_buffer_set_max_length (GTK_ENTRY_GET_PRIVATE (entry)->buffer, max);
+ gtk_entry_buffer_set_max_length (get_buffer (entry), max);
return GTK_WIDGET (entry);
}
+
+static GtkEntryBuffer*
+get_buffer (GtkEntry *entry)
+{
+ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
+
+ if (priv->buffer == NULL)
+ {
+ GtkEntryBuffer *buffer;
+ buffer = gtk_entry_buffer_new (NULL, 0);
+ gtk_entry_set_buffer (entry, buffer);
+ g_object_unref (buffer);
+ }
+
+ return priv->buffer;
+}
+
/**
* gtk_entry_get_buffer:
* @entry: a #GtkEntry
@@ -6607,7 +6611,8 @@ GtkEntryBuffer*
gtk_entry_get_buffer (GtkEntry *entry)
{
g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
- return GTK_ENTRY_GET_PRIVATE (entry)->buffer;
+
+ return get_buffer (entry);
}
/**
@@ -6686,6 +6691,7 @@ void
gtk_entry_set_text (GtkEntry *entry,
const gchar *text)
{
+ gint tmp_pos;
GtkEntryCompletion *completion;
GtkEntryPrivate *priv;
@@ -6696,7 +6702,7 @@ gtk_entry_set_text (GtkEntry *entry,
/* Actually setting the text will affect the cursor and selection;
* if the contents don't actually change, this will look odd to the user.
*/
- if (strcmp (gtk_entry_buffer_get_text (priv->buffer), text) == 0)
+ if (strcmp (gtk_entry_buffer_get_text (get_buffer (entry)), text) == 0)
return;
completion = gtk_entry_get_completion (entry);
@@ -6705,7 +6711,9 @@ gtk_entry_set_text (GtkEntry *entry,
begin_change (entry);
g_object_freeze_notify (G_OBJECT (entry));
- gtk_entry_buffer_set_text (priv->buffer, text, -1);
+ gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
+ tmp_pos = 0;
+ gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos);
g_object_thaw_notify (G_OBJECT (entry));
end_change (entry);
@@ -6733,7 +6741,7 @@ gtk_entry_append_text (GtkEntry *entry,
g_return_if_fail (text != NULL);
priv = GTK_ENTRY_GET_PRIVATE (entry);
- tmp_pos = gtk_entry_buffer_get_length (priv->buffer);
+ tmp_pos = gtk_entry_buffer_get_length (get_buffer (entry));
gtk_editable_insert_text (GTK_EDITABLE (entry), text, -1, &tmp_pos);
}
@@ -7005,7 +7013,7 @@ G_CONST_RETURN gchar*
gtk_entry_get_text (GtkEntry *entry)
{
g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
- return gtk_entry_buffer_get_text (GTK_ENTRY_GET_PRIVATE (entry)->buffer);
+ return gtk_entry_buffer_get_text (get_buffer (entry));
}
/**
@@ -7052,7 +7060,7 @@ gtk_entry_set_max_length (GtkEntry *entry,
gint max)
{
g_return_if_fail (GTK_IS_ENTRY (entry));
- gtk_entry_buffer_set_max_length (GTK_ENTRY_GET_PRIVATE (entry)->buffer, max);
+ gtk_entry_buffer_set_max_length (get_buffer (entry), max);
}
/**
@@ -7075,7 +7083,7 @@ gint
gtk_entry_get_max_length (GtkEntry *entry)
{
g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
- return gtk_entry_buffer_get_max_length (GTK_ENTRY_GET_PRIVATE (entry)->buffer);
+ return gtk_entry_buffer_get_max_length (get_buffer (entry));
}
/**
@@ -7100,7 +7108,7 @@ guint16
gtk_entry_get_text_length (GtkEntry *entry)
{
g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
- return gtk_entry_buffer_get_length (GTK_ENTRY_GET_PRIVATE (entry)->buffer);
+ return gtk_entry_buffer_get_length (get_buffer (entry));
}
/**
@@ -7535,6 +7543,9 @@ gtk_entry_set_icon_from_pixbuf (GtkEntry *entry,
g_object_notify (G_OBJECT (entry), "secondary-icon-pixbuf");
g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type");
}
+
+ if (GTK_WIDGET_MAPPED (entry))
+ gdk_window_show_unraised (icon_info->window);
}
gtk_entry_ensure_pixbuf (entry, icon_pos);
@@ -7599,6 +7610,9 @@ gtk_entry_set_icon_from_stock (GtkEntry *entry,
g_object_notify (G_OBJECT (entry), "secondary-icon-stock");
g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type");
}
+
+ if (GTK_WIDGET_MAPPED (entry))
+ gdk_window_show_unraised (icon_info->window);
}
gtk_entry_ensure_pixbuf (entry, icon_pos);
@@ -7666,6 +7680,9 @@ gtk_entry_set_icon_from_icon_name (GtkEntry *entry,
g_object_notify (G_OBJECT (entry), "secondary-icon-name");
g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type");
}
+
+ if (GTK_WIDGET_MAPPED (entry))
+ gdk_window_show_unraised (icon_info->window);
}
gtk_entry_ensure_pixbuf (entry, icon_pos);
@@ -7730,6 +7747,9 @@ gtk_entry_set_icon_from_gicon (GtkEntry *entry,
g_object_notify (G_OBJECT (entry), "secondary-icon-gicon");
g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type");
}
+
+ if (GTK_WIDGET_MAPPED (entry))
+ gdk_window_show_unraised (icon_info->window);
}
gtk_entry_ensure_pixbuf (entry, icon_pos);
@@ -7973,9 +7993,14 @@ gtk_entry_set_icon_sensitive (GtkEntry *entry,
{
icon_info->insensitive = !sensitive;
+ icon_info->pressed = FALSE;
+ icon_info->prelight = FALSE;
+
if (GTK_WIDGET_REALIZED (GTK_WIDGET (entry)))
update_cursors (GTK_WIDGET (entry));
+ gtk_widget_queue_draw (GTK_WIDGET (entry));
+
g_object_notify (G_OBJECT (entry),
icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-sensitive" : "secondary-icon-sensitive");
}
@@ -8099,6 +8124,8 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry,
* #GtkWidget::drag-begin signal to set a different icon. Note that you
* have to use g_signal_connect_after() to ensure that your signal handler
* gets executed after the default handler.
+ *
+ * Since: 2.16
*/
void
gtk_entry_set_icon_drag_source (GtkEntry *entry,
@@ -8138,6 +8165,8 @@ gtk_entry_set_icon_drag_source (GtkEntry *entry,
*
* Returns: index of the icon which is the source of the current
* DND operation, or -1.
+ *
+ * Since: 2.16
*/
gint
gtk_entry_get_current_icon_drag_source (GtkEntry *entry)
@@ -9374,6 +9403,9 @@ keypress_completion_out:
event->keyval == GDK_KP_Enter ||
event->keyval == GDK_Return)
{
+ GtkTreeIter iter;
+ GtkTreeModel *model = NULL;
+ GtkTreeSelection *sel;
gboolean retval = TRUE;
_gtk_entry_reset_im_context (GTK_ENTRY (widget));
@@ -9381,9 +9413,6 @@ keypress_completion_out:
if (completion->priv->current_selected < matches)
{
- GtkTreeIter iter;
- GtkTreeModel *model = NULL;
- GtkTreeSelection *sel;
gboolean entry_set;
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
@@ -9415,15 +9444,18 @@ keypress_completion_out:
}
else if (completion->priv->current_selected - matches >= 0)
{
- GtkTreePath *path;
-
- _gtk_entry_reset_im_context (GTK_ENTRY (widget));
-
- path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
+ if (gtk_tree_selection_get_selected (sel, &model, &iter))
+ {
+ GtkTreePath *path;
- g_signal_emit_by_name (completion, "action-activated",
- gtk_tree_path_get_indices (path)[0]);
- gtk_tree_path_free (path);
+ path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
+ g_signal_emit_by_name (completion, "action-activated",
+ gtk_tree_path_get_indices (path)[0]);
+ gtk_tree_path_free (path);
+ }
+ else
+ retval = FALSE;
}
g_free (completion->priv->completion_prefix);
@@ -9494,7 +9526,7 @@ accept_completion_callback (GtkEntry *entry)
if (completion->priv->has_completion)
gtk_editable_set_position (GTK_EDITABLE (entry),
- gtk_entry_buffer_get_length (GTK_ENTRY_GET_PRIVATE (entry)->buffer));
+ gtk_entry_buffer_get_length (get_buffer (entry)));
return FALSE;
}
diff --git a/gtk/gtkentrybuffer.c b/gtk/gtkentrybuffer.c
index 865332714f..57ce3b325a 100644
--- a/gtk/gtkentrybuffer.c
+++ b/gtk/gtkentrybuffer.c
@@ -70,7 +70,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
struct _GtkEntryBufferPrivate
{
- guint max_length;
+ gint max_length;
/* Only valid if this class is not derived */
gchar *normal_text;
@@ -288,7 +288,7 @@ gtk_entry_buffer_set_property (GObject *obj,
gtk_entry_buffer_set_text (buffer, g_value_get_string (value), -1);
break;
case PROP_MAX_LENGTH:
- gtk_entry_buffer_set_max_length (buffer, g_value_get_uint (value));
+ gtk_entry_buffer_set_max_length (buffer, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -313,7 +313,7 @@ gtk_entry_buffer_get_property (GObject *obj,
g_value_set_uint (value, gtk_entry_buffer_get_length (buffer));
break;
case PROP_MAX_LENGTH:
- g_value_set_uint (value, gtk_entry_buffer_get_max_length (buffer));
+ g_value_set_int (value, gtk_entry_buffer_get_max_length (buffer));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -347,10 +347,13 @@ gtk_entry_buffer_class_init (GtkEntryBufferClass *klass)
*
* Since: 2.18
*/
- g_object_class_install_property (gobject_class, PROP_TEXT,
- g_param_spec_string ("text", P_("Text"),
- P_("The contents of the buffer"),
- "", GTK_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ P_("Text"),
+ P_("The contents of the buffer"),
+ "",
+ GTK_PARAM_READWRITE));
/**
* GtkEntryBuffer:length:
@@ -359,10 +362,13 @@ gtk_entry_buffer_class_init (GtkEntryBufferClass *klass)
*
* Since: 2.18
*/
- g_object_class_install_property (gobject_class, PROP_LENGTH,
- g_param_spec_uint ("length", P_("Text length"),
- P_("Length of the text currently in the buffer"),
- 0, GTK_ENTRY_BUFFER_MAX_SIZE, 0, GTK_PARAM_READABLE));
+ g_object_class_install_property (gobject_class,
+ PROP_LENGTH,
+ g_param_spec_uint ("length",
+ P_("Text length"),
+ P_("Length of the text currently in the buffer"),
+ 0, GTK_ENTRY_BUFFER_MAX_SIZE, 0,
+ GTK_PARAM_READABLE));
/**
* GtkEntryBuffer:max-length:
@@ -371,10 +377,13 @@ gtk_entry_buffer_class_init (GtkEntryBufferClass *klass)
*
* Since: 2.18
*/
- g_object_class_install_property (gobject_class, PROP_MAX_LENGTH,
- g_param_spec_uint ("max-length", P_("Maximum length"),
- P_("Maximum number of characters for this entry. Zero if no maximum"),
- 0, GTK_ENTRY_BUFFER_MAX_SIZE, 0, GTK_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_MAX_LENGTH,
+ g_param_spec_int ("max-length",
+ P_("Maximum length"),
+ P_("Maximum number of characters for this entry. Zero if no maximum"),
+ 0, GTK_ENTRY_BUFFER_MAX_SIZE, 0,
+ GTK_PARAM_READWRITE));
/**
* GtkEntry::inserted-text:
@@ -511,7 +520,7 @@ gtk_entry_buffer_get_bytes (GtkEntryBuffer *buffer)
*
* Since: 2.18
**/
-const gchar*
+G_CONST_RETURN gchar*
gtk_entry_buffer_get_text (GtkEntryBuffer *buffer)
{
GtkEntryBufferClass *klass;
@@ -568,12 +577,11 @@ gtk_entry_buffer_set_text (GtkEntryBuffer *buffer,
**/
void
gtk_entry_buffer_set_max_length (GtkEntryBuffer *buffer,
- guint max_length)
+ gint max_length)
{
g_return_if_fail (GTK_IS_ENTRY_BUFFER (buffer));
- if (max_length > GTK_ENTRY_BUFFER_MAX_SIZE)
- max_length = GTK_ENTRY_BUFFER_MAX_SIZE;
+ max_length = CLAMP (max_length, 0, GTK_ENTRY_BUFFER_MAX_SIZE);
if (max_length > 0 && gtk_entry_buffer_get_length (buffer) > max_length)
gtk_entry_buffer_delete_text (buffer, max_length, -1);
@@ -593,8 +601,8 @@ gtk_entry_buffer_set_max_length (GtkEntryBuffer *buffer,
* in #GtkEntryBuffer, or 0 if there is no maximum.
*
* Since: 2.18
- **/
-guint
+ */
+gint
gtk_entry_buffer_get_max_length (GtkEntryBuffer *buffer)
{
g_return_val_if_fail (GTK_IS_ENTRY_BUFFER (buffer), 0);
diff --git a/gtk/gtkentrybuffer.h b/gtk/gtkentrybuffer.h
index 275aaa1b3b..20556cb9e8 100644
--- a/gtk/gtkentrybuffer.h
+++ b/gtk/gtkentrybuffer.h
@@ -99,16 +99,16 @@ gsize gtk_entry_buffer_get_bytes (GtkEntryBuffe
guint gtk_entry_buffer_get_length (GtkEntryBuffer *buffer);
-const gchar* gtk_entry_buffer_get_text (GtkEntryBuffer *buffer);
+G_CONST_RETURN gchar* gtk_entry_buffer_get_text (GtkEntryBuffer *buffer);
void gtk_entry_buffer_set_text (GtkEntryBuffer *buffer,
const gchar *chars,
gint n_chars);
void gtk_entry_buffer_set_max_length (GtkEntryBuffer *buffer,
- guint max_length);
+ gint max_length);
-guint gtk_entry_buffer_get_max_length (GtkEntryBuffer *buffer);
+gint gtk_entry_buffer_get_max_length (GtkEntryBuffer *buffer);
guint gtk_entry_buffer_insert_text (GtkEntryBuffer *buffer,
guint position,
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index f113bea1f0..6c7de57225 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -269,6 +269,22 @@ gtk_file_chooser_class_init (gpointer g_iface)
"if necessary."),
FALSE,
GTK_PARAM_READWRITE));
+
+ /**
+ * GtkFileChooser:create-folders:
+ *
+ * Whether a file chooser not in %GTK_FILE_CHOOSER_ACTION_OPEN mode
+ * will offer the user to create new folders.
+ *
+ * Since: 2.18
+ */
+ g_object_interface_install_property (g_iface,
+ g_param_spec_boolean ("create-folders",
+ P_("Allow folders creation"),
+ P_("Whether a file chooser not in open mode "
+ "will offer the user to create new folders."),
+ TRUE,
+ GTK_PARAM_READWRITE));
}
/**
@@ -424,6 +440,49 @@ gtk_file_chooser_get_select_multiple (GtkFileChooser *chooser)
}
/**
+ * gtk_file_chooser_set_create_folders:
+ * @chooser: a #GtkFileChooser
+ * @create_folders: %TRUE if the New Folder button should be displayed
+ *
+ * Sets whether file choser will offer to create new folders.
+ * This is only relevant if the action is not set to be
+ * GTK_FILE_CHOOSER_ACTION_OPEN.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_file_chooser_set_create_folders (GtkFileChooser *chooser,
+ gboolean create_folders)
+{
+ g_return_if_fail (GTK_IS_FILE_CHOOSER (chooser));
+
+ g_object_set (chooser, "create-folders", create_folders, NULL);
+}
+
+/**
+ * gtk_file_chooser_get_create_folders:
+ * @chooser: a #GtkFileChooser
+ *
+ * Gets whether file choser will offer to create new folders.
+ * See gtk_file_chooser_set_create_folders().
+ *
+ * Return value: %TRUE if the New Folder button should be displayed.
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_file_chooser_get_create_folders (GtkFileChooser *chooser)
+{
+ gboolean create_folders;
+
+ g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), FALSE);
+
+ g_object_get (chooser, "create-folders", &create_folders, NULL);
+
+ return create_folders;
+}
+
+/**
* gtk_file_chooser_get_filename:
* @chooser: a #GtkFileChooser
*
@@ -1180,7 +1239,8 @@ gtk_file_chooser_set_file (GtkFileChooser *chooser,
* If the file chooser is in folder mode, this function returns the selected
* folder.
*
- * Returns: a selected #GFile
+ * Returns: a selected #GFile. You own the returned file; use
+ * g_object_unref() to release it.
*
* Since: 2.14
**/
diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h
index b7983a9660..0772690bd2 100644
--- a/gtk/gtkfilechooser.h
+++ b/gtk/gtkfilechooser.h
@@ -85,6 +85,10 @@ void gtk_file_chooser_set_do_overwrite_confirmation (GtkFileChoo
gboolean do_overwrite_confirmation);
gboolean gtk_file_chooser_get_do_overwrite_confirmation (GtkFileChooser *chooser);
+void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser,
+ gboolean create_folders);
+gboolean gtk_file_chooser_get_create_folders (GtkFileChooser *chooser);
+
/* Suggested name for the Save-type actions
*/
void gtk_file_chooser_set_current_name (GtkFileChooser *chooser,
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index 3b95adeeda..70b0b4f268 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -810,6 +810,7 @@ gtk_file_chooser_button_set_property (GObject *object,
case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
+ case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
g_object_set_property (G_OBJECT (priv->dialog), pspec->name, value);
break;
@@ -2301,6 +2302,12 @@ update_label_and_image (GtkFileChooserButton *button)
label_text = NULL;
pixbuf = NULL;
+ if (priv->update_button_cancellable)
+ {
+ g_cancellable_cancel (priv->update_button_cancellable);
+ priv->update_button_cancellable = NULL;
+ }
+
if (files && files->data)
{
GFile *file;
@@ -2332,12 +2339,6 @@ update_label_and_image (GtkFileChooserButton *button)
goto out;
}
- if (priv->update_button_cancellable)
- {
- g_cancellable_cancel (priv->update_button_cancellable);
- priv->update_button_cancellable = NULL;
- }
-
if (g_file_is_native (file))
{
priv->update_button_cancellable =
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 388129ae5e..1dcd09f447 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -191,30 +191,37 @@ typedef enum {
SHORTCUT_TYPE_RECENT
} ShortcutType;
-/* Column numbers for the search model.
- * Keep this in sync with search_setup_model()
- */
+#define MODEL_ATTRIBUTES "standard::name,standard::type,standard::display-name," \
+ "standard::is-hidden,standard::is-backup,standard::size," \
+ "standard::content-type,time::modified"
enum {
- SEARCH_MODEL_COL_FILE,
- SEARCH_MODEL_COL_DISPLAY_NAME,
- SEARCH_MODEL_COL_COLLATION_KEY,
- SEARCH_MODEL_COL_MTIME,
- SEARCH_MODEL_COL_SIZE,
- SEARCH_MODEL_COL_CANCELLABLE,
- SEARCH_MODEL_COL_PIXBUF,
- SEARCH_MODEL_COL_MIME_TYPE,
- SEARCH_MODEL_COL_IS_FOLDER,
- SEARCH_MODEL_COL_NUM_COLUMNS
+ /* the first 3 must be these due to settings caching sort column */
+ MODEL_COL_NAME,
+ MODEL_COL_SIZE,
+ MODEL_COL_MTIME,
+ MODEL_COL_FILE,
+ MODEL_COL_NAME_COLLATED,
+ MODEL_COL_IS_FOLDER,
+ MODEL_COL_PIXBUF,
+ MODEL_COL_SIZE_TEXT,
+ MODEL_COL_MTIME_TEXT,
+ MODEL_COL_ELLIPSIZE,
+ MODEL_COL_NUM_COLUMNS
};
-enum {
- RECENT_MODEL_COL_FILE,
- RECENT_MODEL_COL_DISPLAY_NAME,
- RECENT_MODEL_COL_INFO,
- RECENT_MODEL_COL_IS_FOLDER,
- RECENT_MODEL_COL_CANCELLABLE,
- RECENT_MODEL_COL_NUM_COLUMNS
-};
+/* This list of types is passed to _gtk_file_system_model_new*() */
+#define MODEL_COLUMN_TYPES \
+ MODEL_COL_NUM_COLUMNS, \
+ G_TYPE_STRING, /* MODEL_COL_NAME */ \
+ G_TYPE_INT64, /* MODEL_COL_SIZE */ \
+ G_TYPE_LONG, /* MODEL_COL_MTIME */ \
+ G_TYPE_FILE, /* MODEL_COL_FILE */ \
+ G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \
+ G_TYPE_BOOLEAN, /* MODEL_COL_IS_FOLDER */ \
+ GDK_TYPE_PIXBUF, /* MODEL_COL_PIXBUF */ \
+ G_TYPE_STRING, /* MODEL_COL_SIZE_TEXT */ \
+ G_TYPE_STRING, /* MODEL_COL_MTIME_TEXT */ \
+ PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */
/* Identifiers for target types */
enum {
@@ -376,11 +383,6 @@ static void list_row_activated (GtkTreeView *tree_view,
GtkTreeViewColumn *column,
GtkFileChooserDefault *impl);
-static void select_func (GtkFileSystemModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data);
-
static void path_bar_clicked (GtkPathBar *path_bar,
GFile *file,
GFile *child,
@@ -394,29 +396,7 @@ static void remove_bookmark_button_clicked_cb (GtkButton *button,
static void save_folder_combo_changed_cb (GtkComboBox *combo,
GtkFileChooserDefault *impl);
-static void list_icon_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data);
-static void list_name_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data);
-static void list_size_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data);
-static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data);
-
-static GFileInfo *get_list_file_info (GtkFileChooserDefault *impl,
- GtkTreeIter *iter);
+static void update_cell_renderer_attributes (GtkFileChooserDefault *impl);
static void load_remove_timer (GtkFileChooserDefault *impl);
static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
@@ -427,8 +407,6 @@ static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
static void search_stop_searching (GtkFileChooserDefault *impl,
gboolean remove_query);
-static void search_clear_model_row (GtkTreeModel *model,
- GtkTreeIter *iter);
static void search_clear_model (GtkFileChooserDefault *impl,
gboolean remove_from_treeview);
static gboolean search_should_respond (GtkFileChooserDefault *impl);
@@ -437,9 +415,6 @@ static GSList *search_get_selected_files (GtkFileChooserDefault *impl);
static void search_entry_activate_cb (GtkEntry *entry,
gpointer data);
static void settings_load (GtkFileChooserDefault *impl);
-static void search_get_valid_child_iter (GtkFileChooserDefault *impl,
- GtkTreeIter *child_iter,
- GtkTreeIter *iter);
static void recent_stop_loading (GtkFileChooserDefault *impl);
static void recent_clear_model (GtkFileChooserDefault *impl,
@@ -447,9 +422,6 @@ static void recent_clear_model (GtkFileChooserDefault *impl,
static gboolean recent_should_respond (GtkFileChooserDefault *impl);
static void recent_switch_to_browse_mode (GtkFileChooserDefault *impl);
static GSList * recent_get_selected_files (GtkFileChooserDefault *impl);
-static void recent_get_valid_child_iter (GtkFileChooserDefault *impl,
- GtkTreeIter *child_iter,
- GtkTreeIter *iter);
static void set_file_system_backend (GtkFileChooserDefault *impl);
static void unset_file_system_backend (GtkFileChooserDefault *impl);
@@ -484,56 +456,6 @@ static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *imp
GtkTreeModel *child_model,
GtkTreePath *root);
-
-typedef struct {
- GtkTreeModelSort parent;
-
- GtkFileChooserDefault *impl;
-} RecentModelSort;
-
-typedef struct {
- GtkTreeModelSortClass parent_class;
-} RecentModelSortClass;
-
-#define RECENT_MODEL_SORT_TYPE (_recent_model_sort_get_type ())
-#define RECENT_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RECENT_MODEL_SORT_TYPE, RecentModelSort))
-
-static void recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (RecentModelSort,
- _recent_model_sort,
- GTK_TYPE_TREE_MODEL_SORT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
- recent_model_sort_drag_source_iface_init));
-
-static GtkTreeModel *recent_model_sort_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model);
-
-
-typedef struct {
- GtkTreeModelSort parent;
-
- GtkFileChooserDefault *impl;
-} SearchModelSort;
-
-typedef struct {
- GtkTreeModelSortClass parent_class;
-} SearchModelSortClass;
-
-#define SEARCH_MODEL_SORT_TYPE (_search_model_sort_get_type ())
-#define SEARCH_MODEL_SORT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SEARCH_MODEL_SORT_TYPE, SearchModelSort))
-
-static void search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (SearchModelSort,
- _search_model_sort,
- GTK_TYPE_TREE_MODEL_SORT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
- search_model_sort_drag_source_iface_init));
-
-static GtkTreeModel *search_model_sort_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model);
-
G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX,
@@ -798,9 +720,10 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
impl->pending_select_files = NULL;
impl->location_mode = LOCATION_MODE_PATH_BAR;
impl->operation_mode = OPERATION_MODE_BROWSE;
- impl->sort_column = FILE_LIST_COL_NAME;
+ impl->sort_column = MODEL_COL_NAME;
impl->sort_order = GTK_SORT_ASCENDING;
impl->recent_manager = gtk_recent_manager_get_default ();
+ impl->create_folders = TRUE;
gtk_box_set_spacing (GTK_BOX (impl), 12);
@@ -894,14 +817,11 @@ store_selection_foreach (GtkTreeModel *model,
gpointer data)
{
GtkFileChooserDefault *impl;
- GtkTreeIter child_iter;
GFile *file;
impl = GTK_FILE_CHOOSER_DEFAULT (data);
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
-
- file = _gtk_file_system_model_get_file (impl->browse_files_model, &child_iter);
+ file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (model), iter);
pending_select_files_add (impl, file);
}
@@ -965,9 +885,6 @@ gtk_file_chooser_default_finalize (GObject *object)
if (impl->browse_files_model)
g_object_unref (impl->browse_files_model);
- if (impl->sort_model)
- g_object_unref (impl->sort_model);
-
search_clear_model (impl, FALSE);
recent_clear_model (impl, FALSE);
@@ -2637,36 +2554,17 @@ add_bookmark_foreach_cb (GtkTreeModel *model,
gpointer data)
{
GtkFileChooserDefault *impl;
- GtkFileSystemModel *fs_model;
- GtkTreeIter child_iter;
GFile *file;
impl = (GtkFileChooserDefault *) data;
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_BROWSE:
- fs_model = impl->browse_files_model;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
- file = _gtk_file_system_model_get_file (fs_model, &child_iter);
- break;
-
- case OPERATION_MODE_SEARCH:
- search_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_FILE, &file,
- -1);
- break;
-
- case OPERATION_MODE_RECENT:
- recent_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &file,
- -1);
- break;
- }
+ gtk_tree_model_get (model, iter,
+ MODEL_COL_FILE, &file,
+ -1);
shortcuts_add_bookmark_from_file (impl, file, -1);
+
+ g_object_unref (file);
}
/* Adds a bookmark from the currently selected item in the file list */
@@ -2770,35 +2668,21 @@ selection_check_foreach_cb (GtkTreeModel *model,
gpointer data)
{
struct selection_check_closure *closure;
- GtkTreeIter child_iter;
- GFileInfo *info;
gboolean is_folder;
+ GFile *file;
- closure = data;
- closure->num_selected++;
+ gtk_tree_model_get (model, iter,
+ MODEL_COL_FILE, &file,
+ MODEL_COL_IS_FOLDER, &is_folder,
+ -1);
- switch (closure->impl->operation_mode)
- {
- case OPERATION_MODE_BROWSE:
- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
- info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
- is_folder = info ? (_gtk_file_info_consider_as_directory (info)) : FALSE;
- break;
+ if (file == NULL)
+ return;
- case OPERATION_MODE_SEARCH:
- search_get_valid_child_iter (closure->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
- break;
+ g_object_unref (file);
- case OPERATION_MODE_RECENT:
- recent_get_valid_child_iter (closure->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
- break;
- }
+ closure = data;
+ closure->num_selected++;
closure->all_folders = closure->all_folders && is_folder;
closure->all_files = closure->all_files && !is_folder;
@@ -2847,32 +2731,18 @@ get_selected_file_foreach_cb (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
- struct get_selected_file_closure *closure;
- GtkTreeIter child_iter;
+ struct get_selected_file_closure *closure = data;
- closure = data;
-
- switch (closure->impl->operation_mode)
+ if (closure->file)
{
- case OPERATION_MODE_BROWSE:
- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
- closure->file = _gtk_file_system_model_get_file (closure->impl->browse_files_model, &child_iter);
- break;
-
- case OPERATION_MODE_SEARCH:
- search_get_valid_child_iter (closure->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->search_model), &child_iter,
- SEARCH_MODEL_COL_FILE, &closure->file,
- -1);
- break;
-
- case OPERATION_MODE_RECENT:
- recent_get_valid_child_iter (closure->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (closure->impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &closure->file,
- -1);
- break;
+ /* Just in case this function gets run more than once with a multiple selection; we only care about one file */
+ g_object_unref (closure->file);
+ closure->file = NULL;
}
+
+ gtk_tree_model_get (model, iter,
+ MODEL_COL_FILE, &closure->file, /* this will give us a reffed file */
+ -1);
}
/* Returns a selected path from the file list */
@@ -2905,40 +2775,18 @@ update_tooltip (GtkTreeModel *model,
gpointer data)
{
UpdateTooltipData *udata = data;
- GtkTreeIter child_iter;
- GFileInfo *info;
if (udata->tip == NULL)
{
- const gchar *display_name;
-
- switch (udata->impl->operation_mode)
- {
- case OPERATION_MODE_BROWSE:
- gtk_tree_model_sort_convert_iter_to_child_iter (udata->impl->sort_model,
- &child_iter,
- iter);
- info = _gtk_file_system_model_get_info (udata->impl->browse_files_model, &child_iter);
- display_name = g_file_info_get_display_name (info);
- break;
-
- case OPERATION_MODE_SEARCH:
- search_get_valid_child_iter (udata->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->search_model), &child_iter,
- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
- -1);
- break;
+ gchar *display_name;
- case OPERATION_MODE_RECENT:
- recent_get_valid_child_iter (udata->impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (udata->impl->recent_model), &child_iter,
- RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
- -1);
- break;
- }
+ gtk_tree_model_get (model, iter,
+ MODEL_COL_NAME, &display_name,
+ -1);
udata->tip = g_strdup_printf (_("Add the folder '%s' to the bookmarks"),
display_name);
+ g_free (display_name);
}
}
@@ -2964,7 +2812,9 @@ bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl)
GFile *file;
file = get_selected_file (impl);
- active = all_folders && (shortcut_find_position (impl, file) == -1);
+ active = file && all_folders && (shortcut_find_position (impl, file) == -1);
+ if (file)
+ g_object_unref (file);
}
else
active = all_folders;
@@ -3007,24 +2857,27 @@ bookmarks_check_remove_sensitivity (GtkFileChooserDefault *impl)
GtkTreeIter iter;
gboolean removable = FALSE;
gchar *name = NULL;
+ gchar *tip;
if (shortcuts_get_selected (impl, &iter))
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
- SHORTCUTS_COL_REMOVABLE, &removable,
- SHORTCUTS_COL_NAME, &name,
- -1);
-
- gtk_widget_set_sensitive (impl->browse_shortcuts_remove_button, removable);
-
- if (removable)
{
- gchar *tip;
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_REMOVABLE, &removable,
+ SHORTCUTS_COL_NAME, &name,
+ -1);
+ gtk_widget_set_sensitive (impl->browse_shortcuts_remove_button, removable);
+
+ if (removable)
+ tip = g_strdup_printf (_("Remove the bookmark '%s'"), name);
+ else
+ tip = g_strdup_printf (_("Bookmark '%s' cannot be removed"), name);
- tip = g_strdup_printf (_("Remove the bookmark '%s'"), name);
gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button, tip);
g_free (tip);
}
-
+ else
+ gtk_widget_set_tooltip_text (impl->browse_shortcuts_remove_button,
+ _("Remove the selected bookmark"));
g_free (name);
}
@@ -3649,26 +3502,34 @@ shortcuts_row_separator_func (GtkTreeModel *model,
return shortcut_type == SHORTCUT_TYPE_SEPARATOR;
}
-/* Since GtkTreeView has a keybinding attached to '/', we need to catch
- * keypresses before the TreeView gets them.
- */
static gboolean
-tree_view_keybinding_cb (GtkWidget *tree_view,
- GdkEventKey *event,
- GtkFileChooserDefault *impl)
+shortcuts_key_press_event_after_cb (GtkWidget *tree_view,
+ GdkEventKey *event,
+ GtkFileChooserDefault *impl)
{
- if ((event->keyval == GDK_slash
- || event->keyval == GDK_KP_Divide
-#ifdef G_OS_UNIX
- || event->keyval == GDK_asciitilde
-#endif
- ) && ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+ GtkWidget *entry;
+
+ /* don't screw up focus switching with Tab */
+ if (event->keyval == GDK_Tab
+ || event->keyval == GDK_KP_Tab
+ || event->keyval == GDK_ISO_Left_Tab
+ || event->length < 1)
+ return FALSE;
+
+ if (impl->location_entry)
+ entry = impl->location_entry;
+ else if (impl->search_entry)
+ entry = impl->search_entry;
+ else
+ entry = NULL;
+
+ if (entry)
{
- location_popup_handler (impl, event->string);
- return TRUE;
+ gtk_widget_grab_focus (entry);
+ return gtk_widget_event (entry, (GdkEvent *) event);
}
-
- return FALSE;
+ else
+ return FALSE;
}
/* Callback used when the file list's popup menu is detached */
@@ -3883,11 +3744,28 @@ shortcuts_list_create (GtkFileChooserDefault *impl)
/* Tree */
impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
+ gtk_tree_view_set_enable_search (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), FALSE);
#ifdef PROFILE_FILE_CHOOSER
g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "fmq-name", "shortcuts");
#endif
- g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
- G_CALLBACK (tree_view_keybinding_cb), impl);
+
+ /* Connect "after" to key-press-event on the shortcuts pane. We want this action to be possible:
+ *
+ * 1. user brings up a SAVE dialog
+ * 2. user clicks on a shortcut in the shortcuts pane
+ * 3. user starts typing a filename
+ *
+ * Normally, the user's typing would be ignored, as the shortcuts treeview doesn't
+ * support interactive search. However, we'd rather focus the location entry
+ * so that the user can type *there*.
+ *
+ * To preserve keyboard navigation in the shortcuts pane, we don't focus the
+ * filename entry if one clicks on a shortcut; rather, we focus the entry only
+ * if the user starts typing while the focus is in the shortcuts pane.
+ */
+ g_signal_connect_after (impl->browse_shortcuts_tree_view, "key-press-event",
+ G_CALLBACK (shortcuts_key_press_event_after_cb), impl);
+
g_signal_connect (impl->browse_shortcuts_tree_view, "popup-menu",
G_CALLBACK (shortcuts_popup_menu_cb), impl);
g_signal_connect (impl->browse_shortcuts_tree_view, "button-press-event",
@@ -4030,14 +3908,28 @@ shortcuts_pane_create (GtkFileChooserDefault *impl,
return vbox;
}
+static gboolean
+key_is_left_or_right (GdkEventKey *event)
+{
+ guint modifiers;
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ return ((event->keyval == GDK_Right
+ || event->keyval == GDK_KP_Right
+ || event->keyval == GDK_Left
+ || event->keyval == GDK_KP_Left)
+ && (event->state & modifiers) == 0);
+}
+
/* Handles key press events on the file list, so that we can trap Enter to
* activate the default button on our own. Also, checks to see if '/' has been
* pressed. See comment by tree_view_keybinding_cb() for more details.
*/
static gboolean
-trap_activate_cb (GtkWidget *widget,
- GdkEventKey *event,
- gpointer data)
+browse_files_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer data)
{
GtkFileChooserDefault *impl;
int modifiers;
@@ -4057,6 +3949,12 @@ trap_activate_cb (GtkWidget *widget,
return TRUE;
}
+ if (key_is_left_or_right (event))
+ {
+ gtk_widget_grab_focus (impl->browse_shortcuts_tree_view);
+ return TRUE;
+ }
+
if ((event->keyval == GDK_Return
|| event->keyval == GDK_ISO_Enter
|| event->keyval == GDK_KP_Enter
@@ -4122,9 +4020,8 @@ show_size_column_toggled_cb (GtkCheckMenuItem *item,
{
impl->show_size_column = gtk_check_menu_item_get_active (item);
- if (impl->list_size_column)
- gtk_tree_view_column_set_visible (impl->list_size_column,
- impl->show_size_column);
+ gtk_tree_view_column_set_visible (impl->list_size_column,
+ impl->show_size_column);
}
/* Shows an error dialog about not being able to select a dragged file */
@@ -4461,64 +4358,13 @@ typedef struct {
gint model_column;
} ColumnMap;
-/* Sigh. Each operation mode has different sort column IDs. This table
- * translates between them.
- */
-static const ColumnMap column_map[] = {
- { OPERATION_MODE_BROWSE, FILE_LIST_COL_NAME, FILE_LIST_COL_NAME },
- { OPERATION_MODE_BROWSE, FILE_LIST_COL_SIZE, FILE_LIST_COL_SIZE },
- { OPERATION_MODE_BROWSE, FILE_LIST_COL_MTIME, FILE_LIST_COL_MTIME },
-
- { OPERATION_MODE_SEARCH, FILE_LIST_COL_NAME, SEARCH_MODEL_COL_FILE },
- { OPERATION_MODE_SEARCH, FILE_LIST_COL_SIZE, SEARCH_MODEL_COL_SIZE },
- { OPERATION_MODE_SEARCH, FILE_LIST_COL_MTIME, SEARCH_MODEL_COL_MTIME },
-
- { OPERATION_MODE_RECENT, FILE_LIST_COL_NAME, RECENT_MODEL_COL_FILE },
- { OPERATION_MODE_RECENT, FILE_LIST_COL_SIZE, 0 },
- { OPERATION_MODE_RECENT, FILE_LIST_COL_MTIME, RECENT_MODEL_COL_INFO }
-};
-
-static gint
-general_column_to_model_column (GtkFileChooserDefault *impl, gint general_column)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (column_map); i++)
- if (column_map[i].operation_mode == impl->operation_mode
- && column_map[i].general_column == general_column)
- return column_map[i].model_column;
-
- g_assert_not_reached ();
- return 0;
-}
-
-static gint
-model_column_to_general_column (GtkFileChooserDefault *impl, gint model_column)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (column_map); i++)
- if (column_map[i].operation_mode == impl->operation_mode
- && column_map[i].model_column == model_column)
- return column_map[i].general_column;
-
- g_assert_not_reached ();
- return 0;
-}
-
/* Sets the sort column IDs for the file list based on the operation mode */
static void
file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
{
- int name_id, mtime_id, size_id;
-
- name_id = general_column_to_model_column (impl, FILE_LIST_COL_NAME);
- mtime_id = general_column_to_model_column (impl, FILE_LIST_COL_MTIME);
- size_id = general_column_to_model_column (impl, FILE_LIST_COL_SIZE);
-
- gtk_tree_view_column_set_sort_column_id (impl->list_name_column, name_id);
- gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, mtime_id);
- gtk_tree_view_column_set_sort_column_id (impl->list_size_column, size_id);
+ gtk_tree_view_column_set_sort_column_id (impl->list_name_column, MODEL_COL_NAME);
+ gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, MODEL_COL_MTIME);
+ gtk_tree_view_column_set_sort_column_id (impl->list_size_column, MODEL_COL_SIZE);
}
static gboolean
@@ -4530,8 +4376,9 @@ file_list_query_tooltip_cb (GtkWidget *widget,
gpointer user_data)
{
GtkFileChooserDefault *impl = user_data;
- GtkTreeIter iter, child_iter;
- GtkTreePath *path = NULL;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
GFile *file;
gchar *filename;
@@ -4539,48 +4386,17 @@ file_list_query_tooltip_cb (GtkWidget *widget,
return FALSE;
- gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (impl->browse_files_tree_view),
- &x, &y,
- keyboard_tip,
- NULL, &path, NULL);
-
- if (!path)
+ if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (impl->browse_files_tree_view),
+ &x, &y,
+ keyboard_tip,
+ &model, &path, &iter))
return FALSE;
+
+ gtk_tree_model_get (model, &iter,
+ MODEL_COL_FILE, &file,
+ -1);
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_SEARCH:
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
- {
- gtk_tree_path_free (path);
- return FALSE;
- }
-
- search_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_FILE, &file,
- -1);
- break;
-
- case OPERATION_MODE_RECENT:
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
- {
- gtk_tree_path_free (path);
- return FALSE;
- }
-
- recent_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &file,
- -1);
- break;
-
- case OPERATION_MODE_BROWSE:
- g_assert_not_reached ();
- return FALSE;
- }
-
- if (!file)
+ if (file == NULL)
{
gtk_tree_path_free (path);
return FALSE;
@@ -4593,11 +4409,20 @@ file_list_query_tooltip_cb (GtkWidget *widget,
path);
g_free (filename);
+ g_object_unref (file);
gtk_tree_path_free (path);
return TRUE;
}
+static void
+set_icon_cell_renderer_fixed_size (GtkFileChooserDefault *impl, GtkCellRenderer *renderer)
+{
+ gtk_cell_renderer_set_fixed_size (renderer,
+ renderer->xpad * 2 + impl->icon_size,
+ renderer->ypad * 2 + impl->icon_size);
+}
+
/* Creates the widgets for the file list */
static GtkWidget *
create_file_list (GtkFileChooserDefault *impl)
@@ -4635,7 +4460,7 @@ create_file_list (GtkFileChooserDefault *impl)
g_signal_connect (impl->browse_files_tree_view, "row-activated",
G_CALLBACK (list_row_activated), impl);
g_signal_connect (impl->browse_files_tree_view, "key-press-event",
- G_CALLBACK (trap_activate_cb), impl);
+ G_CALLBACK (browse_files_key_press_event_cb), impl);
g_signal_connect (impl->browse_files_tree_view, "popup-menu",
G_CALLBACK (list_popup_menu_cb), impl);
g_signal_connect (impl->browse_files_tree_view, "button-press-event",
@@ -4665,6 +4490,8 @@ create_file_list (GtkFileChooserDefault *impl)
g_signal_connect (selection, "changed",
G_CALLBACK (list_selection_changed), impl);
+ /* Keep the column order in sync with update_cell_renderer_attributes() */
+
/* Filename column */
impl->list_name_column = gtk_tree_view_column_new ();
@@ -4673,9 +4500,9 @@ create_file_list (GtkFileChooserDefault *impl)
gtk_tree_view_column_set_title (impl->list_name_column, _("Name"));
renderer = gtk_cell_renderer_pixbuf_new ();
+ /* We set a fixed size so that we get an empty slot even if no icons are loaded yet */
+ set_icon_cell_renderer_fixed_size (impl, renderer);
gtk_tree_view_column_pack_start (impl->list_name_column, renderer, FALSE);
- gtk_tree_view_column_set_cell_data_func (impl->list_name_column, renderer,
- list_icon_data_func, impl, NULL);
impl->list_name_renderer = gtk_cell_renderer_text_new ();
g_object_set (impl->list_name_renderer,
@@ -4686,8 +4513,6 @@ create_file_list (GtkFileChooserDefault *impl)
g_signal_connect (impl->list_name_renderer, "editing-canceled",
G_CALLBACK (renderer_editing_canceled_cb), impl);
gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
- gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
- list_name_data_func, impl, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), impl->list_name_column);
@@ -4702,8 +4527,6 @@ create_file_list (GtkFileChooserDefault *impl)
"alignment", PANGO_ALIGN_RIGHT,
NULL);
gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
- gtk_tree_view_column_set_cell_data_func (column, renderer,
- list_size_data_func, impl, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
impl->list_size_column = column;
@@ -4715,12 +4538,11 @@ create_file_list (GtkFileChooserDefault *impl)
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_cell_data_func (column, renderer,
- list_mtime_data_func, impl, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
impl->list_mtime_column = column;
file_list_set_sort_column_ids (impl);
+ update_cell_renderer_attributes (impl);
gtk_widget_show_all (swin);
@@ -4813,6 +4635,39 @@ save_folder_combo_changed_cb (GtkComboBox *combo,
}
}
+static void
+save_folder_update_tooltip (GtkComboBox *combo,
+ GtkFileChooserDefault *impl)
+{
+ GtkTreeIter iter;
+ gchar *tooltip;
+
+ tooltip = NULL;
+
+ if (gtk_combo_box_get_active_iter (combo, &iter))
+ {
+ GtkTreeIter child_iter;
+ gpointer col_data;
+ ShortcutType shortcut_type;
+
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+ &child_iter,
+ &iter);
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &child_iter,
+ SHORTCUTS_COL_DATA, &col_data,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
+ -1);
+
+ if (shortcut_type == SHORTCUT_TYPE_FILE)
+ tooltip = g_file_get_parse_name (G_FILE (col_data));
+ }
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET (combo), tooltip);
+ gtk_widget_set_has_tooltip (GTK_WIDGET (combo),
+ gtk_widget_get_sensitive (GTK_WIDGET (combo)));
+ g_free (tooltip);
+}
+
/* Filter function used to filter out the Search item and its separator.
* Used for the "Save in folder" combo box, so that these items do not appear in it.
*/
@@ -4904,6 +4759,8 @@ save_folder_combo_create (GtkFileChooserDefault *impl)
g_signal_connect (combo, "changed",
G_CALLBACK (save_folder_combo_changed_cb), impl);
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (save_folder_update_tooltip), impl);
return combo;
}
@@ -5512,12 +5369,14 @@ update_appearance (GtkFileChooserDefault *impl)
{
gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
gtk_widget_set_sensitive (impl->save_folder_combo, FALSE);
+ gtk_widget_set_has_tooltip (impl->save_folder_combo, FALSE);
gtk_widget_show (impl->browse_widgets);
}
else
{
gtk_widget_set_sensitive (impl->save_folder_label, TRUE);
gtk_widget_set_sensitive (impl->save_folder_combo, TRUE);
+ gtk_widget_set_has_tooltip (impl->save_folder_combo, TRUE);
gtk_widget_hide (impl->browse_widgets);
}
@@ -5540,7 +5399,7 @@ update_appearance (GtkFileChooserDefault *impl)
if (impl->location_entry)
_gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || !impl->create_folders)
gtk_widget_hide (impl->browse_new_folder_button);
else
gtk_widget_show (impl->browse_new_folder_button);
@@ -5582,6 +5441,7 @@ gtk_file_chooser_default_set_property (GObject *object,
set_select_multiple (impl, FALSE, TRUE);
}
impl->action = action;
+ update_cell_renderer_attributes (impl);
update_appearance (impl);
settings_load (impl);
}
@@ -5655,6 +5515,14 @@ gtk_file_chooser_default_set_property (GObject *object,
}
break;
+ case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
+ {
+ gboolean create_folders = g_value_get_boolean (value);
+ impl->create_folders = create_folders;
+ update_appearance (impl);
+ }
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -5711,6 +5579,10 @@ gtk_file_chooser_default_get_property (GObject *object,
g_value_set_boolean (value, impl->do_overwrite_confirmation);
break;
+ case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
+ g_value_set_boolean (value, impl->create_folders);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -5793,12 +5665,6 @@ gtk_file_chooser_default_dispose (GObject *object)
impl->update_current_folder_cancellable = NULL;
}
- if (impl->show_and_select_files_cancellable)
- {
- g_cancellable_cancel (impl->show_and_select_files_cancellable);
- impl->show_and_select_files_cancellable = NULL;
- }
-
if (impl->should_respond_get_info_cancellable)
{
g_cancellable_cancel (impl->should_respond_get_info_cancellable);
@@ -5889,6 +5755,8 @@ change_icon_theme (GtkFileChooserDefault *impl)
{
GtkSettings *settings;
gint width, height;
+ GtkCellRenderer *renderer;
+ GList *cells;
profile_start ("start", NULL);
@@ -5900,6 +5768,14 @@ change_icon_theme (GtkFileChooserDefault *impl)
impl->icon_size = FALLBACK_ICON_SIZE;
shortcuts_reload_icons (impl);
+ /* the first cell in the first column is the icon column, and we have a fixed size there */
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (
+ gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0)));
+ renderer = GTK_CELL_RENDERER (cells->data);
+ set_icon_cell_renderer_fixed_size (impl, renderer);
+ g_list_free (cells);
+ if (impl->browse_files_model)
+ _gtk_file_system_model_clear_cache (impl->browse_files_model, MODEL_COL_PIXBUF);
gtk_widget_queue_resize (impl->browse_files_tree_view);
profile_end ("end", NULL);
@@ -6006,79 +5882,19 @@ gtk_file_chooser_default_size_allocate (GtkWidget *widget,
GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->size_allocate (widget, allocation);
}
-static gboolean
-get_is_file_filtered (GtkFileChooserDefault *impl,
- GFile *file,
- GFileInfo *file_info)
-{
- GtkFileFilterInfo filter_info;
- GtkFileFilterFlags needed;
- gboolean result;
-
- if (!impl->current_filter)
- return FALSE;
-
- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
-
- needed = gtk_file_filter_get_needed (impl->current_filter);
-
- filter_info.display_name = g_file_info_get_display_name (file_info);
- filter_info.mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (file_info));
-
- if (needed & GTK_FILE_FILTER_FILENAME)
- {
- filter_info.filename = g_file_get_path (file);
- if (filter_info.filename)
- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
- }
- else
- filter_info.filename = NULL;
-
- if (needed & GTK_FILE_FILTER_URI)
- {
- filter_info.uri = g_file_get_uri (file);
- if (filter_info.uri)
- filter_info.contains |= GTK_FILE_FILTER_URI;
- }
- else
- filter_info.uri = NULL;
-
- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
-
- g_free ((gchar *)filter_info.filename);
- g_free ((gchar *)filter_info.uri);
- g_free ((gchar *)filter_info.mime_type);
-
- return !result;
-}
-
static void
set_sort_column (GtkFileChooserDefault *impl)
{
GtkTreeSortable *sortable;
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_BROWSE:
- sortable = GTK_TREE_SORTABLE (impl->sort_model);
- break;
-
- case OPERATION_MODE_SEARCH:
- sortable = GTK_TREE_SORTABLE (impl->search_model_sort);
- break;
-
- case OPERATION_MODE_RECENT:
- sortable = GTK_TREE_SORTABLE (impl->recent_model_sort);
- break;
-
- default:
- g_assert_not_reached ();
- return;
- }
+ sortable = GTK_TREE_SORTABLE (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)));
+ /* can happen when we're still populating the model */
+ if (sortable == NULL)
+ return;
gtk_tree_sortable_set_sort_column_id (sortable,
- general_column_to_model_column (impl, impl->sort_column),
- impl->sort_order);
+ impl->sort_column,
+ impl->sort_order);
}
static void
@@ -6112,8 +5928,7 @@ settings_load (GtkFileChooserDefault *impl)
gtk_expander_set_expanded (GTK_EXPANDER (impl->save_expander), expand_folders);
impl->show_size_column = show_size_column;
- if (impl->list_size_column)
- gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column);
+ gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column);
impl->sort_column = sort_column;
impl->sort_order = sort_order;
@@ -6254,62 +6069,20 @@ gtk_file_chooser_default_unmap (GtkWidget *widget)
impl->reload_state = RELOAD_WAS_UNMAPPED;
}
-static gboolean
-list_model_filter_func (GtkFileSystemModel *model,
- GFile *file,
- GFileInfo *file_info,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
-
- if (!impl->current_filter)
- return TRUE;
-
- if (_gtk_file_info_consider_as_directory (file_info))
- return TRUE;
-
- return !get_is_file_filtered (impl, file, file_info);
-}
-
static void
install_list_model_filter (GtkFileChooserDefault *impl)
{
- GtkFileSystemModelFilter filter;
- gpointer data;
-
- g_assert (impl->browse_files_model != NULL);
-
- if (impl->current_filter)
- {
- filter = list_model_filter_func;
- data = impl;
- }
- else
- {
- filter = NULL;
- data = NULL;
- }
-
_gtk_file_system_model_set_filter (impl->browse_files_model,
- filter,
- data);
+ impl->current_filter);
}
#define COMPARE_DIRECTORIES \
GtkFileChooserDefault *impl = user_data; \
- GFileInfo *info_a = _gtk_file_system_model_get_info (impl->browse_files_model, a); \
- GFileInfo *info_b = _gtk_file_system_model_get_info (impl->browse_files_model, b); \
+ GtkFileSystemModel *fs_model = GTK_FILE_SYSTEM_MODEL (model); \
gboolean dir_a, dir_b; \
\
- if (info_a) \
- dir_a = _gtk_file_info_consider_as_directory (info_a); \
- else \
- return impl->list_sort_ascending ? -1 : 1; \
- \
- if (info_b) \
- dir_b = _gtk_file_info_consider_as_directory (info_b); \
- else \
- return impl->list_sort_ascending ? 1 : -1; \
+ dir_a = g_value_get_boolean (_gtk_file_system_model_get_value (fs_model, a, MODEL_COL_IS_FOLDER)); \
+ dir_b = g_value_get_boolean (_gtk_file_system_model_get_value (fs_model, b, MODEL_COL_IS_FOLDER)); \
\
if (dir_a != dir_b) \
return impl->list_sort_ascending ? (dir_a ? -1 : 1) : (dir_a ? 1 : -1) /* Directories *always* go first */
@@ -6324,15 +6097,20 @@ name_sort_func (GtkTreeModel *model,
COMPARE_DIRECTORIES;
else
{
- gchar *key_a, *key_b;
+ const char *key_a, *key_b;
gint result;
- key_a = g_utf8_collate_key_for_filename (g_file_info_get_display_name (info_a), -1);
- key_b = g_utf8_collate_key_for_filename (g_file_info_get_display_name (info_b), -1);
- result = strcmp (key_a, key_b);
+ key_a = g_value_get_string (_gtk_file_system_model_get_value (fs_model, a, MODEL_COL_NAME_COLLATED));
+ key_b = g_value_get_string (_gtk_file_system_model_get_value (fs_model, b, MODEL_COL_NAME_COLLATED));
- g_free (key_a);
- g_free (key_b);
+ if (key_a && key_b)
+ result = strcmp (key_a, key_b);
+ else if (key_a)
+ result = 1;
+ else if (key_b)
+ result = -1;
+ else
+ result = 0;
return result;
}
@@ -6348,8 +6126,10 @@ size_sort_func (GtkTreeModel *model,
COMPARE_DIRECTORIES;
else
{
- goffset size_a = g_file_info_get_size (info_a);
- goffset size_b = g_file_info_get_size (info_b);
+ gint64 size_a, size_b;
+
+ size_a = g_value_get_int64 (_gtk_file_system_model_get_value (fs_model, a, MODEL_COL_SIZE));
+ size_b = g_value_get_int64 (_gtk_file_system_model_get_value (fs_model, b, MODEL_COL_SIZE));
return size_a > size_b ? -1 : (size_a == size_b ? 0 : 1);
}
@@ -6365,12 +6145,12 @@ mtime_sort_func (GtkTreeModel *model,
COMPARE_DIRECTORIES;
else
{
- GTimeVal ta, tb;
+ glong ta, tb;
- g_file_info_get_modification_time (info_a, &ta);
- g_file_info_get_modification_time (info_b, &tb);
+ ta = g_value_get_long (_gtk_file_system_model_get_value (fs_model, a, MODEL_COL_MTIME));
+ tb = g_value_get_long (_gtk_file_system_model_get_value (fs_model, b, MODEL_COL_MTIME));
- return ta.tv_sec > tb.tv_sec ? -1 : (ta.tv_sec == tb.tv_sec ? 0 : 1);
+ return ta > tb ? -1 : (ta == tb ? 0 : 1);
}
}
@@ -6387,7 +6167,7 @@ list_sort_column_changed_cb (GtkTreeSortable *sortable,
if (gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &sort_type))
{
impl->list_sort_ascending = (sort_type == GTK_SORT_ASCENDING);
- impl->sort_column = model_column_to_general_column (impl, sort_column_id);
+ impl->sort_column = sort_column_id;
impl->sort_order = sort_type;
}
}
@@ -6425,28 +6205,16 @@ load_set_model (GtkFileChooserDefault *impl)
profile_start ("start", NULL);
g_assert (impl->browse_files_model != NULL);
- g_assert (impl->sort_model == NULL);
-
- profile_msg (" gtk_tree_model_sort_new_with_model start", NULL);
- impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_MTIME, mtime_sort_func, impl, NULL);
- gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
- set_sort_column (impl);
- impl->list_sort_ascending = TRUE;
- profile_msg (" gtk_tree_model_sort_new_with_model end", NULL);
-
- g_signal_connect (impl->sort_model, "sort-column-changed",
- G_CALLBACK (list_sort_column_changed_cb), impl);
profile_msg (" gtk_tree_view_set_model start", NULL);
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
- GTK_TREE_MODEL (impl->sort_model));
+ GTK_TREE_MODEL (impl->browse_files_model));
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
- GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
+ MODEL_COL_NAME);
+ set_sort_column (impl);
profile_msg (" gtk_tree_view_set_model end", NULL);
+ impl->list_sort_ascending = TRUE;
profile_end ("end", NULL);
}
@@ -6511,11 +6279,12 @@ browse_files_select_first_row (GtkFileChooserDefault *impl)
GtkTreeIter dummy_iter;
GtkTreeModel *tree_model;
- if (!impl->sort_model)
+ tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
+
+ if (!tree_model)
return;
path = gtk_tree_path_new_from_indices (0, -1);
- tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
/* If the list is empty, do nothing. */
if (gtk_tree_model_get_iter (tree_model, &dummy_iter, path))
@@ -6562,144 +6331,58 @@ browse_files_center_selected_row (GtkFileChooserDefault *impl)
gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
}
-struct ShowAndSelectPathsData
-{
- GtkFileChooserDefault *impl;
- GSList *files;
-};
-
-static void
-show_and_select_files_finished_loading (GtkFolder *folder,
- gpointer user_data)
+static gboolean
+show_and_select_files (GtkFileChooserDefault *impl,
+ GSList *files)
{
- gboolean have_hidden;
- gboolean have_filtered;
- GSList *l;
- struct ShowAndSelectPathsData *data = user_data;
-
- have_hidden = FALSE;
- have_filtered = FALSE;
-
- for (l = data->files; l; l = l->next)
- {
- GFile *file;
- GFileInfo *info;
-
- file = l->data;
-
- info = _gtk_folder_get_info (folder, file);
- if (info)
- {
- if (!have_hidden)
- have_hidden = g_file_info_get_is_hidden (info)
- || g_file_info_get_is_backup (info);
-
- if (!have_filtered)
- have_filtered = (! _gtk_file_info_consider_as_directory (info)) &&
- get_is_file_filtered (data->impl, file, info);
-
- g_object_unref (info);
-
- if (have_hidden && have_filtered)
- break; /* we now have all the information we need */
- }
- }
-
- g_signal_handlers_disconnect_by_func (folder,
- show_and_select_files_finished_loading,
- user_data);
-
- if (have_hidden)
- g_object_set (data->impl, "show-hidden", TRUE, NULL);
+ GtkTreeSelection *selection;
+ GtkFileSystemModel *fsmodel;
+ gboolean can_have_hidden, can_have_filtered, selected_a_file;
+ GSList *walk;
- if (have_filtered)
- set_current_filter (data->impl, NULL);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ fsmodel = GTK_FILE_SYSTEM_MODEL (gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view)));
+ can_have_hidden = !impl->show_hidden;
+ can_have_filtered = impl->current_filter != NULL;
+ selected_a_file = FALSE;
- for (l = data->files; l; l = l->next)
+ for (walk = files; walk && (can_have_hidden || can_have_filtered); walk = walk->next)
{
- GFile *file;
-
- file = l->data;
- _gtk_file_system_model_path_do (data->impl->browse_files_model, file,
- select_func, data->impl);
- }
-
- browse_files_center_selected_row (data->impl);
-
- g_object_unref (data->impl);
- g_slist_foreach (data->files, (GFunc) g_object_unref, NULL);
- g_slist_free (data->files);
- g_free (data);
-}
-
-static void
-show_and_select_files_get_folder_cb (GCancellable *cancellable,
- GtkFolder *folder,
- const GError *error,
- gpointer user_data)
-{
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
- struct ShowAndSelectPathsData *data = user_data;
-
- if (data->impl->show_and_select_files_cancellable != cancellable)
- goto out;
-
- data->impl->show_and_select_files_cancellable = NULL;
-
- if (cancelled || error)
- goto out;
-
- g_object_unref (cancellable);
-
- if (_gtk_folder_is_finished_loading (folder))
- show_and_select_files_finished_loading (folder, user_data);
- else
- g_signal_connect (folder, "finished-loading",
- G_CALLBACK (show_and_select_files_finished_loading),
- user_data);
-
- return;
-
-out:
- g_object_unref (data->impl);
- g_slist_foreach (data->files, (GFunc) g_object_unref, NULL);
- g_slist_free (data->files);
- g_free (data);
+ GFile *file = walk->data;
+ GtkTreeIter iter;
- g_object_unref (cancellable);
-}
+ if (!_gtk_file_system_model_get_iter_for_file (fsmodel, &iter, file))
+ continue;
-static gboolean
-show_and_select_files (GtkFileChooserDefault *impl,
- GFile *parent_file,
- GSList *files,
- GError **error)
-{
- struct ShowAndSelectPathsData *info;
+ if (!_gtk_file_system_model_iter_is_visible (fsmodel, &iter))
+ {
+ GFileInfo *info = _gtk_file_system_model_get_info (fsmodel, &iter);
- profile_start ("start", NULL);
+ if (can_have_hidden &&
+ (g_file_info_get_is_hidden (info) ||
+ g_file_info_get_is_backup (info)))
+ {
+ g_object_set (impl, "show-hidden", TRUE, NULL);
+ can_have_hidden = FALSE;
+ }
- if (!files)
- {
- profile_end ("end", NULL);
- return TRUE;
+ if (can_have_filtered)
+ {
+ set_current_filter (impl, NULL);
+ can_have_filtered = FALSE;
+ }
+ }
+
+ if (_gtk_file_system_model_iter_is_visible (fsmodel, &iter))
+ {
+ gtk_tree_selection_select_iter (selection, &iter);
+ selected_a_file = TRUE;
+ }
}
- info = g_new (struct ShowAndSelectPathsData, 1);
- info->impl = g_object_ref (impl);
- info->files = g_slist_copy (files);
- g_slist_foreach (info->files, (GFunc) g_object_ref, NULL);
-
- if (impl->show_and_select_files_cancellable)
- g_cancellable_cancel (impl->show_and_select_files_cancellable);
-
- impl->show_and_select_files_cancellable =
- _gtk_file_system_get_folder (impl->file_system, parent_file,
- "standard::is-hidden,standard::is-backup,standard::type,standard::name,standard::content-type",
- show_and_select_files_get_folder_cb, info);
+ browse_files_center_selected_row (impl);
- profile_end ("end", NULL);
- return TRUE;
+ return selected_a_file;
}
/* Processes the pending operation when a folder is finished loading */
@@ -6708,12 +6391,10 @@ pending_select_files_process (GtkFileChooserDefault *impl)
{
g_assert (impl->load_state == LOAD_FINISHED);
g_assert (impl->browse_files_model != NULL);
- g_assert (impl->sort_model != NULL);
if (impl->pending_select_files)
{
- /* NULL GError */
- show_and_select_files (impl, impl->current_folder, impl->pending_select_files, NULL);
+ show_and_select_files (impl, impl->pending_select_files);
pending_select_files_free (impl);
browse_files_center_selected_row (impl);
}
@@ -6733,13 +6414,40 @@ pending_select_files_process (GtkFileChooserDefault *impl)
g_assert (impl->pending_select_files == NULL);
}
+static void
+show_error_on_reading_current_folder (GtkFileChooserDefault *impl, GError *error)
+{
+ GFileInfo *info;
+ char *msg;
+
+ info = g_file_query_info (impl->current_folder,
+ G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ NULL);
+ if (info)
+ {
+ msg = g_strdup_printf (_("Could not read the contents of %s"), g_file_info_get_display_name (info));
+ g_object_unref (info);
+ }
+ else
+ msg = g_strdup (_("Could not read the contents of the folder"));
+
+ error_message (impl, msg, error->message);
+ g_free (msg);
+}
+
/* Callback used when the file system model finishes loading */
static void
browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
+ GError *error,
GtkFileChooserDefault *impl)
{
profile_start ("start", NULL);
+ if (error)
+ show_error_on_reading_current_folder (impl, error);
+
if (impl->load_state == LOAD_PRELOAD)
{
load_remove_timer (impl);
@@ -6782,13 +6490,265 @@ stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
impl->browse_files_model = NULL;
}
- if (impl->sort_model)
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+}
+
+static char *
+my_g_format_time_for_display (glong secs)
+{
+ GDate mtime, now;
+ gint days_diff;
+ struct tm tm_mtime;
+ time_t time_mtime, time_now;
+ const gchar *format;
+ gchar *locale_format = NULL;
+ gchar buf[256];
+ char *date_str = NULL;
+#ifdef G_OS_WIN32
+ const char *locale, *dot = NULL;
+ gint64 codepage = -1;
+ char charset[20];
+#endif
+
+ time_mtime = secs;
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r ((time_t *) &time_mtime, &tm_mtime);
+#else
+ {
+ struct tm *ptm = localtime ((time_t *) &time_mtime);
+
+ if (!ptm)
+ {
+ g_warning ("ptm != NULL failed");
+
+ return g_strdup (_("Unknown"));
+ }
+ else
+ memcpy ((void *) &tm_mtime, (void *) ptm, sizeof (struct tm));
+ }
+#endif /* HAVE_LOCALTIME_R */
+
+ g_date_set_time_t (&mtime, time_mtime);
+ time_now = time (NULL);
+ g_date_set_time_t (&now, time_now);
+
+ days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
+
+ /* Translators: %H means "hours" and %M means "minutes" */
+ if (days_diff == 0)
+ format = _("%H:%M");
+ else if (days_diff == 1)
+ format = _("Yesterday at %H:%M");
+ else
+ {
+ if (days_diff > 1 && days_diff < 7)
+ format = "%A"; /* Days from last week */
+ else
+ format = "%x"; /* Any other date */
+ }
+
+#ifdef G_OS_WIN32
+ /* g_locale_from_utf8() returns a string in the system
+ * code-page, which is not always the same as that used by the C
+ * library. For instance when running a GTK+ program with
+ * LANG=ko on an English version of Windows, the system
+ * code-page is 1252, but the code-page used by the C library is
+ * 949. (It's GTK+ itself that sets the C library locale when it
+ * notices the LANG environment variable. See gtkmain.c The
+ * Microsoft C library doesn't look at any locale environment
+ * variables.) We need to pass strftime() a string in the C
+ * library's code-page. See bug #509885.
+ */
+ locale = setlocale (LC_ALL, NULL);
+ if (locale != NULL)
+ dot = strchr (locale, '.');
+ if (dot != NULL)
{
- g_object_unref (impl->sort_model);
- impl->sort_model = NULL;
+ codepage = g_ascii_strtoll (dot+1, NULL, 10);
+
+ /* All codepages should fit in 16 bits AFAIK */
+ if (codepage > 0 && codepage < 65536)
+ {
+ sprintf (charset, "CP%u", (guint) codepage);
+ locale_format = g_convert (format, -1, charset, "UTF-8", NULL, NULL, NULL);
+ }
}
-
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+#else
+ locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
+#endif
+ if (locale_format != NULL &&
+ strftime (buf, sizeof (buf), locale_format, &tm_mtime) != 0)
+ {
+#ifdef G_OS_WIN32
+ /* As above but in opposite direction... */
+ if (codepage > 0 && codepage < 65536)
+ date_str = g_convert (buf, -1, "UTF-8", charset, NULL, NULL, NULL);
+#else
+ date_str = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+#endif
+ }
+
+ if (date_str == NULL)
+ date_str = g_strdup (_("Unknown"));
+
+ g_free (locale_format);
+ return date_str;
+}
+
+static void
+copy_attribute (GFileInfo *to, GFileInfo *from, const char *attribute)
+{
+ GFileAttributeType type;
+ gpointer value;
+
+ if (g_file_info_get_attribute_data (from, attribute, &type, &value, NULL))
+ g_file_info_set_attribute (to, attribute, type, value);
+}
+
+static void
+file_system_model_got_thumbnail (GObject *object, GAsyncResult *res, gpointer data)
+{
+ GtkFileSystemModel *model = data; /* might be unreffed if operation was cancelled */
+ GFile *file = G_FILE (object);
+ GFileInfo *queried, *info;
+ GtkTreeIter iter;
+
+ queried = g_file_query_info_finish (file, res, NULL);
+ if (queried == NULL)
+ return;
+
+ /* now we know model is valid */
+
+ /* file was deleted */
+ if (!_gtk_file_system_model_get_iter_for_file (model, &iter, file))
+ return;
+
+ info = g_file_info_dup (_gtk_file_system_model_get_info (model, &iter));
+
+ copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+ copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
+ copy_attribute (info, queried, G_FILE_ATTRIBUTE_STANDARD_ICON);
+
+ _gtk_file_system_model_update_file (model, file, info, FALSE);
+
+ g_object_unref (info);
+}
+
+static gboolean
+file_system_model_set (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info,
+ int column,
+ GValue *value,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl = data;
+
+ switch (column)
+ {
+ case MODEL_COL_FILE:
+ g_value_set_object (value, file);
+ break;
+ case MODEL_COL_NAME:
+ if (info == NULL)
+ g_value_set_string (value, DEFAULT_NEW_FOLDER_NAME);
+ else
+ g_value_set_string (value, g_file_info_get_display_name (info));
+ break;
+ case MODEL_COL_NAME_COLLATED:
+ if (info == NULL)
+ g_value_take_string (value, g_utf8_collate_key_for_filename (DEFAULT_NEW_FOLDER_NAME, -1));
+ else
+ g_value_take_string (value, g_utf8_collate_key_for_filename (g_file_info_get_display_name (info), -1));
+ break;
+ case MODEL_COL_IS_FOLDER:
+ g_value_set_boolean (value, info == NULL || _gtk_file_info_consider_as_directory (info));
+ break;
+ case MODEL_COL_PIXBUF:
+ if (info)
+ {
+ if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_ICON))
+ {
+ g_value_take_object (value, _gtk_file_info_render_icon (info, GTK_WIDGET (impl), impl->icon_size));
+ }
+ else
+ {
+ GtkTreeModel *tree_model;
+ GtkTreePath *path, *start, *end;
+ GtkTreeIter iter;
+
+ if (impl->browse_files_tree_view == NULL ||
+ g_file_info_has_attribute (info, "filechooser::queried"))
+ return FALSE;
+
+ tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ if (tree_model != GTK_TREE_MODEL (model))
+ return FALSE;
+
+ if (!_gtk_file_system_model_get_iter_for_file (model,
+ &iter,
+ file))
+ g_assert_not_reached ();
+ if (!gtk_tree_view_get_visible_range (GTK_TREE_VIEW (impl->browse_files_tree_view), &start, &end))
+ return FALSE;
+ path = gtk_tree_model_get_path (tree_model, &iter);
+ if (gtk_tree_path_compare (start, path) != 1 &&
+ gtk_tree_path_compare (path, end) != 1)
+ {
+ g_file_info_set_attribute_boolean (info, "filechooser::queried", TRUE);
+ g_file_query_info_async (file,
+ G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
+ G_FILE_ATTRIBUTE_THUMBNAILING_FAILED ","
+ G_FILE_ATTRIBUTE_STANDARD_ICON,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ _gtk_file_system_model_get_cancellable (model),
+ file_system_model_got_thumbnail,
+ model);
+ }
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (start);
+ gtk_tree_path_free (end);
+ return FALSE;
+ }
+ }
+ else
+ g_value_set_object (value, NULL);
+ break;
+ case MODEL_COL_SIZE:
+ g_value_set_int64 (value, info ? g_file_info_get_size (info) : 0);
+ break;
+ case MODEL_COL_SIZE_TEXT:
+ if (info == NULL || _gtk_file_info_consider_as_directory (info))
+ g_value_set_string (value, NULL);
+ else
+ g_value_take_string (value, g_format_size_for_display (g_file_info_get_size (info)));
+ break;
+ case MODEL_COL_MTIME:
+ case MODEL_COL_MTIME_TEXT:
+ {
+ GTimeVal tv;
+ if (info == NULL)
+ break;
+ g_file_info_get_modification_time (info, &tv);
+ if (column == MODEL_COL_MTIME)
+ g_value_set_long (value, tv.tv_sec);
+ else if (tv.tv_sec == 0)
+ g_value_set_static_string (value, _("Unknown"));
+ else
+ g_value_take_string (value, my_g_format_time_for_display (tv.tv_sec));
+ break;
+ }
+ case MODEL_COL_ELLIPSIZE:
+ g_value_set_enum (value, info ? PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_NONE);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return TRUE;
}
/* Gets rid of the old list model and creates a new one for the current folder */
@@ -6805,24 +6765,30 @@ set_list_model (GtkFileChooserDefault *impl,
set_busy_cursor (impl, TRUE);
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
- impl->browse_files_model = _gtk_file_system_model_new (impl->file_system,
- impl->current_folder, 0,
- "standard,time,thumbnail::*",
- error);
- if (!impl->browse_files_model)
- {
- set_busy_cursor (impl, FALSE);
- profile_end ("end", NULL);
- return FALSE;
- }
+ impl->browse_files_model =
+ _gtk_file_system_model_new_for_directory (impl->current_folder,
+ MODEL_ATTRIBUTES,
+ file_system_model_set,
+ impl,
+ MODEL_COLUMN_TYPES);
+
+ _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
+
+ profile_msg (" set sort function", NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->browse_files_model), MODEL_COL_NAME, name_sort_func, impl, NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->browse_files_model), MODEL_COL_SIZE, size_sort_func, impl, NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->browse_files_model), MODEL_COL_MTIME, mtime_sort_func, impl, NULL);
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->browse_files_model), NULL, NULL, NULL);
+ set_sort_column (impl);
+ impl->list_sort_ascending = TRUE;
+ g_signal_connect (impl->browse_files_model, "sort-column-changed",
+ G_CALLBACK (list_sort_column_changed_cb), impl);
load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
g_signal_connect (impl->browse_files_model, "finished-loading",
G_CALLBACK (browse_files_model_finished_loading_cb), impl);
- _gtk_file_system_model_set_show_hidden (impl->browse_files_model, impl->show_hidden);
-
install_list_model_filter (impl);
profile_end ("end", NULL);
@@ -6902,18 +6868,12 @@ update_chooser_entry (GtkFileChooserDefault *impl)
}
else if (closure.num_selected == 1)
{
- GtkTreeIter child_iter;
-
if (impl->operation_mode == OPERATION_MODE_BROWSE)
{
GFileInfo *info;
gboolean change_entry;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- &closure.first_selected_iter);
-
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &closure.first_selected_iter);
/* If the cursor moved to the row of the newly created folder,
* retrieving info will return NULL.
@@ -7321,22 +7281,6 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
_gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
}
-static void
-select_func (GtkFileSystemModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeSelection *selection;
- GtkTreeIter sorted_iter;
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
-
- gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
- gtk_tree_selection_select_iter (selection, &sorted_iter);
-}
-
static gboolean
gtk_file_chooser_default_select_file (GtkFileChooser *chooser,
GFile *file,
@@ -7372,7 +7316,7 @@ gtk_file_chooser_default_select_file (GtkFileChooser *chooser,
files.data = (gpointer) file;
files.next = NULL;
- result = show_and_select_files (impl, parent_file, &files, error);
+ result = show_and_select_files (impl, &files);
g_object_unref (parent_file);
return result;
}
@@ -7393,33 +7337,23 @@ gtk_file_chooser_default_select_file (GtkFileChooser *chooser,
}
static void
-unselect_func (GtkFileSystemModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
- GtkTreePath *sorted_path;
-
- sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model,
- path);
- gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (tree_view),
- sorted_path);
- gtk_tree_path_free (sorted_path);
-}
-
-static void
gtk_file_chooser_default_unselect_file (GtkFileChooser *chooser,
GFile *file)
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+ GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
+ GtkTreeIter iter;
if (!impl->browse_files_model)
return;
- _gtk_file_system_model_path_do (impl->browse_files_model, file,
- unselect_func, impl);
+ if (!_gtk_file_system_model_get_iter_for_file (impl->browse_files_model,
+ &iter,
+ file))
+ return;
+
+ gtk_tree_selection_unselect_iter (gtk_tree_view_get_selection (tree_view),
+ &iter);
}
static gboolean
@@ -7430,13 +7364,13 @@ maybe_select (GtkTreeModel *model,
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (data);
GtkTreeSelection *selection;
- GFileInfo *info;
gboolean is_folder;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
- info = get_list_file_info (impl, iter);
- is_folder = _gtk_file_info_consider_as_directory (info);
+ gtk_tree_model_get (model, iter,
+ MODEL_COL_IS_FOLDER, &is_folder,
+ -1);
if ((is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ||
(!is_folder && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN))
@@ -7463,7 +7397,7 @@ gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
}
if (impl->select_multiple)
- gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model),
+ gtk_tree_model_foreach (GTK_TREE_MODEL (impl->browse_files_model),
maybe_select, impl);
}
@@ -7579,13 +7513,11 @@ get_files_foreach (GtkTreeModel *model,
struct get_files_closure *info;
GFile *file;
GtkFileSystemModel *fs_model;
- GtkTreeIter sel_iter;
info = data;
fs_model = info->impl->browse_files_model;
- gtk_tree_model_sort_convert_iter_to_child_iter (info->impl->sort_model, &sel_iter, iter);
- file = _gtk_file_system_model_get_file (fs_model, &sel_iter);
+ file = _gtk_file_system_model_get_file (fs_model, iter);
if (!file)
return; /* We are on the editable row */
@@ -8131,13 +8063,10 @@ switch_folder_foreach_cb (GtkTreeModel *model,
gpointer data)
{
struct switch_folder_closure *closure;
- GtkTreeIter child_iter;
closure = data;
- gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
-
- closure->file = _gtk_file_system_model_get_file (closure->impl->browse_files_model, &child_iter);
+ closure->file = _gtk_file_system_model_get_file (closure->impl->browse_files_model, iter);
closure->num_selected++;
}
@@ -8172,7 +8101,7 @@ get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
gboolean *had_selection)
{
GtkTreeSelection *selection;
- GtkTreeIter iter, child_iter;
+ GtkTreeIter iter;
GFileInfo *info;
g_assert (!impl->select_multiple);
@@ -8185,11 +8114,7 @@ get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
*had_selection = TRUE;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- &iter);
-
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &iter);
return info;
}
@@ -8794,7 +8719,7 @@ search_selected_foreach_get_file_cb (GtkTreeModel *model,
list = data;
- gtk_tree_model_get (model, iter, SEARCH_MODEL_COL_FILE, &file, -1);
+ gtk_tree_model_get (model, iter, MODEL_COL_FILE, &file, -1);
*list = g_slist_prepend (*list, g_object_ref (file));
}
@@ -8828,106 +8753,12 @@ search_should_respond (GtkFileChooserDefault *impl)
return (gtk_tree_selection_count_selected_rows (selection) != 0);
}
-struct SearchHitInsertRequest
-{
- GtkFileChooserDefault *impl;
- GFile *file;
- GtkTreeRowReference *row_ref;
-};
-
-static void
-search_hit_get_info_cb (GCancellable *cancellable,
- GFileInfo *info,
- const GError *error,
- gpointer data)
-{
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
- GdkPixbuf *pixbuf = NULL;
- GtkTreePath *path;
- GtkTreeIter iter;
- GCancellable *model_cancellable;
- gboolean is_folder = FALSE;
- GTimeVal mtime;
- guint64 modification_time = 0;
- goffset size;
- char *mime_type;
- char *display_name;
- struct SearchHitInsertRequest *request = data;
-
- if (!request->impl->search_model)
- goto out;
-
- path = gtk_tree_row_reference_get_path (request->row_ref);
- if (!path)
- goto out;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->search_model),
- &iter, path);
- gtk_tree_path_free (path);
-
- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->search_model), &iter,
- SEARCH_MODEL_COL_CANCELLABLE, &model_cancellable,
- -1);
- if (cancellable != model_cancellable)
- goto out;
-
- /* set the cancellable to NULL in the model */
- gtk_list_store_set (request->impl->search_model, &iter,
- SEARCH_MODEL_COL_CANCELLABLE, NULL,
- -1);
-
- if (cancelled)
- goto out;
-
- if (!info)
- {
- search_clear_model_row (GTK_TREE_MODEL (request->impl->search_model), &iter);
- gtk_list_store_remove (request->impl->search_model, &iter);
- goto out;
- }
-
- display_name = g_strdup (g_file_info_get_display_name (info));
- mime_type = g_content_type_get_mime_type (g_file_info_get_content_type (info));
- g_file_info_get_modification_time (info, &mtime);
- modification_time = (guint64) mtime.tv_sec;
- size = g_file_info_get_size (info);
- is_folder = _gtk_file_info_consider_as_directory (info);
- pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
- request->impl->icon_size);
-
- gtk_list_store_set (request->impl->search_model, &iter,
- SEARCH_MODEL_COL_PIXBUF, pixbuf,
- SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
- SEARCH_MODEL_COL_MIME_TYPE, mime_type,
- SEARCH_MODEL_COL_IS_FOLDER, is_folder,
- SEARCH_MODEL_COL_MTIME, modification_time,
- SEARCH_MODEL_COL_SIZE, size,
- -1);
-
- if (pixbuf)
- g_object_unref (pixbuf);
-
-out:
- g_object_unref (request->impl);
- g_object_unref (request->file);
- gtk_tree_row_reference_free (request->row_ref);
- g_free (request);
-
- g_object_unref (cancellable);
-}
-
/* Adds one hit from the search engine to the search_model */
static void
search_add_hit (GtkFileChooserDefault *impl,
gchar *uri)
{
GFile *file;
- char *tmp;
- char *collation_key;
- GtkTreeIter iter;
- GtkTreePath *p;
- GCancellable *cancellable;
- struct SearchHitInsertRequest *request;
file = g_file_new_for_uri (uri);
if (!file)
@@ -8939,35 +8770,11 @@ search_add_hit (GtkFileChooserDefault *impl,
return;
}
- tmp = g_file_get_parse_name (file);
- collation_key = g_utf8_collate_key_for_filename (tmp, -1);
- g_free (tmp);
-
- request = g_new0 (struct SearchHitInsertRequest, 1);
- request->impl = g_object_ref (impl);
- request->file = g_object_ref (file);
-
- gtk_list_store_append (impl->search_model, &iter);
- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->search_model), &iter);
-
- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->search_model), p);
- gtk_tree_path_free (p);
+ _gtk_file_system_model_add_and_query_file (impl->search_model,
+ file,
+ MODEL_ATTRIBUTES);
- cancellable = _gtk_file_system_get_info (impl->file_system, file,
- "standard::type,"
- "standard::icon,"
- "standard::content-type,"
- "standard::display-name,"
- "time::modified,"
- "standard::size",
- search_hit_get_info_cb,
- request);
-
- gtk_list_store_set (impl->search_model, &iter,
- SEARCH_MODEL_COL_FILE, file,
- SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
- SEARCH_MODEL_COL_CANCELLABLE, cancellable,
- -1);
+ g_object_unref (file);
}
/* Callback used from GtkSearchEngine when we get new hits */
@@ -8999,7 +8806,7 @@ search_engine_finished_cb (GtkSearchEngine *engine,
* but it'll make the search look like blocked.
*/
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
- GTK_TREE_MODEL (impl->search_model_filter));
+ GTK_TREE_MODEL (impl->search_model));
#endif
/* FMQ: if search was empty, say that we got no hits */
@@ -9034,64 +8841,17 @@ search_engine_error_cb (GtkSearchEngine *engine,
set_busy_cursor (impl, FALSE);
}
-static void
-search_clear_model_row (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- GFile *file;
- gchar *display_name;
- gchar *collation_key;
- GCancellable *cancellable;
- gchar *mime_type;
-
- gtk_tree_model_get (model, iter,
- SEARCH_MODEL_COL_FILE, &file,
- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
- SEARCH_MODEL_COL_CANCELLABLE, &cancellable,
- SEARCH_MODEL_COL_MIME_TYPE, &mime_type,
- -1);
-
- if (file)
- g_object_unref (file);
-
- g_free (display_name);
- g_free (collation_key);
- g_free (mime_type);
-
- if (cancellable)
- g_cancellable_cancel (cancellable);
-}
-
/* Frees the data in the search_model */
static void
search_clear_model (GtkFileChooserDefault *impl,
gboolean remove_from_treeview)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
if (!impl->search_model)
return;
- model = GTK_TREE_MODEL (impl->search_model);
-
- if (gtk_tree_model_get_iter_first (model, &iter))
- do
- {
- search_clear_model_row (model, &iter);
- }
- while (gtk_tree_model_iter_next (model, &iter));
-
g_object_unref (impl->search_model);
impl->search_model = NULL;
- g_object_unref (impl->search_model_filter);
- impl->search_model_filter = NULL;
-
- g_object_unref (impl->search_model_sort);
- impl->search_model_sort = NULL;
-
if (remove_from_treeview)
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
}
@@ -9130,7 +8890,7 @@ search_switch_to_browse_mode (GtkFileChooserDefault *impl)
impl->search_entry = NULL;
gtk_widget_show (impl->browse_path_bar);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || !impl->create_folders)
gtk_widget_hide (impl->browse_new_folder_button);
else
gtk_widget_show (impl->browse_new_folder_button);
@@ -9150,247 +8910,27 @@ search_switch_to_browse_mode (GtkFileChooserDefault *impl)
file_list_set_sort_column_ids (impl);
}
-/* Sort callback from the path column */
-static gint
-search_column_path_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeIter child_a, child_b;
- const char *collation_key_a, *collation_key_b;
- gboolean is_folder_a, is_folder_b;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a,
- -1);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
- SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b,
- -1);
-
- if (!collation_key_a)
- return 1;
-
- if (!collation_key_b)
- return -1;
-
- /* always show folders first */
- if (is_folder_a != is_folder_b)
- return is_folder_a ? 1 : -1;
-
- return strcmp (collation_key_a, collation_key_b);
-}
-
-/* Sort callback from the size column */
-static gint
-search_column_size_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeIter child_a, child_b;
- gboolean is_folder_a, is_folder_b;
- goffset size_a, size_b;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
- SEARCH_MODEL_COL_SIZE, &size_a,
- -1);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
- SEARCH_MODEL_COL_SIZE, &size_b,
- -1);
-
- if (is_folder_a != is_folder_b)
- return is_folder_a ? 1 : -1;
-
- if (size_a < size_b)
- return -1;
- else if (size_a > size_b)
- return 1;
- else
- return 0;
-}
-
-/* Sort callback from the modification time column */
-static gint
-search_column_mtime_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeIter child_a, child_b;
- gboolean is_folder_a, is_folder_b;
- guint64 mtime_a, mtime_b;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_a,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_a,
- SEARCH_MODEL_COL_MTIME, &mtime_a,
- -1);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_b,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder_b,
- SEARCH_MODEL_COL_MTIME, &mtime_b,
- -1);
-
- if (is_folder_a != is_folder_b)
- return is_folder_a ? 1 : -1;
-
- if (mtime_a < mtime_b)
- return -1;
- else if (mtime_a > mtime_b)
- return 1;
- else
- return 0;
-}
-
-static gboolean
-search_get_is_filtered (GtkFileChooserDefault *impl,
- GFile *file,
- const gchar *display_name,
- const gchar *mime_type)
-{
- GtkFileFilterInfo filter_info;
- GtkFileFilterFlags needed;
- gboolean result;
-
- if (!impl->current_filter)
- return FALSE;
-
- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
- needed = gtk_file_filter_get_needed (impl->current_filter);
-
- filter_info.display_name = display_name;
- filter_info.mime_type = mime_type;
-
- if (needed & GTK_FILE_FILTER_FILENAME)
- {
- filter_info.filename = g_file_get_path (file);
- if (filter_info.filename)
- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
- }
- else
- filter_info.filename = NULL;
-
- if (needed & GTK_FILE_FILTER_URI)
- {
- filter_info.uri = g_file_get_uri (file);
- if (filter_info.uri)
- filter_info.contains |= GTK_FILE_FILTER_URI;
- }
- else
- filter_info.uri = NULL;
-
- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
-
- if (filter_info.filename)
- g_free ((gchar *) filter_info.filename);
- if (filter_info.uri)
- g_free ((gchar *) filter_info.uri);
-
- return !result;
-
-}
-
-/* Visibility function for the recent filter model */
-static gboolean
-search_model_visible_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GFile *file;
- gchar *display_name, *mime_type;
- gboolean is_folder;
-
- if (!impl->current_filter)
- return TRUE;
-
- gtk_tree_model_get (model, iter,
- SEARCH_MODEL_COL_FILE, &file,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
- SEARCH_MODEL_COL_MIME_TYPE, &mime_type,
- -1);
-
- if (!display_name)
- return TRUE;
-
- if (is_folder)
- return TRUE;
-
- return !search_get_is_filtered (impl, file, display_name, mime_type);
-}
-
/* Creates the search_model and puts it in the tree view */
static void
search_setup_model (GtkFileChooserDefault *impl)
{
g_assert (impl->search_model == NULL);
- g_assert (impl->search_model_filter == NULL);
- g_assert (impl->search_model_sort == NULL);
- /* We store these columns in the search model:
- *
- * SEARCH_MODEL_COL_FILE - a GFile for the hit's URI, stored
- * as a pointer not as a G_TYPE_FILE
- * SEARCH_MODEL_COL_DISPLAY_NAME - a string with the display name, stored
- * as a pointer not as a G_TYPE_STRING
- * SEARCH_MODEL_COL_COLLATION_KEY - collation key for the filename, stored
- * as a pointer not as a G_TYPE_STRING
- * SEARCH_MODEL_COL_MTIME - G_TYPE_UINT64 for the modification time
- * SEARCH_MODEL_COL_SIZE - G_TYPE_INT64 for the size
- * SEARCH_MODEL_COL_CANCELLABLE - cancellable used when getting the hit's info
- * SEARCH_MODEL_COL_PIXBUF - GdkPixbuf for the hit's icon
- * SEARCH_MODEL_COL_MIME_TYPE - a string with the hit's MIME type
- * SEARCH_MODEL_COL_IS_FOLDER - a boolean flag for folders
- *
- * Keep this in sync with the enumeration defined near the beginning
- * of this file.
- */
- impl->search_model = gtk_list_store_new (SEARCH_MODEL_COL_NUM_COLUMNS,
- G_TYPE_POINTER, /* file */
- G_TYPE_POINTER, /* display-name */
- G_TYPE_POINTER, /* collation-key */
- G_TYPE_UINT64, /* mtime */
- G_TYPE_INT64, /* size */
- G_TYPE_POINTER, /* cancellable */
- GDK_TYPE_PIXBUF, /* pixbuf */
- G_TYPE_POINTER, /* mime-type */
- G_TYPE_BOOLEAN /*is-folder */);
-
- impl->search_model_filter =
- GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->search_model), NULL));
- gtk_tree_model_filter_set_visible_func (impl->search_model_filter,
- search_model_visible_func,
- impl, NULL);
-
- impl->search_model_sort =
- GTK_TREE_MODEL_SORT (search_model_sort_new (impl, GTK_TREE_MODEL (impl->search_model_filter)));
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
- SEARCH_MODEL_COL_FILE,
- search_column_path_sort_func,
+ impl->search_model = _gtk_file_system_model_new (file_system_model_set,
+ impl,
+ MODEL_COLUMN_TYPES);
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+ MODEL_COL_NAME,
+ name_sort_func,
impl, NULL);
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
- SEARCH_MODEL_COL_MTIME,
- search_column_mtime_sort_func,
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+ MODEL_COL_MTIME,
+ mtime_sort_func,
impl, NULL);
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model_sort),
- SEARCH_MODEL_COL_SIZE,
- search_column_size_sort_func,
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+ MODEL_COL_SIZE,
+ size_sort_func,
impl, NULL);
set_sort_column (impl);
@@ -9399,29 +8939,7 @@ search_setup_model (GtkFileChooserDefault *impl)
* run
*/
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
- GTK_TREE_MODEL (impl->search_model_sort));
-}
-
-static void
-search_get_valid_child_iter (GtkFileChooserDefault *impl,
- GtkTreeIter *child_iter,
- GtkTreeIter *iter)
-{
- GtkTreeIter middle;
-
- if (!impl->search_model)
- return;
-
- if (!impl->search_model_filter || !impl->search_model_sort)
- return;
-
- /* pass 1: get the iterator in the filter model */
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->search_model_sort,
- &middle, iter);
-
- /* pass 2: get the iterator in the real model */
- gtk_tree_model_filter_convert_iter_to_child_iter (impl->search_model_filter,
- child_iter, &middle);
+ GTK_TREE_MODEL (impl->search_model));
}
/* Creates a new query with the specified text and launches it */
@@ -9494,6 +9012,7 @@ search_setup_widgets (GtkFileChooserDefault *impl)
{
GtkWidget *label;
GtkWidget *image;
+ gchar *tmp;
impl->search_hbox = gtk_hbox_new (FALSE, 12);
@@ -9506,8 +9025,10 @@ search_setup_widgets (GtkFileChooserDefault *impl)
/* Label */
label = gtk_label_new (NULL);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>_Search:</b>"));
+ tmp = g_strdup_printf ("<b>%s</b>", _("Search:"));
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), tmp);
gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
+ g_free (tmp);
/* Entry */
@@ -9609,7 +9130,6 @@ search_activate (GtkFileChooserDefault *impl)
g_assert (impl->search_hbox == NULL);
g_assert (impl->search_entry == NULL);
g_assert (impl->search_model == NULL);
- g_assert (impl->search_model_filter == NULL);
search_setup_widgets (impl);
file_list_set_sort_column_ids (impl);
@@ -9625,7 +9145,6 @@ recent_clear_model (GtkFileChooserDefault *impl,
gboolean remove_from_treeview)
{
GtkTreeModel *model;
- GtkTreeIter iter;
if (!impl->recent_model)
return;
@@ -9635,40 +9154,8 @@ recent_clear_model (GtkFileChooserDefault *impl,
if (remove_from_treeview)
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
- if (gtk_tree_model_get_iter_first (model, &iter))
- {
- do
- {
- GFile *file;
- GCancellable *cancellable;
- GtkRecentInfo *recent_info;
- gchar *display_name;
-
- gtk_tree_model_get (model, &iter,
- RECENT_MODEL_COL_DISPLAY_NAME, &display_name,
- RECENT_MODEL_COL_FILE, &file,
- RECENT_MODEL_COL_CANCELLABLE, &cancellable,
- RECENT_MODEL_COL_INFO, &recent_info,
- -1);
-
- if (cancellable)
- g_cancellable_cancel (cancellable);
-
- g_object_unref (file);
- gtk_recent_info_unref (recent_info);
- g_free (display_name);
- }
- while (gtk_tree_model_iter_next (model, &iter));
- }
-
g_object_unref (impl->recent_model);
impl->recent_model = NULL;
-
- g_object_unref (impl->recent_model_filter);
- impl->recent_model_filter = NULL;
-
- g_object_unref (impl->recent_model_sort);
- impl->recent_model_sort = NULL;
}
/* Stops any ongoing loading of the recent files list; does
@@ -9699,7 +9186,7 @@ recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
impl->recent_hbox = NULL;
gtk_widget_show (impl->browse_path_bar);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || !impl->create_folders)
gtk_widget_hide (impl->browse_new_folder_button);
else
gtk_widget_show (impl->browse_new_folder_button);
@@ -9720,211 +9207,28 @@ recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
file_list_set_sort_column_ids (impl);
}
-/* Sort callback from the modification time column */
-static gint
-recent_column_mtime_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeIter child_a, child_b;
- GtkRecentInfo *info_a, *info_b;
- gboolean is_folder_a, is_folder_b;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
- RECENT_MODEL_COL_INFO, &info_a,
- -1);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
- RECENT_MODEL_COL_INFO, &info_b,
- -1);
-
- if (!info_a)
- return 1;
-
- if (!info_b)
- return -1;
-
- /* folders always go first */
- if (is_folder_a != is_folder_b)
- return is_folder_a ? 1 : -1;
-
- if (gtk_recent_info_get_modified (info_a) < gtk_recent_info_get_modified (info_b))
- return -1;
- else if (gtk_recent_info_get_modified (info_a) > gtk_recent_info_get_modified (info_b))
- return 1;
- else
- return 0;
-}
-
-static gint
-recent_column_path_sort_func (GtkTreeModel *model,
- GtkTreeIter *a,
- GtkTreeIter *b,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GtkTreeIter child_a, child_b;
- gboolean is_folder_a, is_folder_b;
- gchar *name_a, *name_b;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_a, a);
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_b, b);
-
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_a,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder_a,
- RECENT_MODEL_COL_DISPLAY_NAME, &name_a,
- -1);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_b,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder_b,
- RECENT_MODEL_COL_DISPLAY_NAME, &name_b,
- -1);
-
- if (!name_a)
- return 1;
-
- if (!name_b)
- return -1;
-
- if (is_folder_a != is_folder_b)
- return is_folder_a ? 1 : -1;
-
- return strcmp (name_a, name_b);
-}
-
-static gboolean
-recent_get_is_filtered (GtkFileChooserDefault *impl,
- GFile *file,
- GtkRecentInfo *recent_info)
-{
- GtkFileFilterInfo filter_info;
- GtkFileFilterFlags needed;
- gboolean result;
-
- if (!impl->current_filter)
- return FALSE;
-
- filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
- needed = gtk_file_filter_get_needed (impl->current_filter);
-
- filter_info.display_name = gtk_recent_info_get_display_name (recent_info);
- filter_info.mime_type = gtk_recent_info_get_mime_type (recent_info);
-
- if (needed & GTK_FILE_FILTER_FILENAME)
- {
- filter_info.filename = g_file_get_path (file);
- if (filter_info.filename)
- filter_info.contains |= GTK_FILE_FILTER_FILENAME;
- }
- else
- filter_info.filename = NULL;
-
- if (needed & GTK_FILE_FILTER_URI)
- {
- filter_info.uri = g_file_get_uri (file);
- if (filter_info.uri)
- filter_info.contains |= GTK_FILE_FILTER_URI;
- }
- else
- filter_info.uri = NULL;
-
- result = gtk_file_filter_filter (impl->current_filter, &filter_info);
-
- if (filter_info.filename)
- g_free ((gchar *) filter_info.filename);
- if (filter_info.uri)
- g_free ((gchar *) filter_info.uri);
-
- return !result;
-}
-
-/* Visibility function for the recent filter model */
-static gboolean
-recent_model_visible_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer user_data)
-{
- GtkFileChooserDefault *impl = user_data;
- GFile *file;
- GtkRecentInfo *recent_info;
- gboolean is_folder;
-
- if (!impl->current_filter)
- return TRUE;
-
- gtk_tree_model_get (model, iter,
- RECENT_MODEL_COL_INFO, &recent_info,
- RECENT_MODEL_COL_FILE, &file,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (!recent_info)
- return TRUE;
-
- if (is_folder)
- return TRUE;
-
- return !recent_get_is_filtered (impl, file, recent_info);
-}
-
static void
recent_setup_model (GtkFileChooserDefault *impl)
{
g_assert (impl->recent_model == NULL);
- g_assert (impl->recent_model_filter == NULL);
- g_assert (impl->recent_model_sort == NULL);
- /* We store these columns in the search model:
- *
- * RECENT_MODEL_COL_FILE - a pointer to GFile for the hit's URI,
- * stored as a pointer and not as a G_TYPE_FILE;
- * RECENT_MODEL_COL_DISPLAY_NAME - a string with the display name,
- * stored as a pointer and not as a G_TYPE_STRING;
- * RECENT_MODEL_COL_INFO - GtkRecentInfo, stored as a pointer and not
- * as a GTK_TYPE_RECENT_INFO;
- * RECENT_MODEL_COL_IS_FOLDER - boolean flag;
- * RECENT_MODEL_COL_CANCELLABLE - GCancellable, stored as a pointer
- * and not as a G_TYPE_CANCELLABLE;
- *
- * Keep this in sync with the enumeration defined near the beginning of
- * this file.
- */
- impl->recent_model = gtk_list_store_new (RECENT_MODEL_COL_NUM_COLUMNS,
- G_TYPE_POINTER,
- G_TYPE_POINTER,
- G_TYPE_POINTER,
- G_TYPE_BOOLEAN,
- G_TYPE_POINTER);
-
- impl->recent_model_filter =
- GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->recent_model), NULL));
- gtk_tree_model_filter_set_visible_func (impl->recent_model_filter,
- recent_model_visible_func,
- impl,
- NULL);
-
- /* this is the model that will actually be added to
- * the browse_files_tree_view widget; remember: we are
- * stuffing the real model into a filter model and then
- * into a sort model; this means we'll have to translate
- * the child iterator *twice* to get from a path or an
- * iterator coming from the tree view widget to the
- * real data inside the model.
- */
- impl->recent_model_sort =
- GTK_TREE_MODEL_SORT (recent_model_sort_new (impl, GTK_TREE_MODEL (impl->recent_model_filter)));
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
- RECENT_MODEL_COL_FILE,
- recent_column_path_sort_func,
+ impl->recent_model = _gtk_file_system_model_new (file_system_model_set,
+ impl,
+ MODEL_COLUMN_TYPES);
+
+ _gtk_file_system_model_set_filter (impl->recent_model,
+ impl->current_filter);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model),
+ MODEL_COL_NAME,
+ name_sort_func,
impl, NULL);
- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model_sort),
- RECENT_MODEL_COL_INFO,
- recent_column_mtime_sort_func,
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model),
+ MODEL_COL_SIZE,
+ size_sort_func,
+ impl, NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->recent_model),
+ MODEL_COL_MTIME,
+ mtime_sort_func,
impl, NULL);
set_sort_column (impl);
}
@@ -9945,7 +9249,7 @@ recent_idle_cleanup (gpointer data)
GtkFileChooserDefault *impl = load_data->impl;
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
- GTK_TREE_MODEL (impl->recent_model_sort));
+ GTK_TREE_MODEL (impl->recent_model));
set_busy_cursor (impl, FALSE);
@@ -9960,71 +9264,6 @@ recent_idle_cleanup (gpointer data)
g_free (load_data);
}
-struct RecentItemInsertRequest
-{
- GtkFileChooserDefault *impl;
- GFile *file;
- GtkTreeRowReference *row_ref;
-};
-
-static void
-recent_item_get_info_cb (GCancellable *cancellable,
- GFileInfo *info,
- const GError *error,
- gpointer data)
-{
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
- GtkTreePath *path;
- GtkTreeIter iter;
- GCancellable *model_cancellable;
- gboolean is_folder = FALSE;
- struct RecentItemInsertRequest *request = data;
-
- if (!request->impl->recent_model)
- goto out;
-
- path = gtk_tree_row_reference_get_path (request->row_ref);
- if (!path)
- goto out;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->recent_model),
- &iter, path);
- gtk_tree_path_free (path);
-
- gtk_tree_model_get (GTK_TREE_MODEL (request->impl->recent_model), &iter,
- RECENT_MODEL_COL_CANCELLABLE, &model_cancellable,
- -1);
- if (cancellable != model_cancellable)
- goto out;
-
- gtk_list_store_set (request->impl->recent_model, &iter,
- RECENT_MODEL_COL_CANCELLABLE, NULL,
- -1);
-
- if (cancelled)
- goto out;
-
- if (!info)
- {
- gtk_list_store_remove (request->impl->recent_model, &iter);
- goto out;
- }
-
- is_folder = _gtk_file_info_consider_as_directory (info);
-
- gtk_list_store_set (request->impl->recent_model, &iter,
- RECENT_MODEL_COL_IS_FOLDER, is_folder,
- -1);
-
-out:
- g_object_unref (request->impl);
- g_object_unref (request->file);
- gtk_tree_row_reference_free (request->row_ref);
- g_free (request);
-
- g_object_unref (cancellable);
-}
-
static gint
recent_sort_mru (gconstpointer a,
gconstpointer b)
@@ -10056,13 +9295,8 @@ recent_idle_load (gpointer data)
{
RecentLoadData *load_data = data;
GtkFileChooserDefault *impl = load_data->impl;
- GtkTreeIter iter;
- GtkTreePath *p;
- GtkRecentInfo *info;
- const gchar *uri, *display_name;
+ GList *walk;
GFile *file;
- GCancellable *cancellable;
- struct RecentItemInsertRequest *request;
if (!impl->recent_manager)
return FALSE;
@@ -10112,47 +9346,23 @@ recent_idle_load (gpointer data)
return TRUE;
}
- info = g_list_nth_data (load_data->items, load_data->n_loaded_items);
- g_assert (info != NULL);
-
- uri = gtk_recent_info_get_uri (info);
- display_name = gtk_recent_info_get_display_name (info);
- file = g_file_new_for_uri (uri);
-
- gtk_list_store_append (impl->recent_model, &iter);
- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->recent_model), &iter);
-
- request = g_new0 (struct RecentItemInsertRequest, 1);
- request->impl = g_object_ref (impl);
- request->file = g_object_ref (file);
- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->recent_model), p);
- gtk_tree_path_free (p);
-
- cancellable = _gtk_file_system_get_info (impl->file_system, file,
- "standard::type",
- recent_item_get_info_cb,
- request);
-
- gtk_list_store_set (impl->recent_model, &iter,
- RECENT_MODEL_COL_FILE, file,
- RECENT_MODEL_COL_DISPLAY_NAME, g_strdup (display_name),
- RECENT_MODEL_COL_INFO, gtk_recent_info_ref (info),
- RECENT_MODEL_COL_CANCELLABLE, cancellable,
- -1);
-
- load_data->n_loaded_items += 1;
-
/* finished loading items */
- if (load_data->n_loaded_items == load_data->n_items)
+ for (walk = load_data->items; walk; walk = walk->next)
{
- g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
- g_list_free (load_data->items);
- load_data->items = NULL;
+ GtkRecentInfo *info = walk->data;
+ file = g_file_new_for_uri (gtk_recent_info_get_uri (info));
- return FALSE;
+ _gtk_file_system_model_add_and_query_file (impl->recent_model,
+ file,
+ MODEL_ATTRIBUTES);
+ gtk_recent_info_unref (walk->data);
+ g_object_unref (file);
}
- return TRUE;
+ g_list_free (load_data->items);
+ load_data->items = NULL;
+
+ return FALSE;
}
static void
@@ -10192,8 +9402,8 @@ recent_selected_foreach_get_file_cb (GtkTreeModel *model,
list = data;
- gtk_tree_model_get (model, iter, RECENT_MODEL_COL_FILE, &file, -1);
- *list = g_slist_prepend (*list, g_object_ref (file));
+ gtk_tree_model_get (model, iter, MODEL_COL_FILE, &file, -1);
+ *list = g_slist_prepend (*list, file);
}
/* Constructs a list of the selected paths in recent files mode */
@@ -10232,6 +9442,7 @@ recent_hide_entry (GtkFileChooserDefault *impl)
{
GtkWidget *label;
GtkWidget *image;
+ gchar *tmp;
impl->recent_hbox = gtk_hbox_new (FALSE, 12);
@@ -10242,8 +9453,10 @@ recent_hide_entry (GtkFileChooserDefault *impl)
/* Label */
label = gtk_label_new (NULL);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Recently Used</b>"));
+ tmp = g_strdup_printf ("<b>%s</b>", _("Recently Used"));
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), tmp);
gtk_box_pack_start (GTK_BOX (impl->recent_hbox), label, FALSE, FALSE, 0);
+ g_free (tmp);
gtk_widget_hide (impl->browse_path_bar);
gtk_widget_hide (impl->browse_new_folder_button);
@@ -10279,41 +9492,10 @@ recent_activate (GtkFileChooserDefault *impl)
recent_hide_entry (impl);
- /* hide the file size column if it's visible */
- gtk_tree_view_column_set_visible (impl->list_size_column, FALSE);
-
file_list_set_sort_column_ids (impl);
recent_start_loading (impl);
}
-/* convert an iterator coming from the model bound to
- * browse_files_tree_view to an interator inside the
- * real recent_model
- */
-static void
-recent_get_valid_child_iter (GtkFileChooserDefault *impl,
- GtkTreeIter *child_iter,
- GtkTreeIter *iter)
-{
- GtkTreeIter middle;
-
- if (!impl->recent_model)
- return;
-
- if (!impl->recent_model_filter || !impl->recent_model_sort)
- return;
-
- /* pass 1: get the iterator in the filter model */
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->recent_model_sort,
- &middle, iter);
-
- /* pass 2: get the iterator in the real model */
- gtk_tree_model_filter_convert_iter_to_child_iter (impl->recent_model_filter,
- child_iter,
- &middle);
-}
-
-
static void
set_current_filter (GtkFileChooserDefault *impl,
GtkFileFilter *filter)
@@ -10343,11 +9525,11 @@ set_current_filter (GtkFileChooserDefault *impl,
if (impl->browse_files_model)
install_list_model_filter (impl);
- if (impl->search_model_filter)
- gtk_tree_model_filter_refilter (impl->search_model_filter);
+ if (impl->search_model)
+ _gtk_file_system_model_set_filter (impl->search_model, filter);
- if (impl->recent_model_filter)
- gtk_tree_model_filter_refilter (impl->recent_model_filter);
+ if (impl->recent_model)
+ _gtk_file_system_model_set_filter (impl->recent_model, filter);
g_object_notify (G_OBJECT (impl), "filter");
}
@@ -10368,61 +9550,27 @@ check_preview_change (GtkFileChooserDefault *impl)
{
GtkTreePath *cursor_path;
GFile *new_file;
- const char *new_display_name;
+ char *new_display_name;
+ GtkTreeModel *model;
gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
- new_file = NULL;
- new_display_name = NULL;
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (impl->browse_files_tree_view));
if (cursor_path)
{
- GtkTreeIter child_iter;
-
- if (impl->operation_mode == OPERATION_MODE_BROWSE)
- {
- if (impl->sort_model)
- {
- GtkTreeIter iter;
- GFileInfo *new_info;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
- gtk_tree_path_free (cursor_path);
-
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
-
- new_file = _gtk_file_system_model_get_file (impl->browse_files_model, &child_iter);
- new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- if (new_info)
- new_display_name = g_file_info_get_display_name (new_info);
- }
- }
- else if (impl->operation_mode == OPERATION_MODE_SEARCH)
- {
- GtkTreeIter iter;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort),
- &iter, cursor_path);
- gtk_tree_path_free (cursor_path);
-
- search_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_FILE, &new_file,
- SEARCH_MODEL_COL_DISPLAY_NAME, &new_display_name,
- -1);
- }
- else if (impl->operation_mode == OPERATION_MODE_RECENT)
- {
- GtkTreeIter iter;
-
- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort),
- &iter, cursor_path);
- gtk_tree_path_free (cursor_path);
+ GtkTreeIter iter;
- recent_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &new_file,
- RECENT_MODEL_COL_DISPLAY_NAME, &new_display_name,
- -1);
- }
+ gtk_tree_model_get_iter (model, &iter, cursor_path);
+ gtk_tree_model_get (model, &iter,
+ MODEL_COL_FILE, &new_file,
+ MODEL_COL_NAME, &new_display_name,
+ -1);
+
+ gtk_tree_path_free (cursor_path);
+ }
+ else
+ {
+ new_file = NULL;
+ new_display_name = NULL;
}
if (new_file != impl->preview_file &&
@@ -10437,13 +9585,14 @@ check_preview_change (GtkFileChooserDefault *impl)
if (new_file)
{
- impl->preview_file = g_object_ref (new_file);
- impl->preview_display_name = g_strdup (new_display_name);
+ impl->preview_file = new_file;
+ impl->preview_display_name = new_display_name;
}
else
{
impl->preview_file = NULL;
impl->preview_display_name = NULL;
+ g_free (new_display_name);
}
if (impl->use_preview_label && impl->preview_label)
@@ -10707,6 +9856,12 @@ shortcuts_key_press_event_cb (GtkWidget *widget,
modifiers = gtk_accelerator_get_default_mod_mask ();
+ if (key_is_left_or_right (event))
+ {
+ gtk_widget_grab_focus (impl->browse_files_tree_view);
+ return TRUE;
+ }
+
if ((event->keyval == GDK_BackSpace
|| event->keyval == GDK_Delete
|| event->keyval == GDK_KP_Delete)
@@ -10757,56 +9912,16 @@ list_select_func (GtkTreeSelection *selection,
if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
- GtkTreeIter iter, child_iter;
-
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_SEARCH:
- {
- gboolean is_folder;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
- return FALSE;
-
- search_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
- if (!is_folder)
- return FALSE;
- }
- break;
-
- case OPERATION_MODE_RECENT:
- {
- gboolean is_folder;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
- return FALSE;
-
- recent_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
- if (!is_folder)
- return FALSE;
- }
- break;
-
- case OPERATION_MODE_BROWSE:
- {
- GFileInfo *info;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
- return FALSE;
+ GtkTreeIter iter;
+ gboolean is_folder;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- if (info && (! _gtk_file_info_consider_as_directory (info)))
- return FALSE;
- }
- break;
- }
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return FALSE;
+ gtk_tree_model_get (model, &iter,
+ MODEL_COL_IS_FOLDER, &is_folder,
+ -1);
+ if (!is_folder)
+ return FALSE;
}
return TRUE;
@@ -10849,103 +9964,33 @@ list_row_activated (GtkTreeView *tree_view,
GtkTreeViewColumn *column,
GtkFileChooserDefault *impl)
{
+ GFile *file;
GtkTreeIter iter;
- GtkTreeIter child_iter;
-
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_SEARCH:
- {
- GFile *file;
- gboolean is_folder;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model_sort), &iter, path))
- return;
-
- search_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_FILE, &file,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (is_folder)
- {
- change_folder_and_display_error (impl, file, FALSE);
- return;
- }
+ GtkTreeModel *model;
+ gboolean is_folder;
- g_signal_emit_by_name (impl, "file-activated");
- }
- break;
+ model = gtk_tree_view_get_model (tree_view);
- case OPERATION_MODE_RECENT:
- {
- GFile *file;
- gboolean is_folder;
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->recent_model_sort), &iter, path))
- return;
-
- recent_get_valid_child_iter (impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &file,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (is_folder)
- {
- change_folder_and_display_error (impl, file, FALSE);
- return;
- }
+ gtk_tree_model_get (model, &iter,
+ MODEL_COL_FILE, &file,
+ MODEL_COL_IS_FOLDER, &is_folder,
+ -1);
- g_signal_emit_by_name (impl, "file-activated");
- }
- break;
-
- case OPERATION_MODE_BROWSE:
- {
- GFileInfo *info;
+ if (is_folder && file)
+ {
+ change_folder_and_display_error (impl, file, FALSE);
+ return;
+ }
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
- return;
-
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter, &iter);
- info = _gtk_file_system_model_get_info (impl->browse_files_model,
- &child_iter);
-
- if (_gtk_file_info_consider_as_directory (info))
- {
- GFile *file, *target_file;
- const gchar *target_uri;
-
- file = _gtk_file_system_model_get_file (impl->browse_files_model, &child_iter);
- if (g_file_info_get_file_type (info) == G_FILE_TYPE_MOUNTABLE ||
- g_file_info_get_file_type (info) == G_FILE_TYPE_SHORTCUT)
- {
- target_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
- if (target_uri)
- {
- target_file = g_file_new_for_uri (target_uri);
- if (target_file)
- {
- g_object_unref (file);
- file = target_file;
- }
- }
- }
-
-
- change_folder_and_display_error (impl, file, FALSE);
- return;
- }
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ g_signal_emit_by_name (impl, "file-activated");
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
- impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
- g_signal_emit_by_name (impl, "file-activated");
- }
- break;
- }
+ if (file)
+ g_object_unref (file);
}
static void
@@ -10969,472 +10014,70 @@ path_bar_clicked (GtkPathBar *path_bar,
g_object_set (impl, "show-hidden", TRUE, NULL);
}
-static GFileInfo *
-get_list_file_info (GtkFileChooserDefault *impl,
- GtkTreeIter *iter)
-{
- GtkTreeIter child_iter;
-
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- iter);
-
- return _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
-}
-
static void
-list_icon_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
+update_cell_renderer_attributes (GtkFileChooserDefault *impl)
{
- GtkFileChooserDefault *impl = data;
- GtkTreeIter child_iter;
- GdkPixbuf *pixbuf = NULL;
- gboolean sensitive = TRUE;
-
- profile_start ("start", NULL);
-
- switch (impl->operation_mode)
- {
- case OPERATION_MODE_SEARCH:
- {
- GtkTreeIter child_iter;
- gboolean is_folder;
-
- search_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_PIXBUF, &pixbuf,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = is_folder;
- }
- break;
-
- case OPERATION_MODE_RECENT:
- {
- GtkTreeIter child_iter;
- GtkRecentInfo *info;
- gboolean is_folder;
-
- recent_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_INFO, &info,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- pixbuf = gtk_recent_info_get_icon (info, impl->icon_size);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = is_folder;
- }
- break;
-
- case OPERATION_MODE_BROWSE:
- {
- GFileInfo *info;
- GFile *file;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GList *walk, *list;
+ gboolean always_sensitive;
- info = get_list_file_info (impl, iter);
+ always_sensitive = impl->action != GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
+ impl->action != GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- iter);
- file = _gtk_file_system_model_get_file (impl->browse_files_model, &child_iter);
- if (file)
- {
- if (info)
- {
- /* FIXME: NULL GError */
- pixbuf = _gtk_file_info_render_icon (info, GTK_WIDGET (impl), impl->icon_size);
- }
- }
- else
- {
- /* We are on the editable row */
- pixbuf = NULL;
- }
-
- if (info &&
- (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
- sensitive = _gtk_file_info_consider_as_directory (info);
- }
- break;
- }
-
- g_object_set (cell,
- "pixbuf", pixbuf,
- "sensitive", sensitive,
- NULL);
-
- if (pixbuf)
- g_object_unref (pixbuf);
-
- profile_end ("end", NULL);
-}
+ /* Keep the following column numbers in sync with create_file_list() */
-static void
-list_name_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- GtkFileChooserDefault *impl = data;
- GFileInfo *info;
- gboolean sensitive = TRUE;
-
- if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ /* name */
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 0);
+ list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+ for (walk = list; walk; walk = walk->next)
{
- GtkTreeIter child_iter;
- gchar *display_name;
- gboolean is_folder;
-
- search_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ renderer = walk->data;
+ if (GTK_IS_CELL_RENDERER_PIXBUF (renderer))
{
- sensitive = is_folder;
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "pixbuf", MODEL_COL_PIXBUF,
+ NULL);
}
-
- g_object_set (cell,
- "text", display_name,
- "sensitive", sensitive,
- "ellipsize", PANGO_ELLIPSIZE_END,
- NULL);
-
- return;
- }
-
- if (impl->operation_mode == OPERATION_MODE_RECENT)
- {
- GtkTreeIter child_iter;
- GtkRecentInfo *recent_info;
- gchar *display_name;
- gboolean is_folder;
-
- recent_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_INFO, &recent_info,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- display_name = gtk_recent_info_get_short_name (recent_info);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ else
{
- sensitive = is_folder;
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", MODEL_COL_NAME,
+ "ellipsize", MODEL_COL_ELLIPSIZE,
+ NULL);
}
-
- g_object_set (cell,
- "text", display_name,
- "sensitive", sensitive,
- "ellipsize", PANGO_ELLIPSIZE_END,
- NULL);
-
- g_free (display_name);
-
- return;
- }
-
- info = get_list_file_info (impl, iter);
- sensitive = TRUE;
-
- if (!info)
- {
- g_object_set (cell,
- "text", DEFAULT_NEW_FOLDER_NAME,
- "sensitive", TRUE,
- "ellipsize", PANGO_ELLIPSIZE_NONE,
- NULL);
-
- return;
- }
-
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- {
- sensitive = _gtk_file_info_consider_as_directory (info);
- }
-
- g_object_set (cell,
- "text", g_file_info_get_display_name (info),
- "sensitive", sensitive,
- "ellipsize", PANGO_ELLIPSIZE_END,
- NULL);
-}
-
-static void
-list_size_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- GtkFileChooserDefault *impl = data;
- GFileInfo *info;
- goffset size;
- gchar *str;
- gboolean sensitive = TRUE;
-
- if (impl->operation_mode == OPERATION_MODE_RECENT)
- return;
-
- if (impl->operation_mode == OPERATION_MODE_SEARCH)
- {
- GtkTreeIter child_iter;
- gboolean is_folder = FALSE;
-
- search_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_SIZE, &size,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = is_folder ? TRUE : FALSE;
-
- if (!is_folder)
- str = g_format_size_for_display (size);
- else
- str = NULL;
-
- g_object_set (cell,
- "text", str,
- "sensitive", sensitive,
- NULL);
-
- g_free (str);
-
- return;
- }
-
- info = get_list_file_info (impl, iter);
-
- if (!info || _gtk_file_info_consider_as_directory (info))
- {
- g_object_set (cell,
- "text", NULL,
- "sensitive", sensitive,
- NULL);
- return;
- }
-
- size = g_file_info_get_size (info);
- str = g_format_size_for_display (size);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = FALSE;
-
- g_object_set (cell,
- "text", str,
- "sensitive", sensitive,
- NULL);
-
- g_free (str);
-}
-
-/* Tree column data callback for the file list; fetches the mtime of a file */
-static void
-list_mtime_data_func (GtkTreeViewColumn *tree_column,
- GtkCellRenderer *cell,
- GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gpointer data)
-{
- GtkFileChooserDefault *impl;
- GTimeVal timeval = { 0, };
- time_t time_mtime;
- gchar *date_str = NULL;
- gboolean sensitive = TRUE;
-#ifdef G_OS_WIN32
- const char *locale, *dot = NULL;
- gint64 codepage = -1;
- char charset[20];
-#endif
-
- impl = data;
-
- if (impl->operation_mode == OPERATION_MODE_SEARCH)
- {
- GtkTreeIter child_iter;
- guint64 mtime;
- gboolean is_folder;
-
- search_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &child_iter,
- SEARCH_MODEL_COL_MTIME, &mtime,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- time_mtime = (time_t) mtime;
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = is_folder;
- }
- else if (impl->operation_mode == OPERATION_MODE_RECENT)
- {
- GtkTreeIter child_iter;
- GtkRecentInfo *info;
- gboolean is_folder;
-
- recent_get_valid_child_iter (impl, &child_iter, iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &child_iter,
- RECENT_MODEL_COL_INFO, &info,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- if (info)
- time_mtime = gtk_recent_info_get_modified (info);
+ if (always_sensitive)
+ g_object_set (renderer, "sensitive", TRUE, NULL);
else
- time_mtime = 0;
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = is_folder;
- }
+ gtk_tree_view_column_add_attribute (column, renderer, "sensitive", MODEL_COL_IS_FOLDER);
+ }
+ g_list_free (list);
+
+ /* size */
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 1);
+ list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+ renderer = list->data;
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", MODEL_COL_SIZE_TEXT,
+ NULL);
+ if (always_sensitive)
+ g_object_set (renderer, "sensitive", TRUE, NULL);
else
- {
- GFileInfo *info;
-
- info = get_list_file_info (impl, iter);
- if (!info)
- {
- g_object_set (cell,
- "text", "",
- "sensitive", TRUE,
- NULL);
- return;
- }
-
- g_file_info_get_modification_time (info, &timeval);
- time_mtime = timeval.tv_sec;
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = _gtk_file_info_consider_as_directory (info);
- }
-
- if (G_UNLIKELY (time_mtime == 0))
- date_str = g_strdup (_("Unknown"));
+ gtk_tree_view_column_add_attribute (column, renderer, "sensitive", MODEL_COL_IS_FOLDER);
+ g_list_free (list);
+
+ /* mtime */
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_files_tree_view), 2);
+ list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
+ renderer = list->data;
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", MODEL_COL_MTIME_TEXT,
+ NULL);
+ if (always_sensitive)
+ g_object_set (renderer, "sensitive", TRUE, NULL);
else
- {
- GDate mtime, now;
- gint days_diff;
- struct tm tm_mtime;
- time_t time_now;
- const gchar *format;
- gchar *locale_format = NULL;
- gchar buf[256];
-
-#ifdef HAVE_LOCALTIME_R
- localtime_r ((time_t *) &time_mtime, &tm_mtime);
-#else
- {
- struct tm *ptm = localtime ((time_t *) &timeval.tv_sec);
-
- if (!ptm)
- {
- g_warning ("ptm != NULL failed");
-
- g_object_set (cell,
- "text", _("Unknown"),
- "sensitive", sensitive,
- NULL);
- return;
- }
- else
- memcpy ((void *) &tm_mtime, (void *) ptm, sizeof (struct tm));
- }
-#endif /* HAVE_LOCALTIME_R */
-
- g_date_set_time_t (&mtime, time_mtime);
- time_now = time (NULL);
- g_date_set_time_t (&now, time_now);
-
- days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
-
- /* Translators: %H means "hours" and %M means "minutes" */
- if (days_diff == 0)
- format = _("%H:%M");
- else if (days_diff == 1)
- format = _("Yesterday at %H:%M");
- else
- {
- if (days_diff > 1 && days_diff < 7)
- format = "%A"; /* Days from last week */
- else
- format = "%x"; /* Any other date */
- }
-
-#ifdef G_OS_WIN32
- /* g_locale_from_utf8() returns a string in the system
- * code-page, which is not always the same as that used by the C
- * library. For instance when running a GTK+ program with
- * LANG=ko on an English version of Windows, the system
- * code-page is 1252, but the code-page used by the C library is
- * 949. (It's GTK+ itself that sets the C library locale when it
- * notices the LANG environment variable. See gtkmain.c The
- * Microsoft C library doesn't look at any locale environment
- * variables.) We need to pass strftime() a string in the C
- * library's code-page. See bug #509885.
- */
- locale = setlocale (LC_ALL, NULL);
- if (locale != NULL)
- dot = strchr (locale, '.');
- if (dot != NULL)
- {
- codepage = g_ascii_strtoll (dot+1, NULL, 10);
-
- /* All codepages should fit in 16 bits AFAIK */
- if (codepage > 0 && codepage < 65536)
- {
- sprintf (charset, "CP%u", (guint) codepage);
- locale_format = g_convert (format, -1, charset, "UTF-8", NULL, NULL, NULL);
- }
- }
-#else
- locale_format = g_locale_from_utf8 (format, -1, NULL, NULL, NULL);
-#endif
- if (locale_format != NULL &&
- strftime (buf, sizeof (buf), locale_format, &tm_mtime) != 0)
- {
-#ifdef G_OS_WIN32
- /* As above but in opposite direction... */
- if (codepage > 0 && codepage < 65536)
- date_str = g_convert (buf, -1, "UTF-8", charset, NULL, NULL, NULL);
-#else
- date_str = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
-#endif
- }
-
- if (date_str == NULL)
- date_str = g_strdup (_("Unknown"));
-
- g_free (locale_format);
- }
-
- g_object_set (cell,
- "text", date_str,
- "sensitive", sensitive,
- NULL);
- g_free (date_str);
+ gtk_tree_view_column_add_attribute (column, renderer, "sensitive", MODEL_COL_IS_FOLDER);
+ g_list_free (list);
}
GtkWidget *
@@ -11705,172 +10348,3 @@ shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
return GTK_TREE_MODEL (model);
}
-
-
-static gboolean
-recent_model_sort_row_draggable (GtkTreeDragSource *drag_source,
- GtkTreePath *path)
-{
- RecentModelSort *model;
- GtkTreeIter iter, child_iter;
- gboolean is_folder;
-
- model = RECENT_MODEL_SORT (drag_source);
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
- return FALSE;
-
- recent_get_valid_child_iter (model->impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
- RECENT_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- return is_folder;
-}
-
-static gboolean
-recent_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data)
-{
- RecentModelSort *model;
- GtkTreeIter iter, child_iter;
- GFile *file;
- gchar *uris[2];
-
- model = RECENT_MODEL_SORT (drag_source);
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
- return FALSE;
-
- recent_get_valid_child_iter (model->impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->recent_model), &child_iter,
- RECENT_MODEL_COL_FILE, &file,
- -1);
- g_assert (file != NULL);
-
- uris[0] = g_file_get_uri (file);
- uris[1] = NULL;
-
- gtk_selection_data_set_uris (selection_data, uris);
-
- g_free (uris[0]);
-
- return TRUE;
-}
-
-static void
-recent_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
-{
- iface->row_draggable = recent_model_sort_row_draggable;
- iface->drag_data_get = recent_model_sort_drag_data_get;
-}
-
-static void
-_recent_model_sort_class_init (RecentModelSortClass *klass)
-{
-
-}
-
-static void
-_recent_model_sort_init (RecentModelSort *model)
-{
- model->impl = NULL;
-}
-
-static GtkTreeModel *
-recent_model_sort_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model)
-{
- RecentModelSort *model;
-
- model = g_object_new (RECENT_MODEL_SORT_TYPE,
- "model", child_model,
- NULL);
- model->impl = impl;
-
- return GTK_TREE_MODEL (model);
-}
-
-
-
-static gboolean
-search_model_sort_row_draggable (GtkTreeDragSource *drag_source,
- GtkTreePath *path)
-{
- SearchModelSort *model;
- GtkTreeIter iter, child_iter;
- gboolean is_folder;
-
- model = SEARCH_MODEL_SORT (drag_source);
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
- return FALSE;
-
- search_get_valid_child_iter (model->impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
- SEARCH_MODEL_COL_IS_FOLDER, &is_folder,
- -1);
-
- return is_folder;
-}
-
-static gboolean
-search_model_sort_drag_data_get (GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data)
-{
- SearchModelSort *model;
- GtkTreeIter iter, child_iter;
- GFile *file;
- gchar *uris[2];
-
- model = SEARCH_MODEL_SORT (drag_source);
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
- return FALSE;
-
- search_get_valid_child_iter (model->impl, &child_iter, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (model->impl->search_model), &child_iter,
- RECENT_MODEL_COL_FILE, &file,
- -1);
- g_assert (file != NULL);
-
- uris[0] = g_file_get_uri (file);
- uris[1] = NULL;
-
- gtk_selection_data_set_uris (selection_data, uris);
-
- g_free (uris[0]);
-
- return TRUE;
-}
-
-static void
-search_model_sort_drag_source_iface_init (GtkTreeDragSourceIface *iface)
-{
- iface->row_draggable = search_model_sort_row_draggable;
- iface->drag_data_get = search_model_sort_drag_data_get;
-}
-
-static void
-_search_model_sort_class_init (SearchModelSortClass *klass)
-{
-
-}
-
-static void
-_search_model_sort_init (SearchModelSort *model)
-{
- model->impl = NULL;
-}
-
-static GtkTreeModel *
-search_model_sort_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model)
-{
- SearchModelSort *model;
-
- model = g_object_new (SEARCH_MODEL_SORT_TYPE,
- "model", child_model,
- NULL);
- model->impl = impl;
-
- return GTK_TREE_MODEL (model);
-}
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index 0868691e22..2dd3737154 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -224,6 +224,11 @@ file_chooser_widget_response_requested (GtkWidget *widget,
{
GList *children, *l;
+ dialog->priv->response_requested = TRUE;
+
+ if (gtk_window_activate_default (GTK_WINDOW (dialog)))
+ return;
+
/* There probably isn't a default widget, so make things easier for the
* programmer by looking for a reasonable button on our own.
*/
@@ -239,12 +244,14 @@ file_chooser_widget_response_requested (GtkWidget *widget,
response_id = gtk_dialog_get_response_for_widget (GTK_DIALOG (dialog), widget);
if (is_stock_accept_response_id (response_id))
{
- dialog->priv->response_requested = TRUE;
gtk_widget_activate (widget); /* Should we gtk_dialog_response (dialog, response_id) instead? */
break;
}
}
+ if (l == NULL)
+ dialog->priv->response_requested = FALSE;
+
g_list_free (children);
}
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index be10757c29..9f02b42e67 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -194,17 +194,13 @@ struct _GtkFileChooserDefault
GtkWidget *search_entry;
GtkSearchEngine *search_engine;
GtkQuery *search_query;
- GtkListStore *search_model;
- GtkTreeModelFilter *search_model_filter;
- GtkTreeModelSort *search_model_sort;
+ GtkFileSystemModel *search_model;
/* OPERATION_MODE_RECENT */
GtkWidget *recent_hbox;
GtkRecentManager *recent_manager;
- GtkListStore *recent_model;
+ GtkFileSystemModel *recent_model;
guint load_recent_id;
- GtkTreeModelFilter *recent_model_filter;
- GtkTreeModelSort *recent_model_sort;
GtkWidget *filter_combo_hbox;
GtkWidget *filter_combo;
@@ -232,14 +228,11 @@ struct _GtkFileChooserDefault
*/
GtkTreeModel *shortcuts_combo_filter_model;
- GtkTreeModelSort *sort_model;
-
/* Handles */
GSList *loading_shortcuts;
GSList *reload_icon_cancellables;
GCancellable *file_list_drag_data_received_cancellable;
GCancellable *update_current_folder_cancellable;
- GCancellable *show_and_select_files_cancellable;
GCancellable *should_respond_get_info_cancellable;
GCancellable *file_exists_get_info_cancellable;
GCancellable *update_from_entry_cancellable;
@@ -308,6 +301,7 @@ struct _GtkFileChooserDefault
guint has_search : 1;
guint has_recent : 1;
guint show_size_column : 1;
+ guint create_folders : 1;
#if 0
guint shortcuts_drag_outside : 1;
@@ -315,63 +309,6 @@ struct _GtkFileChooserDefault
};
-/* GtkFileSystemModel private */
-
-typedef struct _FileModelNode FileModelNode;
-
-struct _GtkFileSystemModel
-{
- GObject parent_instance;
-
- GtkFileSystem *file_system;
- gchar *attributes;
- FileModelNode *roots;
- GtkFolder *root_folder;
- GFile *root_file;
-
- GtkFileSystemModelFilter filter_func;
- gpointer filter_data;
-
- GSList *idle_clears;
- GSource *idle_clear_source;
-
- gushort max_depth;
-
- GSList *pending_cancellables;
-
- guint show_hidden : 1;
- guint show_folders : 1;
- guint show_files : 1;
- guint folders_only : 1;
- guint has_editable : 1;
-};
-
-struct _FileModelNode
-{
- GFile *file;
- FileModelNode *next;
-
- GFileInfo *info;
- GtkFolder *folder;
-
- FileModelNode *children;
- FileModelNode *parent;
- GtkFileSystemModel *model;
-
- guint ref_count;
- guint n_referenced_children;
-
- gushort depth;
-
- guint has_dummy : 1;
- guint is_dummy : 1;
- guint is_visible : 1;
- guint loaded : 1;
- guint idle_clear : 1;
- guint load_pending : 1;
-};
-
-
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_PRIVATE_H__ */
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 0eab525b3f..69c71d1116 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -117,6 +117,9 @@ _gtk_file_chooser_install_properties (GObjectClass *klass)
g_object_class_override_property (klass,
GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
"do-overwrite-confirmation");
+ g_object_class_override_property (klass,
+ GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
+ "create-folders");
}
/**
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index c5c1aa75aa..a590cccd16 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -41,7 +41,8 @@ typedef enum {
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
- GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION
+ GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
+ GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS
} GtkFileChooserProp;
void _gtk_file_chooser_install_properties (GObjectClass *klass);
diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c
index 0aa9f17d91..eca76ca910 100644
--- a/gtk/gtkfilesel.c
+++ b/gtk/gtkfilesel.c
@@ -1355,8 +1355,10 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget,
if (g_mkdir (sys_full_path, 0777) < 0)
{
+ int errsv = errno;
+
buf = g_strdup_printf (_("Error creating folder '%s': %s"),
- dirname, g_strerror (errno));
+ dirname, g_strerror (errsv));
gtk_file_selection_fileop_error (fs, buf);
}
@@ -1484,8 +1486,10 @@ gtk_file_selection_delete_file_response (GtkDialog *dialog,
if (g_unlink (sys_full_path) < 0)
{
+ int errsv = errno;
+
buf = g_strdup_printf (_("Error deleting file '%s': %s"),
- fs->fileop_file, g_strerror (errno));
+ fs->fileop_file, g_strerror (errsv));
gtk_file_selection_fileop_error (fs, buf);
}
@@ -1602,9 +1606,11 @@ gtk_file_selection_rename_file_confirmed (GtkWidget *widget,
if (g_rename (sys_old_filename, sys_new_filename) < 0)
{
+ int errsv = errno;
+
buf = g_strdup_printf (_("Error renaming file \"%s\" to \"%s\": %s"),
sys_old_filename, sys_new_filename,
- g_strerror (errno));
+ g_strerror (errsv));
gtk_file_selection_fileop_error (fs, buf);
goto out2;
}
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index 1d0b736d07..095969bdc6 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -19,19 +19,159 @@
*/
#include "config.h"
-#include <string.h>
-#include "gtkfilechooserprivate.h"
#include "gtkfilesystemmodel.h"
+
+#include <stdlib.h>
+#include <string.h>
+
#include "gtkfilesystem.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
+#include "gtktreedatalist.h"
#include "gtktreednd.h"
#include "gtktreemodel.h"
#include "gtkalias.h"
+/*** Structure: how GtkFileSystemModel works
+ *
+ * This is a custom GtkTreeModel used to hold a collection of files for GtkFileChooser. There are two use cases:
+ *
+ * 1. The model populates itself from a folder, using the GIO file enumerator API. This happens if you use
+ * _gtk_file_system_model_new_for_directory(). This is the normal usage for showing the contents of a folder.
+ *
+ * 2. The caller populates the model by hand, with files not necessarily in the same folder. This happens
+ * if you use _gtk_file_system_model_new() and then _gtk_file_system_model_add_and_query_file(). This is
+ * the special kind of usage for "search" and "recent-files", where the file chooser gives the model the
+ * files to be displayed.
+ *
+ * Each file is kept in a FileModelNode structure. Each FileModelNode holds a GFile* and other data. All the
+ * node structures have the same size, determined at runtime, depending on the number of columns that were passed
+ * to _gtk_file_system_model_new() or _gtk_file_system_model_new_for_directory() (that is, the size of a node is
+ * not sizeof (FileModelNode), but rather model->node_size). The last field in the FileModelNode structure,
+ * node->values[], is an array of GValue, used to hold the data for those columns.
+ *
+ * The model stores an array of FileModelNode structures in model->files. This is a GArray where each element is
+ * model->node_size bytes in size (the model computes that node size when initializing itself). There are
+ * convenience macros, get_node() and node_index(), to access that array based on an array index or a pointer to
+ * a node inside the array.
+ *
+ * The model accesses files through two of its fields:
+ *
+ * model->files - GArray of FileModelNode structures.
+ *
+ * model->file_lookup - hash table that maps a GFile* to an index inside the model->files array.
+ *
+ * The model->file_lookup hash table is populated lazily. It is both accessed and populated with the
+ * node_get_for_file() function. The invariant is that the files in model->files[n] for n < g_hash_table_size
+ * (model->file_lookup) are already added to the hash table. The hash table will get cleared when we re-sort the
+ * files, as the array will be in a different order and the indexes need to be rebuilt.
+ *
+ * Each FileModelNode has a node->visible field, which indicates whether the node is visible in the GtkTreeView.
+ * A node may be invisible if, for example, it corresponds to a hidden file and the file chooser is not showing
+ * hidden files.
+ *
+ * Since not all nodes in the model->files array may be visible, we need a way to map visible row indexes from
+ * the treeview to array indexes in our array of files. And thus we introduce a bit of terminology:
+ *
+ * index - An index in the model->files array. All variables/fields that represent indexes are either called
+ * "index" or "i_*", or simply "i" for things like loop counters.
+ *
+ * row - An index in the GtkTreeView, i.e. the index of a row within the outward-facing API of the
+ * GtkFileSystemModel. However, note that our rows are 1-based, not 0-based, for the reason explained in the
+ * following paragraph. Variables/fields that represent visible rows are called "row", or "r_*", or simply
+ * "r".
+ *
+ * Each FileModelNode has a node->row field which is the number of visible rows in the treeview, *before and
+ * including* that node. This means that node->row is 1-based, instead of 0-based --- this makes some code
+ * simpler, believe it or not :) This also means that when the calling GtkTreeView gives us a GtkTreePath, we
+ * turn the 0-based treepath into a 1-based row for our purposes. If a node is not visible, it will have the
+ * same row number as its closest preceding visible node.
+ *
+ * We try to compute the node->row fields lazily. A node is said to be "valid" if its node->row is accurate.
+ * For this, the model keeps a model->n_nodes_valid field which is the count of valid nodes starting from the
+ * beginning of the model->files array. When a node changes its information, or when a node gets deleted, that
+ * node and the following ones get invalidated by simply setting model->n_nodes_valid to the array index of the
+ * node. If the model happens to need a node's row number and that node is in the model->files array after
+ * model->n_nodes_valid, then the nodes get re-validated up to the sought node. See node_validate_rows() for
+ * this logic.
+ *
+ * You never access a node->row directly. Instead, call node_get_tree_row(). That function will validate the nodes
+ * up to the sought one if the node is not valid yet, and it will return a proper 0-based row.
+ */
+
+/*** DEFINES ***/
+
+/* priority used for all async callbacks in the main loop
+ * This should be higher than redraw priorities so multiple callbacks
+ * firing can be handled without intermediate redraws */
+#define IO_PRIORITY G_PRIORITY_DEFAULT
+
+/* random number that everyone else seems to use, too */
+#define FILES_PER_QUERY 100
+
+typedef struct _FileModelNode FileModelNode;
typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
+struct _FileModelNode
+{
+ GFile * file; /* file represented by this node or NULL for editable */
+ GFileInfo * info; /* info for this file or NULL if unknown */
+
+ guint row; /* if valid (see model->n_valid_indexes), visible nodes before and including
+ * this one - see the "Structure" comment above.
+ */
+
+ guint visible :1; /* if the file is currently visible */
+ guint frozen_add :1; /* true if the model was frozen and the entry has not been added yet */
+
+ GValue values[1]; /* actually n_columns values */
+};
+
+struct _GtkFileSystemModel
+{
+ GObject parent_instance;
+
+ GFile * dir; /* directory that's displayed */
+ guint dir_thaw_source;/* GSource id for unfreezing the model */
+ char * attributes; /* attributes the file info must contain, or NULL for all attributes */
+ GFileMonitor * dir_monitor; /* directory that is monitored, or NULL if monitoring was not supported */
+
+ GCancellable * cancellable; /* cancellable in use for all operations - cancelled on dispose */
+ GArray * files; /* array of FileModelNode containing all our files */
+ gsize node_size; /* Size of a FileModelNode structure once its ->values field has n_columns */
+ guint n_nodes_valid; /* count of valid nodes (i.e. those whose node->row is accurate) */
+ GHashTable * file_lookup; /* mapping of GFile => array index in model->files
+ * This hash table doesn't always have the same number of entries as the files array;
+ * it can get cleared completely when we resort.
+ * The hash table gets re-populated in node_get_for_file() if this mismatch is
+ * detected.
+ */
+
+ guint n_columns; /* number of columns */
+ GType * column_types; /* types of each column */
+ GtkFileSystemModelGetValue get_func; /* function to call to fill in values in columns */
+ gpointer get_data; /* data to pass to get_func */
+
+ GtkFileFilter * filter; /* filter to use for deciding which nodes are visible */
+
+ int sort_column_id; /* current sorting column */
+ GtkSortType sort_order; /* current sorting order */
+ GList * sort_list; /* list of sorting functions */
+ GtkTreeIterCompareFunc default_sort_func; /* default sort function */
+ gpointer default_sort_data; /* data to pass to default sort func */
+ GDestroyNotify default_sort_destroy; /* function to call to destroy default_sort_data */
+
+ guint frozen; /* number of times we're frozen */
+
+ gboolean filter_on_thaw :1;/* set when filtering needs to happen upon thawing */
+ gboolean sort_on_thaw :1;/* set when sorting needs to happen upon thawing */
+
+ guint show_hidden :1; /* whether to show hidden files */
+ guint show_folders :1;/* whether to show folders */
+ guint show_files :1; /* whether to show files */
+};
+
#define GTK_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
#define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
#define GTK_FILE_SYSTEM_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
@@ -42,314 +182,352 @@ struct _GtkFileSystemModelClass
/* Signals */
- void (*finished_loading) (GtkFileSystemModel *model);
+ void (*finished_loading) (GtkFileSystemModel *model, GError *error);
};
+static void add_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info);
+static void remove_file (GtkFileSystemModel *model,
+ GFile *file);
-static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
-static void gtk_file_system_model_finalize (GObject *object);
-static void gtk_file_system_model_dispose (GObject *object);
-
-static void drag_source_iface_init (GtkTreeDragSourceIface *iface);
-
-static GtkTreeModelFlags gtk_file_system_model_get_flags (GtkTreeModel *tree_model);
-static gint gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model);
-static GType gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
- gint index);
-static gboolean gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path);
-static GtkTreePath * gtk_file_system_model_get_path (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-static void gtk_file_system_model_get_value (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- gint column,
- GValue *value);
-static gboolean gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-static gboolean gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent);
-static gboolean gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-static gint gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-static gboolean gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n);
-static gboolean gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child);
-static void gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-static void gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
- GtkTreeIter *iter);
-
-static gboolean drag_source_row_draggable (GtkTreeDragSource *drag_source,
- GtkTreePath *path);
-static gboolean drag_source_drag_data_get (GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data);
-
-static FileModelNode *file_model_node_new (GtkFileSystemModel *model,
- GFile *file);
-static void file_model_node_free (FileModelNode *node);
-static void file_model_node_ref (FileModelNode *node);
-static void file_model_node_unref (GtkFileSystemModel *model,
- FileModelNode *node);
-
-static void file_model_node_idle_clear (FileModelNode *node);
-static void file_model_node_idle_clear_cancel (FileModelNode *node);
-static void file_model_node_child_unref (FileModelNode *parent);
-
-static GFileInfo * file_model_node_get_info (GtkFileSystemModel *model,
- FileModelNode *node);
-static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
- FileModelNode *node);
-static void file_model_node_clear (GtkFileSystemModel *model,
- FileModelNode *node);
-static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
- FileModelNode *node);
-
-static void deleted_callback (GFile *folder,
- FileModelNode *node);
-static void files_added_callback (GFile *folder,
- GSList *paths,
- FileModelNode *node);
-static void files_changed_callback (GFile *folder,
- GSList *paths,
- FileModelNode *node);
-static void files_removed_callback (GFile *folder,
- GSList *paths,
- FileModelNode *node);
-
-static void root_deleted_callback (GFile *folder,
- GtkFileSystemModel *model);
-static void root_files_added_callback (GFile *folder,
- GSList *paths,
- GtkFileSystemModel *model);
-static void root_files_changed_callback (GFile *folder,
- GSList *paths,
- GtkFileSystemModel *model);
-static void root_files_removed_callback (GFile *folder,
- GSList *paths,
- GtkFileSystemModel *model);
+/* iter setup:
+ * @user_data: the model
+ * @user_data2: GUINT_TO_POINTER of array index of current entry
+ *
+ * All other fields are unused. Note that the array index does not corrspond
+ * 1:1 with the path index as entries might not be visible.
+ */
+#define ITER_INDEX(iter) GPOINTER_TO_UINT((iter)->user_data2)
+#define ITER_IS_VALID(model, iter) ((model) == (iter)->user_data)
+#define ITER_INIT_FROM_INDEX(model, _iter, _index) G_STMT_START {\
+ g_assert (_index < (model)->files->len); \
+ (_iter)->user_data = (model); \
+ (_iter)->user_data2 = GUINT_TO_POINTER (_index); \
+}G_STMT_END
-/* Signal IDs */
-enum {
- FINISHED_LOADING,
- LAST_SIGNAL
-};
+/*** FileModelNode ***/
-static guint file_system_model_signals[LAST_SIGNAL] = { 0 };
+/* Get a FileModelNode structure given an index in the model->files array of nodes */
+#define get_node(_model, _index) ((FileModelNode *) ((_model)->files->data + (_index) * (_model)->node_size))
-
-
-G_DEFINE_TYPE_WITH_CODE (GtkFileSystemModel, _gtk_file_system_model, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
- gtk_file_system_model_iface_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
- drag_source_iface_init))
+/* Get an index within the model->files array of nodes, given a FileModelNode* */
+#define node_index(_model, _node) (((gchar *) (_node) - (_model)->files->data) / (_model)->node_size)
+/* @up_to_index: smallest model->files array index that will be valid after this call
+ * @up_to_row: smallest node->row that will be valid after this call
+ *
+ * If you want to validate up to an index or up to a row, specify the index or
+ * the row you want and specify G_MAXUINT for the other argument. Pass
+ * G_MAXUINT for both arguments for "validate everything".
+ */
static void
-_gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
+node_validate_rows (GtkFileSystemModel *model, guint up_to_index, guint up_to_row)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ guint i, row;
- gobject_class->finalize = gtk_file_system_model_finalize;
- gobject_class->dispose = gtk_file_system_model_dispose;
+ if (model->files->len == 0)
+ return;
- file_system_model_signals[FINISHED_LOADING] =
- g_signal_new (I_("finished-loading"),
- G_OBJECT_CLASS_TYPE (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkFileSystemModelClass, finished_loading),
- NULL, NULL,
- _gtk_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ up_to_index = MIN (up_to_index, model->files->len - 1);
+
+ i = model->n_nodes_valid;
+ if (i != 0)
+ row = get_node (model, i - 1)->row;
+ else
+ row = 0;
+
+ while (i <= up_to_index && row <= up_to_row)
+ {
+ FileModelNode *node = get_node (model, i);
+ if (node->visible)
+ row++;
+ node->row = row;
+ i++;
+ }
+ model->n_nodes_valid = i;
+}
+
+static guint
+node_get_tree_row (GtkFileSystemModel *model, guint index)
+{
+ if (model->n_nodes_valid <= index)
+ node_validate_rows (model, index, G_MAXUINT);
+
+ return get_node (model, index)->row - 1;
+}
+
+static void
+node_invalidate_index (GtkFileSystemModel *model, guint id)
+{
+ model->n_nodes_valid = MIN (model->n_nodes_valid, id);
+}
+
+static GtkTreePath *
+gtk_tree_path_new_from_node (GtkFileSystemModel *model, guint id)
+{
+ guint i = node_get_tree_row (model, id);
+
+ g_assert (i < model->files->len);
+
+ return gtk_tree_path_new_from_indices (i, -1);
}
static void
-gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
+emit_row_inserted_for_node (GtkFileSystemModel *model, guint id)
{
- iface->get_flags = gtk_file_system_model_get_flags;
- iface->get_n_columns = gtk_file_system_model_get_n_columns;
- iface->get_column_type = gtk_file_system_model_get_column_type;
- iface->get_iter = gtk_file_system_model_get_iter;
- iface->get_path = gtk_file_system_model_get_path;
- iface->get_value = gtk_file_system_model_get_value;
- iface->iter_next = gtk_file_system_model_iter_next;
- iface->iter_children = gtk_file_system_model_iter_children;
- iface->iter_has_child = gtk_file_system_model_iter_has_child;
- iface->iter_n_children = gtk_file_system_model_iter_n_children;
- iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
- iface->iter_parent = gtk_file_system_model_iter_parent;
- iface->ref_node = gtk_file_system_model_ref_node;
- iface->unref_node = gtk_file_system_model_unref_node;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_node (model, id);
+ ITER_INIT_FROM_INDEX (model, &iter, id);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
}
static void
-_gtk_file_system_model_init (GtkFileSystemModel *model)
+emit_row_changed_for_node (GtkFileSystemModel *model, guint id)
{
- model->show_files = TRUE;
- model->show_folders = TRUE;
- model->show_hidden = FALSE;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_node (model, id);
+ ITER_INIT_FROM_INDEX (model, &iter, id);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
}
static void
-gtk_file_system_model_finalize (GObject *object)
+emit_row_deleted_for_row (GtkFileSystemModel *model, guint row)
{
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
- FileModelNode *children, *next;
+ GtkTreePath *path;
- if (model->root_folder)
- g_object_unref (model->root_folder);
+ path = gtk_tree_path_new_from_indices (row, -1);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+}
- if (model->root_file)
- g_object_unref (model->root_file);
+static void
+node_set_visible (GtkFileSystemModel *model, guint id, gboolean visible)
+{
+ FileModelNode *node = get_node (model, id);
- if (model->file_system)
- g_object_unref (model->file_system);
+ if (node->visible == visible ||
+ node->frozen_add)
+ return;
- children = model->roots;
- while (children)
+ if (visible)
{
- next = children->next;
- file_model_node_free (children);
- children = next;
+ node->visible = TRUE;
+ node_invalidate_index (model, id);
+ emit_row_inserted_for_node (model, id);
}
+ else
+ {
+ guint row;
- g_free (model->attributes);
+ row = node_get_tree_row (model, id);
+ g_assert (row < model->files->len);
- G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->finalize (object);
+ node->visible = FALSE;
+ node_invalidate_index (model, id);
+ emit_row_deleted_for_row (model, row);
+ }
}
-
-static void
-gtk_file_system_model_dispose (GObject *object)
+static gboolean
+node_should_be_visible (GtkFileSystemModel *model, guint id)
{
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
+ FileModelNode *node = get_node (model, id);
+ GtkFileFilterInfo filter_info = { 0, };
+ GtkFileFilterFlags required;
+ gboolean is_folder, result;
+ char *mime_type = NULL;
+ char *filename = NULL;
+ char *uri = NULL;
+
+ if (node->info == NULL)
+ return FALSE;
+
+ if (!model->show_hidden &&
+ (g_file_info_get_is_hidden (node->info) || g_file_info_get_is_backup (node->info)))
+ return FALSE;
+
+ is_folder = _gtk_file_info_consider_as_directory (node->info);
+
+ /* wtf? */
+ if (model->show_folders != model->show_files &&
+ model->show_folders != is_folder)
+ return FALSE;
- if (model->pending_cancellables)
+ if (is_folder)
+ return TRUE;
+
+ if (model->filter == NULL)
+ return TRUE;
+
+ /* fill info */
+ required = gtk_file_filter_get_needed (model->filter);
+
+ filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
+ filter_info.display_name = g_file_info_get_display_name (node->info);
+
+ if (required & GTK_FILE_FILTER_MIME_TYPE)
{
- GSList *l;
+ const char *s = g_file_info_get_content_type (node->info);
+ if (s)
+ {
+ mime_type = g_content_type_get_mime_type (s);
+ if (mime_type)
+ {
+ filter_info.mime_type = mime_type;
+ filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
+ }
+ }
+ }
- for (l = model->pending_cancellables; l; l = l->next)
- g_cancellable_cancel (l->data);
- g_slist_free (model->pending_cancellables);
- model->pending_cancellables = NULL;
+ if (required & GTK_FILE_FILTER_FILENAME)
+ {
+ filename = g_file_get_path (node->file);
+ if (filename)
+ {
+ filter_info.filename = filename;
+ filter_info.contains |= GTK_FILE_FILTER_FILENAME;
+ }
}
- G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->dispose (object);
-}
+ if (required & GTK_FILE_FILTER_URI)
+ {
+ uri = g_file_get_uri (node->file);
+ if (uri)
+ {
+ filter_info.uri = uri;
+ filter_info.contains |= GTK_FILE_FILTER_URI;
+ }
+ }
-static void
-drag_source_iface_init (GtkTreeDragSourceIface *iface)
-{
- iface->row_draggable = drag_source_row_draggable;
- iface->drag_data_get = drag_source_drag_data_get;
- iface->drag_data_delete = NULL;
+ result = gtk_file_filter_filter (model->filter, &filter_info);
+
+ g_free (mime_type);
+ g_free (filename);
+ g_free (uri);
+
+ return result;
}
-/*
- * ******************** GtkTreeModel methods ********************
- */
+/*** GtkTreeModel ***/
static GtkTreeModelFlags
gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
{
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
-
- if (model->max_depth == 0)
- flags |= GTK_TREE_MODEL_LIST_ONLY;
-
- return flags;
+ /* GTK_TREE_MODEL_ITERS_PERSIST doesn't work with arrays :( */
+ return GTK_TREE_MODEL_LIST_ONLY;
}
static gint
gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
{
- return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+
+ return model->n_columns;
}
static GType
gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
- gint index)
+ gint i)
{
- switch (index)
- {
- case GTK_FILE_SYSTEM_MODEL_INFO:
- return G_TYPE_FILE_INFO;
- case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
- return G_TYPE_STRING;
- default:
- g_assert_not_reached ();
- return G_TYPE_NONE;
- }
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+
+ g_return_val_if_fail (i >= 0 && (guint) i < model->n_columns, G_TYPE_NONE);
+
+ return model->column_types[i];
}
-static gboolean
-gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreePath *path)
+static int
+compare_indices (gconstpointer key, gconstpointer _node)
{
- GtkTreeIter parent;
- gint *indices;
- gint depth, i;
+ const FileModelNode *node = _node;
+
+ return GPOINTER_TO_UINT (key) - node->row;
+}
- indices = gtk_tree_path_get_indices (path);
- depth = gtk_tree_path_get_depth (path);
+static gboolean
+gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+ char *node;
+ guint id;
+ guint row_to_find;
- g_return_val_if_fail (depth > 0, FALSE);
+ g_return_val_if_fail (n >= 0, FALSE);
- if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
+ if (parent != NULL)
return FALSE;
- for (i = 1; i < depth; i++)
+ row_to_find = n + 1; /* plus one as our node->row numbers are 1-based; see the "Structure" comment at the beginning */
+
+ if (model->n_nodes_valid > 0 &&
+ get_node (model, model->n_nodes_valid - 1)->row >= row_to_find)
+ {
+ /* Fast path - the nodes are valid up to the sought one.
+ *
+ * First, find a node with the sought row number...*/
+
+ node = bsearch (GUINT_TO_POINTER (row_to_find),
+ model->files->data,
+ model->n_nodes_valid,
+ model->node_size,
+ compare_indices);
+ if (node == NULL)
+ return FALSE;
+
+ /* ... Second, back up until we find the first visible node with that row number */
+
+ id = node_index (model, node);
+ while (!get_node (model, id)->visible)
+ id--;
+
+ g_assert (get_node (model, id)->row == row_to_find);
+ }
+ else
{
- parent = *iter;
- if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
- return FALSE;
+ /* Slow path - the nodes need to be validated up to the sought one */
+
+ node_validate_rows (model, G_MAXUINT, n); /* note that this is really "n", not row_to_find - see node_validate_rows() */
+ id = model->n_nodes_valid - 1;
+ if (model->n_nodes_valid == 0 || get_node (model, id)->row != row_to_find)
+ return FALSE;
}
+ ITER_INIT_FROM_INDEX (model, iter, id);
return TRUE;
}
+static gboolean
+gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+ return gtk_file_system_model_iter_nth_child (tree_model,
+ iter,
+ NULL,
+ gtk_tree_path_get_indices (path)[0]);
+}
+
static GtkTreePath *
gtk_file_system_model_get_path (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- FileModelNode *node = iter->user_data;
-
- GtkTreePath *result = gtk_tree_path_new ();
-
- while (node)
- {
- FileModelNode *parent = node->parent;
- FileModelNode *children;
- int n = 0;
-
- if (parent)
- children = parent->children;
- else
- children = model->roots;
-
- while (children != node)
- {
- if (children->is_visible)
- n++;
- children = children->next;
- }
- gtk_tree_path_prepend_index (result, n);
+ g_return_val_if_fail (ITER_IS_VALID (model, iter), NULL);
- node = parent;
- }
-
- return result;
+ return gtk_tree_path_new_from_node (model, ITER_INDEX (iter));
}
static void
@@ -359,51 +537,42 @@ gtk_file_system_model_get_value (GtkTreeModel *tree_model,
GValue *value)
{
GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- FileModelNode *node = iter->user_data;
- GFileInfo *info;
+ const GValue *original;
- switch (column)
- {
- case GTK_FILE_SYSTEM_MODEL_INFO:
- if (model->has_editable && node == model->roots)
- info = NULL;
- else
- info = file_model_node_get_info (model, node);
+ g_return_if_fail ((guint) column < model->n_columns);
+ g_return_if_fail (ITER_IS_VALID (model, iter));
- g_value_set_object (value, info);
- break;
- case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
- {
- g_value_init (value, G_TYPE_STRING);
-
- if (model->has_editable && node == model->roots)
- g_value_set_static_string (value, "");
- else
- {
- GFileInfo *info = file_model_node_get_info (model, node);
-
- g_value_set_string (value, g_file_info_get_display_name (info));
- }
- }
- break;
- default:
- g_assert_not_reached ();
+ original = _gtk_file_system_model_get_value (model, iter, column);
+ if (original)
+ {
+ g_value_init (value, G_VALUE_TYPE (original));
+ g_value_copy (original, value);
}
+ else
+ g_value_init (value, model->column_types[column]);
}
static gboolean
gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
- FileModelNode *node = iter->user_data;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
+ guint i;
- node = node->next;
- while (node && !node->is_visible)
- node = node->next;
-
- iter->user_data = node;
+ g_return_val_if_fail (ITER_IS_VALID (model, iter), FALSE);
+
+ for (i = ITER_INDEX (iter) + 1; i < model->files->len; i++)
+ {
+ FileModelNode *node = get_node (model, i);
- return node != NULL;
+ if (node->visible)
+ {
+ ITER_INIT_FROM_INDEX (model, iter, i);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
static gboolean
@@ -411,41 +580,14 @@ gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- FileModelNode *children;
-
- if (parent)
- {
- FileModelNode *parent_node = parent->user_data;
- children = file_model_node_get_children (model, parent_node);
- }
- else
- {
- children = model->roots;
- }
-
- while (children && !children->is_visible)
- children = children->next;
-
- iter->user_data = children;
-
- return children != NULL;
+ return FALSE;
}
static gboolean
gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
- FileModelNode *node = iter->user_data;
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
-
- if (node->depth == model->max_depth)
- return FALSE;
- else
- {
- GFileInfo *info = file_model_node_get_info (model, node);
- return _gtk_file_info_consider_as_directory (info);
- }
+ return FALSE;
}
static gint
@@ -453,110 +595,305 @@ gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- FileModelNode *children;
- gint n = 0;
if (iter)
+ return 0;
+
+ return node_get_tree_row (model, model->files->len - 1) + 1;
+}
+
+static gboolean
+gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+static void
+gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ /* nothing to do */
+}
+
+static void
+gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ /* nothing to do */
+}
+
+static void
+gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = gtk_file_system_model_get_flags;
+ iface->get_n_columns = gtk_file_system_model_get_n_columns;
+ iface->get_column_type = gtk_file_system_model_get_column_type;
+ iface->get_iter = gtk_file_system_model_get_iter;
+ iface->get_path = gtk_file_system_model_get_path;
+ iface->get_value = gtk_file_system_model_get_value;
+ iface->iter_next = gtk_file_system_model_iter_next;
+ iface->iter_children = gtk_file_system_model_iter_children;
+ iface->iter_has_child = gtk_file_system_model_iter_has_child;
+ iface->iter_n_children = gtk_file_system_model_iter_n_children;
+ iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
+ iface->iter_parent = gtk_file_system_model_iter_parent;
+ iface->ref_node = gtk_file_system_model_ref_node;
+ iface->unref_node = gtk_file_system_model_unref_node;
+}
+
+/*** GtkTreeSortable ***/
+
+typedef struct _SortData SortData;
+struct _SortData {
+ GtkFileSystemModel * model;
+ GtkTreeIterCompareFunc func;
+ gpointer data;
+ int order; /* -1 to invert sort order or 1 to keep it */
+};
+
+/* returns FALSE if no sort necessary */
+static gboolean
+sort_data_init (SortData *data, GtkFileSystemModel *model)
+{
+ GtkTreeDataSortHeader *header;
+
+ if (model->files->len <= 2)
+ return FALSE;
+
+ switch (model->sort_column_id)
{
- FileModelNode *node = iter->user_data;
- children = file_model_node_get_children (model, node);
+ case GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID:
+ if (!model->default_sort_func)
+ return FALSE;
+ data->func = model->default_sort_func;
+ data->data = model->default_sort_data;
+ break;
+ case GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID:
+ return FALSE;
+ default:
+ header = _gtk_tree_data_list_get_header (model->sort_list, model->sort_column_id);
+ if (header == NULL)
+ return FALSE;
+ data->func = header->func;
+ data->data = header->data;
+ break;
}
- else
+
+ data->order = model->sort_order == GTK_SORT_DESCENDING ? -1 : 1;
+ data->model = model;
+ return TRUE;
+}
+
+static int
+compare_array_element (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ SortData *data = user_data;
+ GtkTreeIter itera, iterb;
+
+ ITER_INIT_FROM_INDEX (data->model, &itera, node_index (data->model, a));
+ ITER_INIT_FROM_INDEX (data->model, &iterb, node_index (data->model, b));
+ return data->func (GTK_TREE_MODEL (data->model), &itera, &iterb, data->data) * data->order;
+}
+
+static void
+gtk_file_system_model_sort (GtkFileSystemModel *model)
+{
+ SortData data;
+
+ if (model->frozen)
{
- children = model->roots;
+ model->sort_on_thaw = TRUE;
+ return;
}
- while (children)
+ if (sort_data_init (&data, model))
{
- if (children->is_visible)
- n++;
- children = children->next;
+ GtkTreePath *path;
+ guint i;
+ guint r, n_visible_rows;
+
+ node_validate_rows (model, G_MAXUINT, G_MAXUINT);
+ n_visible_rows = node_get_tree_row (model, model->files->len - 1) + 1;
+ model->n_nodes_valid = 0;
+ g_hash_table_remove_all (model->file_lookup);
+ g_qsort_with_data (get_node (model, 1), /* start at index 1; don't sort the editable row */
+ model->files->len - 1,
+ model->node_size,
+ compare_array_element,
+ &data);
+ g_assert (model->n_nodes_valid == 0);
+ g_assert (g_hash_table_size (model->file_lookup) == 0);
+ if (n_visible_rows)
+ {
+ int *new_order = g_new (int, n_visible_rows);
+
+ r = 0;
+ for (i = 0; i < model->files->len; i++)
+ {
+ FileModelNode *node = get_node (model, i);
+ if (!node->visible)
+ {
+ node->row = r;
+ continue;
+ }
+
+ new_order[r] = node->row;
+ r++;
+ node->row = r;
+ }
+ g_assert (r == n_visible_rows);
+ path = gtk_tree_path_new ();
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
+ path,
+ NULL,
+ new_order);
+ gtk_tree_path_free (path);
+ g_free (new_order);
+ }
}
- return n;
+ model->sort_on_thaw = FALSE;
+}
+
+static void
+gtk_file_system_model_sort_node (GtkFileSystemModel *model, guint node)
+{
+ /* FIXME: improve */
+ gtk_file_system_model_sort (model);
}
static gboolean
-gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *parent,
- gint n)
+gtk_file_system_model_get_sort_column_id (GtkTreeSortable *sortable,
+ gint *sort_column_id,
+ GtkSortType *order)
{
- GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
- FileModelNode *children;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
- if (parent)
- {
- FileModelNode *parent_node = parent->user_data;
- children = file_model_node_get_children (model, parent_node);
- }
- else
- {
- children = model->roots;
- }
+ if (sort_column_id)
+ *sort_column_id = model->sort_column_id;
+ if (order)
+ *order = model->sort_order;
+
+ if (model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID ||
+ model->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
+ return FALSE;
+
+ return TRUE;
+}
- while (children && !children->is_visible)
- children = children->next;
+static void
+gtk_file_system_model_set_sort_column_id (GtkTreeSortable *sortable,
+ gint sort_column_id,
+ GtkSortType order)
+{
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
- while (n && children)
+ if ((model->sort_column_id == sort_column_id) &&
+ (model->sort_order == order))
+ return;
+
+ if (sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
{
- n--;
- children = children->next;
- while (children && !children->is_visible)
- children = children->next;
+ if (sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
+ {
+ GtkTreeDataSortHeader *header = NULL;
+
+ header = _gtk_tree_data_list_get_header (model->sort_list,
+ sort_column_id);
+
+ /* We want to make sure that we have a function */
+ g_return_if_fail (header != NULL);
+ g_return_if_fail (header->func != NULL);
+ }
+ else
+ {
+ g_return_if_fail (model->default_sort_func != NULL);
+ }
}
- iter->user_data = children;
- return children != NULL;
+ model->sort_column_id = sort_column_id;
+ model->sort_order = order;
+
+ gtk_tree_sortable_sort_column_changed (sortable);
+
+ gtk_file_system_model_sort (model);
}
-static gboolean
-gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
- GtkTreeIter *iter,
- GtkTreeIter *child)
+static void
+gtk_file_system_model_set_sort_func (GtkTreeSortable *sortable,
+ gint sort_column_id,
+ GtkTreeIterCompareFunc func,
+ gpointer data,
+ GDestroyNotify destroy)
{
- FileModelNode *node = child->user_data;
-
- node = node->parent;
- iter->user_data = node;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
+
+ model->sort_list = _gtk_tree_data_list_set_header (model->sort_list,
+ sort_column_id,
+ func, data, destroy);
- return node != NULL;
+ if (model->sort_column_id == sort_column_id)
+ gtk_file_system_model_sort (model);
}
static void
-gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
+gtk_file_system_model_set_default_sort_func (GtkTreeSortable *sortable,
+ GtkTreeIterCompareFunc func,
+ gpointer data,
+ GDestroyNotify destroy)
{
- file_model_node_ref (iter->user_data);
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
+
+ if (model->default_sort_destroy)
+ {
+ GDestroyNotify d = model->default_sort_destroy;
+
+ model->default_sort_destroy = NULL;
+ d (model->default_sort_data);
+ }
+
+ model->default_sort_func = func;
+ model->default_sort_data = data;
+ model->default_sort_destroy = destroy;
+
+ if (model->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID)
+ gtk_file_system_model_sort (model);
+}
+
+static gboolean
+gtk_file_system_model_has_default_sort_func (GtkTreeSortable *sortable)
+{
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (sortable);
+
+ return (model->default_sort_func != NULL);
}
static void
-gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
- GtkTreeIter *iter)
+gtk_file_system_model_sortable_init (GtkTreeSortableIface *iface)
{
- file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
- iter->user_data);
+ iface->get_sort_column_id = gtk_file_system_model_get_sort_column_id;
+ iface->set_sort_column_id = gtk_file_system_model_set_sort_column_id;
+ iface->set_sort_func = gtk_file_system_model_set_sort_func;
+ iface->set_default_sort_func = gtk_file_system_model_set_default_sort_func;
+ iface->has_default_sort_func = gtk_file_system_model_has_default_sort_func;
}
+/*** GtkTreeDragSource ***/
+
static gboolean
drag_source_row_draggable (GtkTreeDragSource *drag_source,
GtkTreePath *path)
{
- GtkFileSystemModel *model;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (drag_source);
GtkTreeIter iter;
- FileModelNode *node;
-
- model = GTK_FILE_SYSTEM_MODEL (drag_source);
if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
return FALSE;
- if (!model->has_editable)
- return TRUE;
-
- node = iter.user_data;
- return (node != model->roots);
+ return ITER_INDEX (&iter) != 0;
}
static gboolean
@@ -564,219 +901,498 @@ drag_source_drag_data_get (GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data)
{
- GtkFileSystemModel *model;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (drag_source);
+ FileModelNode *node;
GtkTreeIter iter;
- GFile *file;
char *uris[2];
- model = GTK_FILE_SYSTEM_MODEL (drag_source);
-
if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
return FALSE;
- file = _gtk_file_system_model_get_file (model, &iter);
- g_assert (file != NULL);
+ node = get_node (model, ITER_INDEX (&iter));
+ if (node->file == NULL)
+ return FALSE;
- uris[0] = g_file_get_uri (file);
+ uris[0] = g_file_get_uri (node->file);
uris[1] = NULL;
-
gtk_selection_data_set_uris (selection_data, uris);
-
g_free (uris[0]);
return TRUE;
}
-/* Callback used when the root folder finished loading */
static void
-root_folder_finished_loading_cb (GFile *folder,
- GtkFileSystemModel *model)
+drag_source_iface_init (GtkTreeDragSourceIface *iface)
+{
+ iface->row_draggable = drag_source_row_draggable;
+ iface->drag_data_get = drag_source_drag_data_get;
+ iface->drag_data_delete = NULL;
+}
+
+/*** GtkFileSystemModel ***/
+
+/* Signal IDs */
+enum {
+ FINISHED_LOADING,
+ LAST_SIGNAL
+};
+
+static guint file_system_model_signals[LAST_SIGNAL] = { 0 };
+
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkFileSystemModel, _gtk_file_system_model, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ gtk_file_system_model_iface_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
+ gtk_file_system_model_sortable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
+ drag_source_iface_init))
+
+static void
+gtk_file_system_model_dispose (GObject *object)
{
- g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
+
+ if (model->dir_thaw_source)
+ {
+ g_source_remove (model->dir_thaw_source);
+ model->dir_thaw_source = 0;
+ }
+
+ g_cancellable_cancel (model->cancellable);
+ if (model->dir_monitor)
+ g_file_monitor_cancel (model->dir_monitor);
+
+ G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->dispose (object);
}
+
static void
-got_root_folder_cb (GCancellable *cancellable,
- GtkFolder *folder,
- const GError *error,
- gpointer data)
+gtk_file_system_model_finalize (GObject *object)
{
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
- GtkFileSystemModel *model = data;
- GSList *tmp_list;
+ GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
+ guint i;
- tmp_list = g_slist_find (model->pending_cancellables, cancellable);
- if (!tmp_list)
- goto out;
+ for (i = 0; i < model->files->len; i++)
+ {
+ int v;
- model->pending_cancellables = g_slist_delete_link (model->pending_cancellables,
- tmp_list);
+ FileModelNode *node = get_node (model, i);
+ if (node->file)
+ g_object_unref (node->file);
+ if (node->info)
+ g_object_unref (node->info);
- if (cancelled || !folder)
- goto out;
+ for (v = 0; v < model->n_columns; v++)
+ if (G_VALUE_TYPE (&node->values[v]) != G_TYPE_INVALID)
+ g_value_unset (&node->values[v]);
+ }
+ g_array_free (model->files, TRUE);
- model->root_folder = g_object_ref (folder);
+ g_object_unref (model->cancellable);
+ g_free (model->attributes);
+ if (model->dir)
+ g_object_unref (model->dir);
+ if (model->dir_monitor)
+ g_object_unref (model->dir_monitor);
+ g_hash_table_destroy (model->file_lookup);
+ if (model->filter)
+ g_object_unref (model->filter);
- g_signal_connect_object (model->root_folder, "finished-loading",
- G_CALLBACK (root_folder_finished_loading_cb), model, 0);
- g_signal_connect_object (model->root_folder, "deleted",
- G_CALLBACK (root_deleted_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-added",
- G_CALLBACK (root_files_added_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-changed",
- G_CALLBACK (root_files_changed_callback), model, 0);
- g_signal_connect_object (model->root_folder, "files-removed",
- G_CALLBACK (root_files_removed_callback), model, 0);
+ g_slice_free1 (sizeof (GType) * model->n_columns, model->column_types);
-out:
- g_object_unref (model);
- g_object_unref (cancellable);
+ _gtk_tree_data_list_header_free (model->sort_list);
+ if (model->default_sort_destroy)
+ model->default_sort_destroy (model->default_sort_data);
+
+ G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->finalize (object);
}
-/**
- * _gtk_file_system_model_new:
- * @file_system: an object implementing #GtkFileSystem
- * @root_file: the root file path to show.
- * @max_depth: the maximum depth from the children of @root_file
- * or the roots of the file system to display in
- * the file selector). A depth of 0 displays
- * only the immediate children of @root_file,
- * or the roots of the filesystem. -1 for no
- * maximum depth.
- * @error: location to store error, or %NULL.
- *
- * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
- * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
- * Using the @root_file and @max_depth parameters, the tree model
- * can be restricted to a subportion of the entire file system.
- *
- * Return value: the newly created #GtkFileSystemModel object, or NULL if there
- * was an error.
- **/
-GtkFileSystemModel *
-_gtk_file_system_model_new (GtkFileSystem *file_system,
- GFile *root_file,
- gint max_depth,
- const gchar *attributes,
- GError **error)
+static void
+_gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
{
- GtkFileSystemModel *model;
- GCancellable *cancellable;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
- g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
- g_return_val_if_fail (G_IS_FILE (root_file), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ gobject_class->finalize = gtk_file_system_model_finalize;
+ gobject_class->dispose = gtk_file_system_model_dispose;
- /* Then, actually create the model and the root nodes */
+ file_system_model_signals[FINISHED_LOADING] =
+ g_signal_new (I_("finished-loading"),
+ G_OBJECT_CLASS_TYPE (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkFileSystemModelClass, finished_loading),
+ NULL, NULL,
+ _gtk_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
- model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
- model->file_system = g_object_ref (file_system);
- if (max_depth < 0)
- model->max_depth = G_MAXUSHORT;
- else
- model->max_depth = MIN (max_depth, G_MAXUSHORT);
+static void
+_gtk_file_system_model_init (GtkFileSystemModel *model)
+{
+ model->show_files = TRUE;
+ model->show_folders = TRUE;
+ model->show_hidden = FALSE;
- model->attributes = g_strdup (attributes);
- model->root_folder = NULL;
- model->root_file = g_object_ref (root_file);
+ model->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
- model->roots = NULL;
+ model->file_lookup = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
+ model->cancellable = g_cancellable_new ();
+}
- cancellable = _gtk_file_system_get_folder (file_system, root_file,
- attributes,
- got_root_folder_cb,
- g_object_ref (model));
- if (!cancellable)
- {
- /* In this case got_root_folder_cb() will never be called, so we
- * need to unref model twice.
- */
- g_object_unref (model);
- g_object_unref (model);
+/*** API ***/
- g_set_error_literal (error,
- GTK_FILE_CHOOSER_ERROR,
- GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
- _("Could not obtain root folder"));
+static void
+gtk_file_system_model_closed_enumerator (GObject *object, GAsyncResult *res, gpointer data)
+{
+ g_file_enumerator_close_finish (G_FILE_ENUMERATOR (object), res, NULL);
+}
- return NULL;
+static gboolean
+thaw_func (gpointer data)
+{
+ GtkFileSystemModel *model = data;
+
+ _gtk_file_system_model_thaw_updates (model);
+ model->dir_thaw_source = 0;
+
+ return FALSE;
+}
+
+static void
+gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer data)
+{
+ GFileEnumerator *enumerator = G_FILE_ENUMERATOR (object);
+ GtkFileSystemModel *model = data;
+ GList *walk, *files;
+ GError *error = NULL;
+
+ gdk_threads_enter ();
+
+ files = g_file_enumerator_next_files_finish (enumerator, res, &error);
+
+ if (files)
+ {
+ if (model->dir_thaw_source == 0)
+ {
+ _gtk_file_system_model_freeze_updates (model);
+ model->dir_thaw_source = gdk_threads_add_timeout_full (IO_PRIORITY + 1,
+ 50,
+ thaw_func,
+ model,
+ NULL);
+ }
+
+ for (walk = files; walk; walk = walk->next)
+ {
+ const char *name;
+ GFileInfo *info;
+ GFile *file;
+
+ info = walk->data;
+ name = g_file_info_get_name (info);
+ if (name == NULL)
+ {
+ /* Shouldn't happen, but the APIs allow it */
+ g_object_unref (info);
+ continue;
+ }
+ file = g_file_get_child (model->dir, name);
+ add_file (model, file, info);
+ g_object_unref (file);
+ g_object_unref (info);
+ }
+ g_list_free (files);
+
+ g_file_enumerator_next_files_async (enumerator,
+ g_file_is_native (model->dir) ? 50 * FILES_PER_QUERY : FILES_PER_QUERY,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_files,
+ model);
}
+ else
+ {
+ g_file_enumerator_close_async (enumerator,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_closed_enumerator,
+ model);
+ if (model->dir_thaw_source != 0)
+ {
+ g_source_remove (model->dir_thaw_source);
+ model->dir_thaw_source = 0;
+ _gtk_file_system_model_thaw_updates (model);
+ }
- model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
+ g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, error);
- return model;
+ if (error)
+ g_error_free (error);
+
+ g_object_unref (model);
+ }
+
+ gdk_threads_leave ();
}
static void
-model_refilter_recurse (GtkFileSystemModel *model,
- FileModelNode *parent,
- GtkTreePath *path)
+gtk_file_system_model_query_done (GObject * object,
+ GAsyncResult *res,
+ gpointer data)
{
- GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
- int i = 0;
- FileModelNode *nodes;
- gboolean has_children = FALSE;
+ GtkFileSystemModel *model = data; /* only a valid pointer if not cancelled */
+ GFile *file = G_FILE (object);
+ GFileInfo *info;
- if (parent && !parent->loaded)
+ info = g_file_query_info_finish (file, res, NULL);
+ if (info == NULL)
return;
- if (parent)
- nodes = parent->children;
- else
- nodes = model->roots;
+ _gtk_file_system_model_update_file (model, file, info, TRUE);
+}
- while (nodes)
+static void
+gtk_file_system_model_monitor_change (GFileMonitor * monitor,
+ GFile * file,
+ GFile * other_file,
+ GFileMonitorEvent type,
+ GtkFileSystemModel *model)
+{
+ switch (type)
{
- FileModelNode *next = nodes->next;
- gboolean is_visible;
-
- gtk_tree_path_append_index (path, i);
+ case G_FILE_MONITOR_EVENT_CREATED:
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ /* We can treat all of these the same way */
+ g_file_query_info_async (file,
+ model->attributes,
+ G_FILE_QUERY_INFO_NONE,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_query_done,
+ model);
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ remove_file (model, file);
+ break;
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ /* FIXME: use freeze/thaw with this somehow? */
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ default:
+ /* ignore these */
+ break;
+ }
+}
- is_visible = file_model_node_is_visible (model, nodes);
-
- if (!is_visible && nodes->is_visible)
- {
- file_model_node_clear (model, nodes);
- gtk_tree_model_row_deleted (tree_model, path);
+static void
+gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer data)
+{
+ GtkFileSystemModel *model = data;
+ GFileEnumerator *enumerator;
+ GError *error = NULL;
- nodes->is_visible = FALSE;
- }
- else if (is_visible && !nodes->is_visible)
- {
- GtkTreeIter iter;
+ gdk_threads_enter ();
- iter.user_data = nodes;
- nodes->is_visible = TRUE;
- gtk_tree_model_row_inserted (tree_model, path, &iter);
- }
- else
- model_refilter_recurse (model, nodes, path);
+ enumerator = g_file_enumerate_children_finish (G_FILE (dir), res, &error);
+ if (enumerator == NULL)
+ {
+ g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, error);
+ g_object_unref (model);
+ g_error_free (error);
+ }
+ else
+ {
+ g_file_enumerator_next_files_async (enumerator,
+ g_file_is_native (model->dir) ? 50 * FILES_PER_QUERY : FILES_PER_QUERY,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_files,
+ model);
+ g_object_unref (enumerator);
+ model->dir_monitor = g_file_monitor_directory (model->dir,
+ G_FILE_MONITOR_NONE,
+ model->cancellable,
+ NULL); /* we don't mind if directory monitoring isn't supported, so the GError is NULL here */
+ if (model->dir_monitor)
+ g_signal_connect (model->dir_monitor,
+ "changed",
+ G_CALLBACK (gtk_file_system_model_monitor_change),
+ model);
+ }
+
+ gdk_threads_leave ();
+}
+
+static void
+gtk_file_system_model_set_n_columns (GtkFileSystemModel *model,
+ gint n_columns,
+ va_list args)
+{
+ guint i;
+
+ g_assert (model->files == NULL);
+ g_assert (n_columns > 0);
- if (is_visible)
+ model->n_columns = n_columns;
+ model->column_types = g_slice_alloc (sizeof (GType) * n_columns);
+
+ model->node_size = sizeof (FileModelNode) + sizeof (GValue) * (n_columns - 1); /* minus 1 because FileModelNode.values[] has a default size of 1 */
+
+ for (i = 0; i < (guint) n_columns; i++)
+ {
+ GType type = va_arg (args, GType);
+ if (! _gtk_tree_data_list_check_type (type))
{
- has_children = TRUE;
- i++;
+ g_error ("%s: type %s cannot be a column type for GtkFileSystemModel\n", G_STRLOC, g_type_name (type));
+ return; /* not reached */
}
-
- gtk_tree_path_up (path);
-
- nodes = next;
- }
- if (parent && !has_children)
- {
- /* Fixme - need to insert dummy node here */
+ model->column_types[i] = type;
}
+
+ model->sort_list = _gtk_tree_data_list_header_new (n_columns, model->column_types);
+
+ model->files = g_array_sized_new (FALSE, FALSE, model->node_size, FILES_PER_QUERY);
+ /* add editable node at start */
+ g_array_set_size (model->files, 1);
+ memset (get_node (model, 0), 0, model->node_size);
}
static void
-model_refilter_all (GtkFileSystemModel *model)
+gtk_file_system_model_set_directory (GtkFileSystemModel *model,
+ GFile * dir,
+ const gchar * attributes)
{
- GtkTreePath *path;
+ g_assert (G_IS_FILE (dir));
- path = gtk_tree_path_new ();
- model_refilter_recurse (model, NULL, path);
- gtk_tree_path_free (path);
+ model->dir = g_object_ref (dir);
+ model->attributes = g_strdup (attributes);
+
+ g_object_ref (model);
+ g_file_enumerate_children_async (model->dir,
+ attributes,
+ G_FILE_QUERY_INFO_NONE,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_enumerator,
+ model);
+
+}
+
+static GtkFileSystemModel *
+_gtk_file_system_model_new_valist (GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ va_list args)
+{
+ GtkFileSystemModel *model;
+
+ model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
+ model->get_func = get_func;
+ model->get_data = get_data;
+
+ gtk_file_system_model_set_n_columns (model, n_columns, args);
+
+ return model;
+}
+
+/**
+ * _gtk_file_system_model_new:
+ * @get_func: function to call for getting a value
+ * @get_data: user data argument passed to @get_func
+ * @n_columns: number of columns
+ * @...: @n_columns #GType types for the columns
+ *
+ * Creates a new #GtkFileSystemModel object. You need to add files
+ * to the list using _gtk_file_system_model_add_and_query_file()
+ * or _gtk_file_system_model_update_file().
+ *
+ * Return value: the newly created #GtkFileSystemModel
+ **/
+GtkFileSystemModel *
+_gtk_file_system_model_new (GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...)
+{
+ GtkFileSystemModel *model;
+ va_list args;
+
+ g_return_val_if_fail (get_func != NULL, NULL);
+ g_return_val_if_fail (n_columns > 0, NULL);
+
+ va_start (args, n_columns);
+ model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
+ va_end (args);
+
+ return model;
+}
+
+/**
+ * _gtk_file_system_model_new_for_directory:
+ * @directory: the directory to show.
+ * @attributes: attributes to immediately load or %NULL for all
+ * @get_func: function that the model should call to query data about a file
+ * @get_data: user data to pass to the @get_func
+ * @n_columns: number of columns
+ * @...: @n_columns #GType types for the columns
+ *
+ * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
+ * object wraps the given @directory as a #GtkTreeModel.
+ * The model will query the given directory with the given @attributes
+ * and add all files inside the directory automatically. If supported,
+ * it will also monitor the drectory and update the model's
+ * contents to reflect changes, if the @directory supports monitoring.
+ *
+ * Return value: the newly created #GtkFileSystemModel
+ **/
+GtkFileSystemModel *
+_gtk_file_system_model_new_for_directory (GFile * dir,
+ const gchar * attributes,
+ GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...)
+{
+ GtkFileSystemModel *model;
+ va_list args;
+
+ g_return_val_if_fail (G_IS_FILE (dir), NULL);
+ g_return_val_if_fail (get_func != NULL, NULL);
+ g_return_val_if_fail (n_columns > 0, NULL);
+
+ va_start (args, n_columns);
+ model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
+ va_end (args);
+
+ gtk_file_system_model_set_directory (model, dir, attributes);
+
+ return model;
+}
+
+static void
+gtk_file_system_model_refilter_all (GtkFileSystemModel *model)
+{
+ guint i;
+
+ if (model->frozen)
+ {
+ model->filter_on_thaw = TRUE;
+ return;
+ }
+
+ _gtk_file_system_model_freeze_updates (model);
+
+ /* start at index 1, don't change the editable */
+ for (i = 1; i < model->files->len; i++)
+ {
+ node_set_visible (model, i, node_should_be_visible (model, i));
+ }
+
+ model->filter_on_thaw = FALSE;
+ _gtk_file_system_model_thaw_updates (model);
}
/**
@@ -791,12 +1407,14 @@ void
_gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
gboolean show_hidden)
{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+
show_hidden = show_hidden != FALSE;
if (show_hidden != model->show_hidden)
{
model->show_hidden = show_hidden;
- model_refilter_all (model);
+ gtk_file_system_model_refilter_all (model);
}
}
@@ -812,12 +1430,14 @@ void
_gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
gboolean show_folders)
{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+
show_folders = show_folders != FALSE;
if (show_folders != model->show_folders)
{
model->show_folders = show_folders;
- model_refilter_all (model);
+ gtk_file_system_model_refilter_all (model);
}
}
@@ -834,29 +1454,74 @@ void
_gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
gboolean show_files)
{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+
show_files = show_files != FALSE;
if (show_files != model->show_files)
{
model->show_files = show_files;
- model_refilter_all (model);
+ gtk_file_system_model_refilter_all (model);
}
}
/**
+ * _gtk_file_system_model_get_cancellable:
+ * @model: the model
+ *
+ * Gets the cancellable used by the @model. This is the cancellable used
+ * internally by the @model that will be cancelled when @model is
+ * disposed. So you can use it for operations that should be cancelled
+ * when the model goes away.
+ *
+ * Returns: The cancellable used by @model
+ **/
+GCancellable *
+_gtk_file_system_model_get_cancellable (GtkFileSystemModel *model)
+{
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
+
+ return model->cancellable;
+}
+
+/**
+ * _gtk_file_system_model_iter_is_visible:
+ * @model: the model
+ * @iter: a valid iterator
+ *
+ * Checks if the iterator is visible. A visible iterator references
+ * a row that is currently exposed using the #GtkTreeModel API. If
+ * the iterator is invisible, it references a file that is not shown
+ * for some reason, such as being filtered by the current filter or
+ * being a hidden file.
+ *
+ * Returns: %TRUE if the iterator is visible
+ **/
+gboolean
+_gtk_file_system_model_iter_is_visible (GtkFileSystemModel *model,
+ GtkTreeIter *iter)
+{
+ FileModelNode *node;
+
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ node = get_node (model, ITER_INDEX (iter));
+ return node->visible;
+}
+
+/**
* _gtk_file_system_model_get_info:
* @model: a #GtkFileSystemModel
* @iter: a #GtkTreeIter pointing to a row of @model
*
* Gets the #GFileInfo structure for a particular row
- * of @model. The information included in this structure
- * is determined by the @types parameter to
- * _gtk_file_system_model_new().
+ * of @model.
*
* Return value: a #GFileInfo structure. This structure
* is owned by @model and must not be modified or freed.
- * If you want to save the information for later use,
- * you must make a copy, since the structure may be
+ * If you want to keep the information for later use,
+ * you must take a reference, since the structure may be
* freed on later changes to the file system. If you have
* called _gtk_file_system_model_add_editable() and the @iter
* corresponds to the row that this function returned, the
@@ -868,11 +1533,12 @@ _gtk_file_system_model_get_info (GtkFileSystemModel *model,
{
FileModelNode *node;
- node = iter->user_data;
- if (model->has_editable && node == model->roots)
- return NULL;
- else
- return file_model_node_get_info (model, node);
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ node = get_node (model, ITER_INDEX (iter));
+ g_assert (node->info == NULL || G_IS_FILE_INFO (node->info));
+ return node->info;
}
/**
@@ -880,7 +1546,7 @@ _gtk_file_system_model_get_info (GtkFileSystemModel *model,
* @model: a #GtkFileSystemModel
* @iter: a #GtkTreeIter pointing to a row of @model
*
- * Gets the path for a particular row in @model.
+ * Gets the file for a particular row in @model.
*
* Return value: the file. This object is owned by @model and
* or freed. If you want to save the path for later use,
@@ -891,311 +1557,273 @@ GFile *
_gtk_file_system_model_get_file (GtkFileSystemModel *model,
GtkTreeIter *iter)
{
- FileModelNode *node = iter->user_data;
+ FileModelNode *node;
- if (model->has_editable && node == model->roots)
- return NULL;
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
- if (node->is_dummy)
- return node->parent->file;
- else
- return node->file;
+ node = get_node (model, ITER_INDEX (iter));
+ return node->file;
}
-static void
-unref_node_and_parents (GtkFileSystemModel *model,
- FileModelNode *node)
+/**
+ * _gtk_file_system_model_get_value:
+ * @model: a #GtkFileSystemModel
+ * @iter: a #GtkTreeIter pointing to a row of @model
+ * @column: the column to get the value for
+ *
+ * Gets the value associated with the given row @iter and @column.
+ * If no value is available yet and the default value should be used,
+ * %NULL is returned.
+ * This is a performance optimization for the calls
+ * gtk_tree_model_get() or gtk_tree_model_get_value(), which copy
+ * the value and spend a considerable amount of time in iterator
+ * lookups. Both of which are slow.
+ *
+ * Returns: a pointer to the actual value as stored in @model or %NULL
+ * if no value available yet.
+ **/
+const GValue *
+_gtk_file_system_model_get_value (GtkFileSystemModel *model,
+ GtkTreeIter * iter,
+ int column)
{
- file_model_node_unref (model, node);
- if (node->parent)
- file_model_node_unref (model, node->parent);
+ FileModelNode *node;
+
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), NULL);
+ g_return_val_if_fail (column >= 0 && (guint) column < model->n_columns, NULL);
+
+ node = get_node (model, ITER_INDEX (iter));
+
+ if (!G_VALUE_TYPE (&node->values[column]))
+ {
+ g_value_init (&node->values[column], model->column_types[column]);
+ if (!model->get_func (model,
+ node->file,
+ node->info,
+ column,
+ &node->values[column],
+ model->get_data))
+ {
+ g_value_unset (&node->values[column]);
+ return NULL;
+ }
+ }
+
+ return &node->values[column];
}
-static FileModelNode *
-find_child_node (GtkFileSystemModel *model,
- FileModelNode *parent_node,
- GFile *file)
+static guint
+node_get_for_file (GtkFileSystemModel *model,
+ GFile * file)
{
- FileModelNode *children;
-
- if (parent_node)
- children = file_model_node_get_children (model, parent_node);
- else
- children = model->roots;
+ guint i;
+
+ i = GPOINTER_TO_UINT (g_hash_table_lookup (model->file_lookup, file));
+ if (i != 0)
+ return i;
- while (children)
+ /* Node 0 is the editable row and has no associated file or entry in the table, so we start counting from 1.
+ *
+ * The invariant here is that the files in model->files[n] for n < g_hash_table_size (model->file_lookup)
+ * are already added to the hash table. The table can get cleared when we re-sort; this loop merely rebuilds
+ * our (file -> index) mapping on demand.
+ *
+ * If we exit the loop, the next pending batch of mappings will be resolved when this function gets called again
+ * with another file that is not yet in the mapping.
+ */
+ for (i = g_hash_table_size (model->file_lookup) + 1; i < model->files->len; i++)
{
- if (children->is_visible &&
- children->file &&
- g_file_equal (children->file, file))
- return children;
+ FileModelNode *node = get_node (model, i);
- children = children->next;
+ g_hash_table_insert (model->file_lookup, node->file, GUINT_TO_POINTER (i));
+ if (g_file_equal (node->file, file))
+ return i;
}
- return NULL;
+ return 0;
}
/**
- * _gtk_file_system_model_set_filter:
- * @mode: a #GtkFileSystemModel
- * @filter: function to be called for each file
- * @user_data: data to pass to @filter
- *
- * Sets a callback called for each file/directory to see whether
- * it should be included in model. If this function was made
- * public, we'd want to include a GDestroyNotify as well.
+ * _gtk_file_system_model_get_iter_for_file:
+ * @model: the model
+ * @iter: the iterator to be initialized
+ * @file: the file to look up
+ *
+ * Initializes @iter to point to the row used for @file, if @file is part
+ * of the model. Note that upon successful return, @iter may point to an
+ * invisible row in the @model. Use
+ * _gtk_file_system_model_iter_is_visible() to make sure it is visible to
+ * the tree view.
+ *
+ * Returns: %TRUE if file is part of the model and @iter was initialized
**/
-void
-_gtk_file_system_model_set_filter (GtkFileSystemModel *model,
- GtkFileSystemModelFilter filter,
- gpointer user_data)
+gboolean
+_gtk_file_system_model_get_iter_for_file (GtkFileSystemModel *model,
+ GtkTreeIter *iter,
+ GFile * file)
{
- g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
-
- model->filter_func = filter;
- model->filter_data = user_data;
+ guint i;
- model_refilter_all (model);
-}
+ g_return_val_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ i = node_get_for_file (model, file);
-struct RefPathData
-{
- GtkFileSystemModel *model;
- FileModelNode *node;
- FileModelNode *parent_node;
- GSList *files;
- GSList *cleanups;
- GtkFileSystemModelPathFunc func;
- gpointer user_data;
-};
+ if (i == 0)
+ return FALSE;
-/* FIXME: maybe we have to wait on finished-loading? */
+ ITER_INIT_FROM_INDEX (model, iter, i);
+ return TRUE;
+}
+
+/**
+ * add_file:
+ * @model: the model
+ * @file: the file to add
+ * @info: the information to associate with the file
+ *
+ * Adds the given @file with its associated @info to the @model.
+ * If the model is frozen, the file will only show up after it is thawn.
+ **/
static void
-ref_path_cb (GCancellable *cancellable,
- GtkFolder *folder,
- const GError *error,
- gpointer data)
+add_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info)
{
- struct RefPathData *info = data;
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
-
- if (!g_slist_find (info->model->pending_cancellables, cancellable))
- goto out;
-
- info->model->pending_cancellables = g_slist_remove (info->model->pending_cancellables, cancellable);
-
- /* Note that !folder means that the child node was already
- * found, without using get_folder.
- */
- if (cancelled || error)
- goto out;
-
- if (folder)
- info->cleanups = g_slist_prepend (info->cleanups, folder);
- else if ((info->files != NULL && info->files->next == NULL) /* g_slist_length == 1 */
- && g_file_equal (info->node->file, info->files->data))
- {
- /* Done, now call the function */
- if (info->node)
- {
- GtkTreeIter iter;
- GtkTreePath *path;
-
- iter.user_data = info->node;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
-
- (* info->func) (info->model, path, &iter, info->user_data);
-
- gtk_tree_path_free (path);
- }
-
- goto out;
- }
-
- info->node = find_child_node (info->model, info->parent_node, info->files->data);
- if (info->node)
- file_model_node_ref (info->node);
- else
- {
- goto out;
- }
+ FileModelNode *node;
+
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (G_IS_FILE_INFO (info));
- g_object_unref (info->files->data);
- info->files = g_slist_remove (info->files, info->files->data);
+ node = g_slice_alloc0 (model->node_size);
+ node->file = g_object_ref (file);
+ if (info)
+ node->info = g_object_ref (info);
+ node->frozen_add = model->frozen ? TRUE : FALSE;
- if (info->files == NULL)
- {
- /* Done, now call the function */
- if (info->node)
- {
- GtkTreeIter iter;
- GtkTreePath *path;
+ g_array_append_vals (model->files, node, 1);
+ g_slice_free1 (model->node_size, node);
- iter.user_data = info->node;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
+ if (!model->frozen)
+ node_set_visible (model, model->files->len -1,
+ node_should_be_visible (model, model->files->len - 1));
+ gtk_file_system_model_sort_node (model, model->files->len -1);
+}
- (* info->func) (info->model, path, &iter, info->user_data);
+/**
+ * remove_file:
+ * @model: the model
+ * @file: file to remove from the model. The file must have been
+ * added to the model previously
+ *
+ * Removes the given file from the model. If the file is not part of
+ * @model, this function does nothing.
+ **/
+static void
+remove_file (GtkFileSystemModel *model,
+ GFile *file)
+{
+ FileModelNode *node;
+ guint id;
- gtk_tree_path_free (path);
- }
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
- goto out;
- }
- else
- {
- info->parent_node = info->node;
+ id = node_get_for_file (model, file);
+ if (id == 0)
+ return;
- if (info->parent_node->loaded)
- {
- info->node = find_child_node (info->model, info->parent_node, info->files->data);
- ref_path_cb (NULL, NULL, NULL, info);
- }
- else
- {
- GCancellable *cancellable;
-
- cancellable = _gtk_file_system_get_folder (info->model->file_system,
- info->files->data,
- info->model->attributes,
- ref_path_cb, data);
- info->model->pending_cancellables =
- g_slist_append (info->model->pending_cancellables, cancellable);
- }
+ node = get_node (model, id);
+ node_set_visible (model, id, FALSE);
- return;
- }
+ g_hash_table_remove (model->file_lookup, file);
+ g_object_unref (node->file);
-out:
- if (info->node)
- unref_node_and_parents (info->model, info->node);
- g_slist_foreach (info->files, (GFunc)g_object_unref, NULL);
- g_slist_free (info->files);
- g_slist_foreach (info->cleanups, (GFunc)g_object_unref, NULL);
- g_slist_free (info->cleanups);
- g_object_unref (info->model);
- g_free (info);
+ if (node->info)
+ g_object_unref (node->info);
- g_object_unref (cancellable);
+ g_array_remove_index (model->files, id);
+ /* We don't need to resort, as removing a row doesn't change the sorting order */
}
/**
- * _gtk_file_system_model_path_do:
- * @model: a #GtkFileSystemModel
- * @path: a path pointing to a file in the filesystem
- * for @model.
- * @func: Function to call with the path and iter corresponding
- * to @path.
- * @user_data: data to pass to @func
- *
- * Locates @path within @model, referencing
- * (gtk_tree_model_ref_node()) all parent nodes,
- * calls @func passing in the path and iter for @path,
- * then unrefs all the parent nodes.
+ * _gtk_file_system_model_update_file:
+ * @model: the model
+ * @file: the file
+ * @info: the new file info
+ * @requires_resort: FIXME: get rid of this argument
*
- * The reason for doing this operation as a callback
- * is so that if the operation performed with the
- * path and iter results in referencing the node
- * and/or parent nodes, we don't load all the information
- * about the nodes.
- *
- * This function is particularly useful for expanding
- * a #GtkTreeView to a particular point in the file system.
- */
+ * Tells the file system model that the file changed and that the
+ * new @info should be used for it now. If the file is not part of
+ * @model, it will get added automatically.
+ **/
void
-_gtk_file_system_model_path_do (GtkFileSystemModel *model,
- GFile *file,
- GtkFileSystemModelPathFunc func,
- gpointer user_data)
+_gtk_file_system_model_update_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info,
+ gboolean requires_resort)
{
- GFile *parent_file;
- GSList *files = NULL;
FileModelNode *node;
- struct RefPathData *info;
-
- if (g_file_equal (file, model->root_file))
- return;
+ guint i, id;
+ GFileInfo *old_info;
- parent_file = g_file_get_parent (file);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (G_IS_FILE_INFO (info));
- if (!parent_file)
- return;
+ id = node_get_for_file (model, file);
+ if (id == 0)
+ add_file (model, file, info);
- files = g_slist_prepend (files, g_object_ref (file));
- while (!g_file_equal (parent_file, model->root_file))
- {
- files = g_slist_prepend (files, parent_file);
- parent_file = g_file_get_parent (parent_file);
- if (!parent_file)
- {
- g_slist_foreach (files, (GFunc) g_object_unref, NULL);
- g_slist_free (files);
- return;
- }
- }
- g_object_unref (parent_file);
+ node = get_node (model, id);
- if (files == NULL)
- return;
+ old_info = node->info;
+ node->info = g_object_ref (info);
+ if (old_info)
+ g_object_unref (old_info);
- /* Now we have all paths, except the root path */
- node = find_child_node (model, NULL, files->data);
- if (!node)
+ for (i = 0; i < model->n_columns; i++)
{
- g_slist_foreach (files, (GFunc) g_object_unref, NULL);
- g_slist_free (files);
- return;
+ if (G_VALUE_TYPE (&node->values[i]))
+ g_value_unset (&node->values[i]);
}
- file_model_node_ref (node);
+ if (node->visible)
+ emit_row_changed_for_node (model, id);
- g_object_unref (files->data);
- files = g_slist_remove (files, files->data);
+ if (requires_resort)
+ gtk_file_system_model_sort_node (model, id);
+}
- if (files == NULL)
- {
- /* Done, now call the function */
- if (node)
- {
- GtkTreeIter iter;
- GtkTreePath *path;
+/**
+ * _gtk_file_system_model_set_filter:
+ * @mode: a #GtkFileSystemModel
+ * @filter: %NULL or filter to use
+ *
+ * Sets a filter to be used for deciding if a row should be visible or not.
+ * Directories are always visible.
+ **/
+void
+_gtk_file_system_model_set_filter (GtkFileSystemModel *model,
+ GtkFileFilter * filter)
+{
+ GtkFileFilter *old_filter;
- iter.user_data = node;
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (filter == NULL || GTK_IS_FILE_FILTER (filter));
+
+ if (filter)
+ g_object_ref (filter);
- (* func) (model, path, &iter, user_data);
+ old_filter = model->filter;
+ model->filter = filter;
- gtk_tree_path_free (path);
- unref_node_and_parents (model, node);
- }
- }
- else
- {
- info = g_new0 (struct RefPathData, 1);
- info->files = files;
- info->model = g_object_ref (model);
- info->func = func;
- info->user_data = user_data;
- info->node = node;
-
- if (info->node->loaded)
- {
- info->parent_node = info->node;
- info->node = find_child_node (model, info->parent_node, info->files->data);
- ref_path_cb (NULL, NULL, NULL, info);
- }
- else
- {
- GCancellable *cancellable;
+ if (old_filter)
+ g_object_unref (old_filter);
- cancellable = _gtk_file_system_get_folder (model->file_system,
- files->data,
- model->attributes,
- ref_path_cb, info);
- model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
- }
- }
+ gtk_file_system_model_refilter_all (model);
}
/**
@@ -1211,26 +1839,11 @@ _gtk_file_system_model_path_do (GtkFileSystemModel *model,
void
_gtk_file_system_model_add_editable (GtkFileSystemModel *model, GtkTreeIter *iter)
{
- FileModelNode *node;
- GtkTreePath *path;
-
- g_return_if_fail (!model->has_editable);
-
- model->has_editable = TRUE;
-
- node = file_model_node_new (model, NULL);
- node->is_visible = TRUE;
-
- node->next = model->roots;
- model->roots = node;
-
- path = gtk_tree_path_new ();
- gtk_tree_path_append_index (path, 0);
- iter->user_data = node;
-
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (!get_node (model, 0)->visible);
- gtk_tree_path_free (path);
+ node_set_visible (model, 0, TRUE);
+ ITER_INIT_FROM_INDEX (model, iter, 0);
}
/**
@@ -1244,735 +1857,148 @@ _gtk_file_system_model_add_editable (GtkFileSystemModel *model, GtkTreeIter *ite
void
_gtk_file_system_model_remove_editable (GtkFileSystemModel *model)
{
- GtkTreePath *path;
- FileModelNode *node;
-
- g_return_if_fail (model->has_editable);
-
- model->has_editable = FALSE;
-
- node = model->roots;
- model->roots = model->roots->next;
- file_model_node_free (node);
-
- path = gtk_tree_path_new ();
- gtk_tree_path_append_index (path, 0);
-
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
-
- gtk_tree_path_free (path);
-}
-
-static FileModelNode *
-file_model_node_new (GtkFileSystemModel *model,
- GFile *file)
-{
- FileModelNode *node = g_new0 (FileModelNode, 1);
-
- node->model = model;
- node->file = file ? g_object_ref (file) : NULL;
-
- return node;
-}
-
-static void
-file_model_node_free (FileModelNode *node)
-{
- file_model_node_clear (node->model, node);
-
- if (node->file)
- g_object_unref (node->file);
-
- if (node->info)
- g_object_unref (node->info);
-
- g_free (node);
-}
-
-static GFileInfo *
-file_model_node_get_info (GtkFileSystemModel *model,
- FileModelNode *node)
-{
- if (!node->info)
- {
- if (node->is_dummy)
- {
- node->info = g_file_info_new ();
- g_file_info_set_display_name (node->info, _("(Empty)"));
- }
- else if (node->parent || model->root_folder)
- {
- node->info = _gtk_folder_get_info ((node->parent != NULL) ? node->parent->folder : model->root_folder,
- node->file);
- }
- else
- g_assert_not_reached ();
- }
-
- return node->info;
-}
-
-static gboolean
-file_model_node_is_visible (GtkFileSystemModel *model,
- FileModelNode *node)
-{
- if (model->show_folders != model->show_files ||
- !model->show_hidden ||
- model->filter_func)
- {
- GFileInfo *info = file_model_node_get_info (model, node);
- gboolean is_folder;
-
- if (!info)
- {
- /* File probably disappeared underneath us or resides in a
- directory where we have only partial access rights. */
- return FALSE;
- }
-
- is_folder = _gtk_file_info_consider_as_directory (info);
-
- if (model->show_folders != model->show_files &&
- model->show_folders != is_folder)
- return FALSE;
-
- if (!model->show_hidden &&
- (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)))
- return FALSE;
-
- if (model->filter_func &&
- !model->filter_func (model, node->file, info, model->filter_data))
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void
-file_model_node_clear (GtkFileSystemModel *model,
- FileModelNode *node)
-{
- FileModelNode *children;
-
- file_model_node_idle_clear_cancel (node);
-
- children = node->children;
- node->children = NULL;
- node->loaded = FALSE;
-
- while (children)
- {
- FileModelNode *next = children->next;
-
- file_model_node_free (children);
-
- children = next;
- }
-
- if (node->folder)
- {
- /* Unreffing node->folder may cause roots_changed,
- * so we need to be careful about ordering.
- */
- GtkFolder *folder = node->folder;
- node->folder = NULL;
-
- g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (deleted_callback), node);
- g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_added_callback), node);
- g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_changed_callback), node);
- g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_removed_callback), node);
-
- g_object_unref (folder);
- }
-}
-
-static void
-file_model_node_ref (FileModelNode *node)
-{
- node->ref_count++;
- if (node->ref_count == 1 && node->parent)
- node->parent->n_referenced_children++;
-}
-
-static gboolean
-idle_clear_callback (GtkFileSystemModel *model)
-{
- while (model->idle_clears)
- {
- FileModelNode *node = model->idle_clears->data;
- model->idle_clears = g_slist_delete_link (model->idle_clears, model->idle_clears);
-
- node->idle_clear = FALSE;
- file_model_node_clear (node->model, node);
- }
-
- return FALSE;
-}
-
-static void
-file_model_node_idle_clear (FileModelNode *node)
-{
- if (!node->idle_clear)
- {
- GtkFileSystemModel *model = node->model;
-
- node->idle_clear = TRUE;
- if (!model->idle_clears)
- {
- model->idle_clear_source = g_idle_source_new ();
- g_source_set_priority (model->idle_clear_source, G_PRIORITY_HIGH);
- g_source_set_closure (model->idle_clear_source,
- g_cclosure_new_object (G_CALLBACK (idle_clear_callback),
- G_OBJECT (model)));
- g_source_attach (model->idle_clear_source, NULL);
- }
-
- model->idle_clears = g_slist_prepend (model->idle_clears, node);
- node->idle_clear = TRUE;
- }
-}
-
-static void
-file_model_node_idle_clear_cancel (FileModelNode *node)
-{
- if (node->idle_clear)
- {
- GtkFileSystemModel *model = node->model;
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (get_node (model, 0)->visible);
- model->idle_clears = g_slist_remove (model->idle_clears, node);
- if (!model->idle_clears)
- {
- g_source_destroy (model->idle_clear_source);
- model->idle_clear_source = NULL;
- }
-
- node->idle_clear = FALSE;
- }
+ node_set_visible (model, 0, FALSE);
}
-static void
-file_model_node_unref (GtkFileSystemModel *model,
- FileModelNode *node)
+/**
+ * _gtk_file_system_model_freeze_updates:
+ * @model: a #GtkFileSystemModel
+ *
+ * Freezes most updates on the model, so that performing multiple
+ * operations on the files in the model do not cause any events.
+ * Use _gtk_file_system_model_thaw_updates() to resume proper
+ * operations. It is fine to call this function multiple times as
+ * long as freeze and thaw calls are balanced.
+ **/
+void
+_gtk_file_system_model_freeze_updates (GtkFileSystemModel *model)
{
- node->ref_count--;
- if (node->ref_count == 0)
- {
- file_model_node_clear (model, node);
- if (node->parent)
- file_model_node_child_unref (node->parent);
- }
-}
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
-static void
-file_model_node_child_unref (FileModelNode *parent)
-{
- parent->n_referenced_children--;
- if (parent->n_referenced_children == 0)
- file_model_node_idle_clear (parent);
+ model->frozen++;
}
-struct GetChildrenData
-{
- GtkFileSystemModel *model;
- FileModelNode *node;
-};
-
-static void
-get_children_get_folder_cb (GCancellable *cancellable,
- GtkFolder *folder,
- const GError *error,
- gpointer callback_data)
+/**
+ * _gtk_file_system_model_thaw_updates:
+ * @model: a #GtkFileSystemModel
+ *
+ * Undoes the effect of a previous call to
+ * _gtk_file_system_model_freeze_updates()
+ **/
+void
+_gtk_file_system_model_thaw_updates (GtkFileSystemModel *model)
{
- gboolean cancelled = g_cancellable_is_cancelled (cancellable);
- struct GetChildrenData *data = callback_data;
- FileModelNode *child_node;
- GSList *tmp_list;
-
- tmp_list = g_slist_find (data->model->pending_cancellables, cancellable);
-
- if (!tmp_list)
- goto out;
-
- data->model->pending_cancellables = g_slist_delete_link (data->model->pending_cancellables, tmp_list);
-
- if (cancelled || !folder)
- {
- /* error, no folder, remove dummy child */
- if (data->node->parent && data->node->parent->has_dummy)
- {
- data->node->parent->children = NULL;
- data->node->parent->has_dummy = FALSE;
- }
-
- file_model_node_free (data->node);
-
- goto out;
- }
-
- data->node->folder = folder;
- data->node->load_pending = FALSE;
-
- g_signal_connect (data->node->folder, "deleted",
- G_CALLBACK (deleted_callback), data->node);
- g_signal_connect (data->node->folder, "files-added",
- G_CALLBACK (files_added_callback), data->node);
- g_signal_connect (data->node->folder, "files-changed",
- G_CALLBACK (files_changed_callback), data->node);
- g_signal_connect (data->node->folder, "files-removed",
- G_CALLBACK (files_removed_callback), data->node);
-
- data->node->loaded = TRUE;
+ gboolean stuff_added;
- /* We claimed this folder had children, so we
- * have to add a dummy child, possibly to remove later.
- */
- child_node = file_model_node_new (data->model, NULL);
- child_node->is_visible = TRUE;
- child_node->parent = data->node;
- child_node->is_dummy = TRUE;
-
- data->node->children = child_node;
- data->node->has_dummy = TRUE;
-
- g_object_set_data (G_OBJECT (data->node->folder), I_("model-node"), data->node);
-
-out:
- g_object_unref (data->model);
- g_free (data);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (model->frozen > 0);
- g_object_unref (cancellable);
-}
+ model->frozen--;
+ if (model->frozen > 0)
+ return;
-static FileModelNode *
-file_model_node_get_children (GtkFileSystemModel *model,
- FileModelNode *node)
-{
- if (node->ref_count == 0)
- return NULL;
+ stuff_added = get_node (model, model->files->len - 1)->frozen_add;
- if (!node->loaded && !node->load_pending)
+ if (model->filter_on_thaw)
+ gtk_file_system_model_refilter_all (model);
+ if (model->sort_on_thaw)
+ gtk_file_system_model_sort (model);
+ if (stuff_added)
{
- GFileInfo *info = file_model_node_get_info (model, node);
- gboolean has_children = FALSE;
- gboolean is_folder = _gtk_file_info_consider_as_directory (info);
-
- file_model_node_idle_clear_cancel (node);
+ guint i;
- if (node->depth < model->max_depth && is_folder)
+ for (i = 0; i < model->files->len; i++)
{
- struct GetChildrenData *data;
- GCancellable *cancellable;
-
- data = g_new (struct GetChildrenData, 1);
- data->model = g_object_ref (model);
- data->node = node;
-
- cancellable =
- _gtk_file_system_get_folder (model->file_system,
- node->file,
- model->attributes,
- get_children_get_folder_cb,
- data);
-
- model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
- node->load_pending = TRUE;
-
- if (!has_children)
- {
- /* The hard case ... we claimed this folder had children, but actually
- * it didn't. We have to add a dummy child, possibly to remove later.
- */
- FileModelNode *child_node = file_model_node_new (model, NULL);
- child_node->is_visible = TRUE;
- child_node->parent = node;
- child_node->is_dummy = TRUE;
-
- node->children = child_node;
- node->has_dummy = TRUE;
- }
- }
- }
-
- return node->children;
-}
-
-static gint
-file_compare_func (GFile *file1,
- GFile *file2)
-{
- gchar *uri1, *uri2;
- gint result;
-
- uri1 = g_file_get_uri (file1);
- uri2 = g_file_get_uri (file2);
-
- result = g_strcmp0 (uri1, uri2);
-
- g_free (uri1);
- g_free (uri2);
-
- return result;
-}
-
-static GSList *
-sort_file_list (GSList *list)
-{
- GSList *copy;
-
- copy = g_slist_copy (list);
- return g_slist_sort (copy, (GCompareFunc) file_compare_func);
-}
-
-static void
-do_files_added (GtkFileSystemModel *model,
- FileModelNode *parent_node,
- GSList *files)
-{
- GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
- FileModelNode *children;
- FileModelNode *prev = NULL;
- GtkTreeIter iter;
- GtkTreePath *path;
- GSList *sorted_files, *tmp_list;
-
- sorted_files = sort_file_list (files);
-
- if (parent_node)
- {
- iter.user_data = parent_node;
- path = gtk_tree_model_get_path (tree_model, &iter);
- children = parent_node->children;
- }
- else
- {
- path = gtk_tree_path_new ();
- children = model->roots;
- }
-
- gtk_tree_path_down (path);
-
- if (parent_node && parent_node->has_dummy)
- {
- prev = children;
- children = children->next;
- gtk_tree_path_next (path);
- }
-
- for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
- {
- GFile *file = tmp_list->data;
-
- while (children &&
- (!children->file || !g_file_equal (children->file, file)))
- {
- prev = children;
- if (children->is_visible)
- gtk_tree_path_next (path);
-
- children = children->next;
- }
-
- if (children &&
- children->file && g_file_equal (children->file, file))
- {
- /* Shouldn't happen */
- }
- else
- {
- FileModelNode *new;
-
- new = file_model_node_new (model, file);
-
- if (children)
- new->next = children;
- if (prev)
- prev->next = new;
- else if (parent_node)
- parent_node->children = new;
- else
- model->roots = new;
-
- prev = new;
-
- if (parent_node)
- {
- new->parent = parent_node;
- new->depth = parent_node->depth + 1;
- }
-
- new->is_visible = file_model_node_is_visible (model, new);
-
- if (new->is_visible)
- {
- iter.user_data = new;
- gtk_tree_path_free (path);
- path = gtk_tree_model_get_path (tree_model, &iter);
- gtk_tree_model_row_inserted (tree_model, path, &iter);
-
- if (gtk_file_system_model_iter_has_child (tree_model, &iter))
- gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
-
- if (parent_node && parent_node->has_dummy)
- {
- FileModelNode *dummy = parent_node->children;
- GtkTreePath *dummy_path;
-
- parent_node->children = parent_node->children->next;
- parent_node->has_dummy = FALSE;
-
- dummy_path = gtk_tree_path_copy (path);
- gtk_tree_path_up (dummy_path);
- gtk_tree_path_down (dummy_path);
-
- gtk_tree_model_row_deleted (tree_model, dummy_path);
- gtk_tree_path_free (dummy_path);
-
- if (dummy->ref_count)
- file_model_node_child_unref (parent_node);
- file_model_node_free (dummy);
- }
-
- gtk_tree_path_next (path);
- }
- }
- }
-
- gtk_tree_path_free (path);
- g_slist_free (sorted_files);
-}
-
-static void
-do_files_changed (GtkFileSystemModel *model,
- FileModelNode *parent_node,
- GSList *files)
-{
- GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
- FileModelNode *children;
- GtkTreeIter iter;
- GtkTreePath *path;
- GSList *sorted_files;
- GSList *tmp_list;
-
- sorted_files = sort_file_list (files);
-
- if (parent_node)
- {
- iter.user_data = parent_node;
- path = gtk_tree_model_get_path (tree_model, &iter);
- children = parent_node->children;
- }
- else
- {
- path = gtk_tree_path_new ();
- children = model->roots;
- }
-
- gtk_tree_path_down (path);
-
- if (parent_node && parent_node->has_dummy)
- {
- children = children->next;
- gtk_tree_path_next (path);
- }
+ FileModelNode *node = get_node (model, i);
- for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
- {
- GFile *file = tmp_list->data;
-
- while (children &&
- (!children->file || !g_file_equal (children->file, file)))
- {
- if (children->is_visible)
- gtk_tree_path_next (path);
-
- children = children->next;
- }
-
- if (children &&
- children->file && g_file_equal (children->file, file))
- {
- gtk_tree_model_row_changed (tree_model, path, &iter);
- }
- else
- {
- /* Shouldn't happen */
- }
+ if (!node->frozen_add)
+ continue;
+ node->frozen_add = FALSE;
+ node_set_visible (model, i, node_should_be_visible (model, i));
+ }
}
-
- gtk_tree_path_free (path);
- g_slist_free (sorted_files);
}
-static void
-do_files_removed (GtkFileSystemModel *model,
- FileModelNode *parent_node,
- GSList *files)
+/**
+ * _gtk_file_system_model_clear_cache:
+ * @model: a #GtkFileSystemModel
+ * @column: the column to clear or -1 for all columns
+ *
+ * Clears the cached values in the model for the given @column. Use
+ * this function whenever your get_value function would return different
+ * values for a column.
+ * The file chooser uses this for example when the icon theme changes to
+ * invalidate the cached pixbufs.
+ **/
+void
+_gtk_file_system_model_clear_cache (GtkFileSystemModel *model,
+ int column)
{
- GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
- FileModelNode *children;
- FileModelNode *prev = NULL;
- GtkTreeIter iter;
- GtkTreePath *path;
- GSList *sorted_files;
- GSList *tmp_list;
- FileModelNode *tmp_child;
- gint n_visible;
+ guint i;
+ int start, end;
+ gboolean changed;
- sorted_files = sort_file_list (files);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (column >= -1 && (guint) column < model->n_columns);
- if (parent_node)
+ if (column > -1)
{
- iter.user_data = parent_node;
- path = gtk_tree_model_get_path (tree_model, &iter);
- children = parent_node->children;
+ start = column;
+ end = column + 1;
}
else
{
- path = gtk_tree_path_new ();
- children = model->roots;
+ start = 0;
+ end = model->n_columns;
}
- /* Count the number of currently visible children, so that
- * can catch when we need to insert a dummy node.
- */
- n_visible = 0;
- for (tmp_child = children; tmp_child; tmp_child = tmp_child->next)
+ for (i = 0; i < model->files->len; i++)
{
- if (tmp_child->is_visible)
- n_visible++;
- }
-
- gtk_tree_path_down (path);
-
- if (parent_node && parent_node->has_dummy)
- {
- prev = children;
- children = children->next;
- gtk_tree_path_next (path);
- }
-
- for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
- {
- GFile *file = tmp_list->data;
-
- while (children &&
- (!children->file || !g_file_equal (children->file, file)))
- {
- prev = children;
- if (children->is_visible)
- gtk_tree_path_next (path);
-
- children = children->next;
- }
-
- if (children &&
- children->file && g_file_equal (children->file, file))
- {
- FileModelNode *next = children->next;
-
- if (children->is_visible)
- n_visible--;
-
- if (parent_node && n_visible == 0)
- {
- FileModelNode *dummy = file_model_node_new (model, NULL);
- dummy->is_visible = TRUE;
- dummy->parent = parent_node;
- dummy->is_dummy = TRUE;
-
- parent_node->children = dummy;
- parent_node->has_dummy = TRUE;
-
- iter.user_data = dummy;
- gtk_tree_model_row_inserted (tree_model, path, &iter);
- gtk_tree_path_next (path);
+ FileModelNode *node = get_node (model, i);
+ changed = FALSE;
+ for (column = start; column < end; column++)
+ {
+ if (!G_VALUE_TYPE (&node->values[column]))
+ continue;
+
+ g_value_unset (&node->values[column]);
+ changed = TRUE;
+ }
- prev = dummy;
- }
-
- if (prev)
- prev->next = next;
- else if (parent_node)
- parent_node->children = next;
- else
- model->roots = next;
-
- if (parent_node && children->ref_count)
- file_model_node_child_unref (parent_node);
-
- if (children->is_visible)
- gtk_tree_model_row_deleted (tree_model, path);
-
- file_model_node_free (children);
-
- children = next;
- }
- else
- {
- /* Shouldn't happen */
- }
+ if (changed && node->visible)
+ emit_row_changed_for_node (model, i);
}
- gtk_tree_path_free (path);
- g_slist_free (sorted_files);
-}
-
-static void
-deleted_callback (GFile *folder,
- FileModelNode *node)
-{
+ /* FIXME: resort? */
}
-static void
-files_added_callback (GFile *folder,
- GSList *files,
- FileModelNode *node)
-{
- do_files_added (node->model, node, files);
-}
-
-static void
-files_changed_callback (GFile *folder,
- GSList *files,
- FileModelNode *node)
-{
- do_files_changed (node->model, node, files);
-}
-
-static void
-files_removed_callback (GFile *folder,
- GSList *files,
- FileModelNode *node)
-{
- do_files_removed (node->model, node, files);
-}
-
-static void
-root_deleted_callback (GFile *folder,
- GtkFileSystemModel *model)
-{
-}
-
-static void
-root_files_added_callback (GFile *folder,
- GSList *files,
- GtkFileSystemModel *model)
-{
- do_files_added (model, NULL, files);
-}
-
-static void
-root_files_changed_callback (GFile *folder,
- GSList *files,
- GtkFileSystemModel *model)
-{
- do_files_changed (model, NULL, files);
-}
-
-static void
-root_files_removed_callback (GFile *folder,
- GSList *files,
- GtkFileSystemModel *model)
+/**
+ * _gtk_file_system_model_add_and_query_file:
+ * @model: a #GtkFileSystemModel
+ * @file: the file to add
+ * @attributes: attributes to query before adding the file
+ *
+ * This is a conenience function that calls g_file_query_info_async() on
+ * the given file, and when successful, adds it to the model.
+ * Upon failure, the @file is discarded.
+ **/
+void
+_gtk_file_system_model_add_and_query_file (GtkFileSystemModel *model,
+ GFile * file,
+ const char * attributes)
{
- do_files_removed (model, NULL, files);
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (attributes != NULL);
+
+ g_file_query_info_async (file,
+ attributes,
+ G_FILE_QUERY_INFO_NONE,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_query_done,
+ model);
}
diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h
index 750fa33663..a6fbab936f 100644
--- a/gtk/gtkfilesystemmodel.h
+++ b/gtk/gtkfilesystemmodel.h
@@ -21,7 +21,8 @@
#ifndef __GTK_FILE_SYSTEM_MODEL_H__
#define __GTK_FILE_SYSTEM_MODEL_H__
-#include "gtkfilesystem.h"
+#include <gio/gio.h>
+#include <gtk/gtkfilefilter.h>
#include <gtk/gtktreemodel.h>
G_BEGIN_DECLS
@@ -34,46 +35,58 @@ typedef struct _GtkFileSystemModel GtkFileSystemModel;
GType _gtk_file_system_model_get_type (void) G_GNUC_CONST;
-typedef enum {
- GTK_FILE_SYSTEM_MODEL_INFO,
- GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME,
- GTK_FILE_SYSTEM_MODEL_N_COLUMNS
-} GtkFileSystemModelColumns;
+typedef gboolean (*GtkFileSystemModelGetValue) (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info,
+ int column,
+ GValue *value,
+ gpointer user_data);
-GtkFileSystemModel *_gtk_file_system_model_new (GtkFileSystem *file_system,
- GFile *root_file,
- gint max_depth,
- const gchar *attributes,
- GError **error);
+GtkFileSystemModel *_gtk_file_system_model_new (GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...);
+GtkFileSystemModel *_gtk_file_system_model_new_for_directory(GFile * dir,
+ const gchar * attributes,
+ GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...);
+GCancellable * _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model);
+gboolean _gtk_file_system_model_iter_is_visible (GtkFileSystemModel *model,
+ GtkTreeIter *iter);
GFileInfo * _gtk_file_system_model_get_info (GtkFileSystemModel *model,
GtkTreeIter *iter);
+gboolean _gtk_file_system_model_get_iter_for_file(GtkFileSystemModel *model,
+ GtkTreeIter *iter,
+ GFile *file);
GFile * _gtk_file_system_model_get_file (GtkFileSystemModel *model,
GtkTreeIter *iter);
+const GValue * _gtk_file_system_model_get_value (GtkFileSystemModel *model,
+ GtkTreeIter * iter,
+ int column);
+
+void _gtk_file_system_model_add_and_query_file (GtkFileSystemModel *model,
+ GFile *file,
+ const char *attributes);
+void _gtk_file_system_model_update_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info,
+ gboolean requires_resort);
+
void _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
gboolean show_hidden);
void _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
gboolean show_folders);
void _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
gboolean show_files);
+void _gtk_file_system_model_freeze_updates (GtkFileSystemModel *model);
+void _gtk_file_system_model_thaw_updates (GtkFileSystemModel *model);
+void _gtk_file_system_model_clear_cache (GtkFileSystemModel *model,
+ int column);
-typedef gboolean (*GtkFileSystemModelFilter) (GtkFileSystemModel *model,
- GFile *file,
- GFileInfo *info,
- gpointer user_data);
-
-void _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
- GtkFileSystemModelFilter filter,
- gpointer user_data);
-
-typedef void (*GtkFileSystemModelPathFunc) (GtkFileSystemModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer user_data);
-
-void _gtk_file_system_model_path_do (GtkFileSystemModel *model,
- GFile *file,
- GtkFileSystemModelPathFunc func,
- gpointer user_data);
+void _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
+ GtkFileFilter *filter);
void _gtk_file_system_model_add_editable (GtkFileSystemModel *model,
GtkTreeIter *iter);
diff --git a/gtk/gtkgamma.c b/gtk/gtkgamma.c
index fd03f857ef..5485dede0f 100644
--- a/gtk/gtkgamma.c
+++ b/gtk/gtkgamma.c
@@ -24,6 +24,8 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+#undef GTK_DISABLE_DEPRECATED
+
#include "config.h"
#include <string.h>
#include <stdlib.h>
diff --git a/gtk/gtkgamma.h b/gtk/gtkgamma.h
index bde3d88df4..0173f960ac 100644
--- a/gtk/gtkgamma.h
+++ b/gtk/gtkgamma.h
@@ -24,19 +24,7 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-/*
- * NOTE this widget is considered too specialized/little-used for
- * GTK+, and will in the future be moved to some other package. If
- * your application needs this widget, feel free to use it, as the
- * widget does work and is useful in some applications; it's just not
- * of general interest. However, we are not accepting new features for
- * the widget, and it will eventually move out of the GTK+
- * distribution.
- */
-
-#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
+#ifndef GTK_DISABLE_DEPRECATED
#ifndef __GTK_GAMMA_CURVE_H__
#define __GTK_GAMMA_CURVE_H__
@@ -90,3 +78,5 @@ GtkWidget* gtk_gamma_curve_new (void);
G_END_DECLS
#endif /* __GTK_GAMMA_CURVE_H__ */
+
+#endif /* GTK_DISABLE_DEPRECATED */
diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
index cced1108e5..145d935e8e 100644
--- a/gtk/gtkiconfactory.c
+++ b/gtk/gtkiconfactory.c
@@ -21,7 +21,7 @@
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
@@ -54,7 +54,7 @@ typedef enum {
struct _GtkIconSource
{
GtkIconSourceType type;
-
+
union {
gchar *icon_name;
gchar *filename;
@@ -126,7 +126,7 @@ static void
gtk_icon_factory_class_init (GtkIconFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
+
object_class->finalize = gtk_icon_factory_finalize;
}
@@ -150,11 +150,11 @@ gtk_icon_factory_finalize (GObject *object)
GtkIconFactory *factory = GTK_ICON_FACTORY (object);
all_icon_factories = g_slist_remove (all_icon_factories, factory);
-
+
g_hash_table_foreach (factory->icons, free_icon_set, NULL);
-
+
g_hash_table_destroy (factory->icons);
-
+
G_OBJECT_CLASS (gtk_icon_factory_parent_class)->finalize (object);
}
@@ -174,9 +174,9 @@ gtk_icon_factory_finalize (GObject *object)
* gtk_icon_factory_remove_default(). Applications with icons should
* add a default icon factory with their icons, which will allow
* themes to override the icons for the application.
- *
+ *
* Return value: a new #GtkIconFactory
- **/
+ */
GtkIconFactory*
gtk_icon_factory_new (void)
{
@@ -199,8 +199,7 @@ gtk_icon_factory_new (void)
* override your application's default icons. If an icon already
* existed in @factory for @stock_id, it is unreferenced and replaced
* with the new @icon_set.
- *
- **/
+ */
void
gtk_icon_factory_add (GtkIconFactory *factory,
const gchar *stock_id,
@@ -211,14 +210,14 @@ gtk_icon_factory_add (GtkIconFactory *factory,
g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
g_return_if_fail (stock_id != NULL);
- g_return_if_fail (icon_set != NULL);
+ g_return_if_fail (icon_set != NULL);
g_hash_table_lookup_extended (factory->icons, stock_id,
&old_key, &old_value);
if (old_value == icon_set)
return;
-
+
gtk_icon_set_ref (icon_set);
/* GHashTable key memory management is so fantastically broken. */
@@ -235,22 +234,22 @@ gtk_icon_factory_add (GtkIconFactory *factory,
* gtk_icon_factory_lookup:
* @factory: a #GtkIconFactory
* @stock_id: an icon name
- *
+ *
* Looks up @stock_id in the icon factory, returning an icon set
* if found, otherwise %NULL. For display to the user, you should
* use gtk_style_lookup_icon_set() on the #GtkStyle for the
* widget that will display the icon, instead of using this
* function directly, so that themes are taken into account.
- *
+ *
* Return value: icon set of @stock_id.
- **/
+ */
GtkIconSet *
gtk_icon_factory_lookup (GtkIconFactory *factory,
const gchar *stock_id)
{
g_return_val_if_fail (GTK_IS_ICON_FACTORY (factory), NULL);
g_return_val_if_fail (stock_id != NULL, NULL);
-
+
return g_hash_table_lookup (factory->icons, stock_id);
}
@@ -260,22 +259,21 @@ static GSList *default_factories = NULL;
/**
* gtk_icon_factory_add_default:
* @factory: a #GtkIconFactory
- *
+ *
* Adds an icon factory to the list of icon factories searched by
* gtk_style_lookup_icon_set(). This means that, for example,
* gtk_image_new_from_stock() will be able to find icons in @factory.
* There will normally be an icon factory added for each library or
* application that comes with icons. The default icon factories
* can be overridden by themes.
- *
- **/
+ */
void
gtk_icon_factory_add_default (GtkIconFactory *factory)
{
g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
g_object_ref (factory);
-
+
default_factories = g_slist_prepend (default_factories, factory);
}
@@ -286,8 +284,7 @@ gtk_icon_factory_add_default (GtkIconFactory *factory)
* Removes an icon factory from the list of default icon
* factories. Not normally used; you might use it for a library that
* can be unloaded or shut down.
- *
- **/
+ */
void
gtk_icon_factory_remove_default (GtkIconFactory *factory)
{
@@ -318,17 +315,16 @@ _gtk_icon_factory_ensure_default_icons (void)
* the #GtkStyle for the widget that will display the icon, instead of
* using this function directly, so that themes are taken into
* account.
- *
- *
+ *
* Return value: a #GtkIconSet, or %NULL
- **/
+ */
GtkIconSet *
gtk_icon_factory_lookup_default (const gchar *stock_id)
{
GSList *tmp_list;
g_return_val_if_fail (stock_id != NULL, NULL);
-
+
tmp_list = default_factories;
while (tmp_list != NULL)
{
@@ -338,12 +334,12 @@ gtk_icon_factory_lookup_default (const gchar *stock_id)
if (icon_set)
return icon_set;
-
+
tmp_list = g_slist_next (tmp_list);
}
_gtk_icon_factory_ensure_default_icons ();
-
+
return gtk_icon_factory_lookup (gtk_default_icons, stock_id);
}
@@ -357,7 +353,7 @@ register_stock_icon (GtkIconFactory *factory,
source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
source.source.icon_name = (gchar *)stock_id;
gtk_icon_set_add_source (set, &source);
-
+
gtk_icon_factory_add (factory, stock_id, set);
gtk_icon_set_unref (set);
}
@@ -375,12 +371,12 @@ register_bidi_stock_icon (GtkIconFactory *factory,
source.source.icon_name = (gchar *)stock_id_ltr;
source.direction = GTK_TEXT_DIR_LTR;
gtk_icon_set_add_source (set, &source);
-
+
source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
source.source.icon_name = (gchar *)stock_id_rtl;
source.direction = GTK_TEXT_DIR_RTL;
gtk_icon_set_add_source (set, &source);
-
+
gtk_icon_factory_add (factory, stock_id, set);
gtk_icon_set_unref (set);
}
@@ -416,9 +412,9 @@ get_default_icons (GtkIconFactory *factory)
register_stock_icon (factory, GTK_STOCK_GO_DOWN);
register_stock_icon (factory, GTK_STOCK_EXECUTE);
register_stock_icon (factory, GTK_STOCK_QUIT);
- register_bidi_stock_icon (factory,
- GTK_STOCK_GOTO_FIRST,
- GTK_STOCK_GOTO_FIRST "-ltr",
+ register_bidi_stock_icon (factory,
+ GTK_STOCK_GOTO_FIRST,
+ GTK_STOCK_GOTO_FIRST "-ltr",
GTK_STOCK_GOTO_FIRST "-rtl");
register_stock_icon (factory, GTK_STOCK_SELECT_FONT);
register_stock_icon (factory, GTK_STOCK_FULLSCREEN);
@@ -427,15 +423,15 @@ get_default_icons (GtkIconFactory *factory)
register_stock_icon (factory, GTK_STOCK_HELP);
register_stock_icon (factory, GTK_STOCK_HOME);
register_stock_icon (factory, GTK_STOCK_INFO);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_JUMP_TO,
GTK_STOCK_JUMP_TO "-ltr",
GTK_STOCK_JUMP_TO "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_GOTO_LAST,
GTK_STOCK_GOTO_LAST "-ltr",
GTK_STOCK_GOTO_LAST "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_GO_BACK,
GTK_STOCK_GO_BACK "-ltr",
GTK_STOCK_GO_BACK "-rtl");
@@ -457,17 +453,17 @@ get_default_icons (GtkIconFactory *factory)
register_stock_icon (factory, GTK_STOCK_PRINT_REPORT);
register_stock_icon (factory, GTK_STOCK_PRINT_WARNING);
register_stock_icon (factory, GTK_STOCK_PROPERTIES);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_REDO,
GTK_STOCK_REDO "-ltr",
GTK_STOCK_REDO "-rtl");
register_stock_icon (factory, GTK_STOCK_REMOVE);
register_stock_icon (factory, GTK_STOCK_REFRESH);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_REVERT_TO_SAVED,
GTK_STOCK_REVERT_TO_SAVED "-ltr",
GTK_STOCK_REVERT_TO_SAVED "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_GO_FORWARD,
GTK_STOCK_GO_FORWARD "-ltr",
GTK_STOCK_GO_FORWARD "-rtl");
@@ -484,21 +480,21 @@ get_default_icons (GtkIconFactory *factory)
register_stock_icon (factory, GTK_STOCK_ITALIC);
register_stock_icon (factory, GTK_STOCK_STRIKETHROUGH);
register_stock_icon (factory, GTK_STOCK_UNDERLINE);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_INDENT,
GTK_STOCK_INDENT "-ltr",
GTK_STOCK_INDENT "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_UNINDENT,
GTK_STOCK_UNINDENT "-ltr",
GTK_STOCK_UNINDENT "-rtl");
register_stock_icon (factory, GTK_STOCK_GOTO_TOP);
register_stock_icon (factory, GTK_STOCK_DELETE);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_UNDELETE,
GTK_STOCK_UNDELETE "-ltr",
GTK_STOCK_UNDELETE "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_UNDO,
GTK_STOCK_UNDO "-ltr",
GTK_STOCK_UNDO "-rtl");
@@ -510,25 +506,25 @@ get_default_icons (GtkIconFactory *factory)
register_stock_icon (factory, GTK_STOCK_DISCONNECT);
register_stock_icon (factory, GTK_STOCK_EDIT);
register_stock_icon (factory, GTK_STOCK_CAPS_LOCK_WARNING);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_MEDIA_FORWARD,
GTK_STOCK_MEDIA_FORWARD "-ltr",
GTK_STOCK_MEDIA_FORWARD "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_MEDIA_NEXT,
GTK_STOCK_MEDIA_NEXT "-ltr",
GTK_STOCK_MEDIA_NEXT "-rtl");
register_stock_icon (factory, GTK_STOCK_MEDIA_PAUSE);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_MEDIA_PLAY,
GTK_STOCK_MEDIA_PLAY "-ltr",
GTK_STOCK_MEDIA_PLAY "-rtl");
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_MEDIA_PREVIOUS,
GTK_STOCK_MEDIA_PREVIOUS "-ltr",
GTK_STOCK_MEDIA_PREVIOUS "-rtl");
register_stock_icon (factory, GTK_STOCK_MEDIA_RECORD);
- register_bidi_stock_icon (factory,
+ register_bidi_stock_icon (factory,
GTK_STOCK_MEDIA_REWIND,
GTK_STOCK_MEDIA_REWIND "-ltr",
GTK_STOCK_MEDIA_REWIND "-rtl");
@@ -554,7 +550,7 @@ struct _IconSize
{
gint size;
gchar *name;
-
+
gint width;
gint height;
};
@@ -589,7 +585,7 @@ init_icon_sizes (void)
gint i;
icon_aliases = g_hash_table_new (g_str_hash, g_str_equal);
-
+
icon_sizes = g_new (IconSize, NUM_BUILTIN_SIZES);
icon_sizes_allocated = NUM_BUILTIN_SIZES;
icon_sizes_used = NUM_BUILTIN_SIZES;
@@ -604,7 +600,7 @@ init_icon_sizes (void)
* Even if we did I suppose removing the builtin sizes would be
* disallowed.
*/
-
+
icon_sizes[GTK_ICON_SIZE_MENU].size = GTK_ICON_SIZE_MENU;
icon_sizes[GTK_ICON_SIZE_MENU].name = "gtk-menu";
icon_sizes[GTK_ICON_SIZE_MENU].width = 16;
@@ -619,7 +615,7 @@ init_icon_sizes (void)
icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].name = "gtk-small-toolbar";
icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].width = 18;
icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].height = 18;
-
+
icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].size = GTK_ICON_SIZE_LARGE_TOOLBAR;
icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].name = "gtk-large-toolbar";
icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].width = 24;
@@ -642,10 +638,10 @@ init_icon_sizes (void)
while (i < NUM_BUILTIN_SIZES)
{
gtk_icon_size_register_alias (icon_sizes[i].name, icon_sizes[i].size);
-
+
++i;
}
-
+
#undef NUM_BUILTIN_SIZES
}
}
@@ -695,7 +691,7 @@ icon_size_set_for_settings (GtkSettings *settings,
if (size == GTK_ICON_SIZE_INVALID)
/* Reserve a place */
size = icon_size_register_intern (size_name, -1, -1);
-
+
settings_sizes = get_settings_sizes (settings, NULL);
if (size >= settings_sizes->len)
{
@@ -707,7 +703,7 @@ icon_size_set_for_settings (GtkSettings *settings,
}
settings_size = &g_array_index (settings_sizes, SettingsIconSize, size);
-
+
settings_size->width = width;
settings_size->height = height;
}
@@ -721,7 +717,7 @@ scan_icon_size_name (const char **pos, GString *out)
while (g_ascii_isspace (*p))
p++;
-
+
if (!((*p >= 'A' && *p <= 'Z') ||
(*p >= 'a' && *p <= 'z') ||
*p == '_' || *p == '-'))
@@ -755,7 +751,7 @@ icon_size_setting_parse (GtkSettings *settings,
while (pango_skip_space (&p))
{
gint width, height;
-
+
if (!scan_icon_size_name (&p, name_buf))
goto err;
@@ -845,10 +841,10 @@ icon_sizes_init_for_settings (GtkSettings *settings)
"notify::gtk-icon-sizes",
G_CALLBACK (icon_size_settings_changed),
NULL);
-
+
icon_size_set_all_from_settings (settings);
}
-
+
static gboolean
icon_size_lookup_intern (GtkSettings *settings,
GtkIconSize size,
@@ -858,7 +854,7 @@ icon_size_lookup_intern (GtkSettings *settings,
GArray *settings_sizes;
gint width_for_settings = -1;
gint height_for_settings = -1;
-
+
init_icon_sizes ();
if (size == (GtkIconSize)-1)
@@ -873,17 +869,18 @@ icon_size_lookup_intern (GtkSettings *settings,
if (settings)
{
gboolean initial = FALSE;
-
+
settings_sizes = get_settings_sizes (settings, &initial);
+
if (initial)
icon_sizes_init_for_settings (settings);
-
+
if (size < settings_sizes->len)
{
SettingsIconSize *settings_size;
-
+
settings_size = &g_array_index (settings_sizes, SettingsIconSize, size);
-
+
width_for_settings = settings_size->width;
height_for_settings = settings_size->height;
}
@@ -907,7 +904,7 @@ icon_size_lookup_intern (GtkSettings *settings,
* @height: location to store icon height
*
* Obtains the pixel size of a semantic icon size, possibly
- * modified by user preferences for a particular
+ * modified by user preferences for a particular
* #GtkSettings. Normally @size would be
* #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_BUTTON, etc. This function
* isn't normally needed, gtk_widget_render_icon() is the usual
@@ -916,11 +913,11 @@ icon_size_lookup_intern (GtkSettings *settings,
* the width/height returned by gtk_icon_size_lookup(), because themes
* are free to render the pixbuf however they like, including changing
* the usual size.
- *
+ *
* Return value: %TRUE if @size was a valid size
*
* Since: 2.2
- **/
+ */
gboolean
gtk_icon_size_lookup_for_settings (GtkSettings *settings,
GtkIconSize size,
@@ -949,9 +946,9 @@ gtk_icon_size_lookup_for_settings (GtkSettings *settings,
* the width/height returned by gtk_icon_size_lookup(), because themes
* are free to render the pixbuf however they like, including changing
* the usual size.
- *
+ *
* Return value: %TRUE if @size was a valid size
- **/
+ */
gboolean
gtk_icon_size_lookup (GtkIconSize size,
gint *widthp,
@@ -971,7 +968,7 @@ icon_size_register_intern (const gchar *name,
{
IconAlias *old_alias;
GtkIconSize size;
-
+
init_icon_sizes ();
old_alias = g_hash_table_lookup (icon_aliases, name);
@@ -1018,8 +1015,7 @@ icon_size_register_intern (const gchar *name,
* etc. Returns the integer value for the size.
*
* Returns: integer value representing the size
- *
- **/
+ */
GtkIconSize
gtk_icon_size_register (const gchar *name,
gint width,
@@ -1028,7 +1024,7 @@ gtk_icon_size_register (const gchar *name,
g_return_val_if_fail (name != NULL, 0);
g_return_val_if_fail (width > 0, 0);
g_return_val_if_fail (height > 0, 0);
-
+
return icon_size_register_intern (name, width, height);
}
@@ -1040,14 +1036,13 @@ gtk_icon_size_register (const gchar *name,
* Registers @alias as another name for @target.
* So calling gtk_icon_size_from_name() with @alias as argument
* will return @target.
- *
- **/
+ */
void
gtk_icon_size_register_alias (const gchar *alias,
GtkIconSize target)
{
IconAlias *ia;
-
+
g_return_if_fail (alias != NULL);
init_icon_sizes ();
@@ -1077,20 +1072,20 @@ gtk_icon_size_register_alias (const gchar *alias,
}
}
-/**
+/**
* gtk_icon_size_from_name:
* @name: the name to look up.
* @returns: the icon size with the given name.
- *
+ *
* Looks up the icon size associated with @name.
- **/
+ */
GtkIconSize
gtk_icon_size_from_name (const gchar *name)
{
IconAlias *ia;
init_icon_sizes ();
-
+
ia = g_hash_table_lookup (icon_aliases, name);
if (ia && icon_sizes[ia->target].width > 0)
@@ -1103,10 +1098,10 @@ gtk_icon_size_from_name (const gchar *name)
* gtk_icon_size_get_name:
* @size: a #GtkIconSize.
* @returns: the name of the given icon size.
- *
- * Gets the canonical name of the given icon size. The returned string
+ *
+ * Gets the canonical name of the given icon size. The returned string
* is statically allocated and should not be freed.
- **/
+ */
G_CONST_RETURN gchar*
gtk_icon_size_get_name (GtkIconSize size)
{
@@ -1164,7 +1159,7 @@ static guint cache_serial = 0;
/**
* gtk_icon_set_new:
- *
+ *
* Creates a new #GtkIconSet. A #GtkIconSet represents a single icon
* in various sizes and widget states. It can provide a #GdkPixbuf
* for a given size and state on request, and automatically caches
@@ -1174,9 +1169,9 @@ static guint cache_serial = 0;
* using #GtkIconSet directly. The one case where you'd use
* #GtkIconSet is to create application-specific icon sets to place in
* a #GtkIconFactory.
- *
+ *
* Return value: a new #GtkIconSet
- **/
+ */
GtkIconSet*
gtk_icon_set_new (void)
{
@@ -1189,22 +1184,22 @@ gtk_icon_set_new (void)
icon_set->cache = NULL;
icon_set->cache_size = 0;
icon_set->cache_serial = cache_serial;
-
+
return icon_set;
}
/**
* gtk_icon_set_new_from_pixbuf:
* @pixbuf: a #GdkPixbuf
- *
+ *
* Creates a new #GtkIconSet with @pixbuf as the default/fallback
* source image. If you don't add any additional #GtkIconSource to the
* icon set, all variants of the icon will be created from @pixbuf,
* using scaling, pixelation, etc. as required to adjust the icon size
* or make the icon look insensitive/prelighted.
- *
+ *
* Return value: a new #GtkIconSet
- **/
+ */
GtkIconSet *
gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
{
@@ -1219,7 +1214,7 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
gtk_icon_source_set_pixbuf (&source, pixbuf);
gtk_icon_set_add_source (set, &source);
gtk_icon_source_set_pixbuf (&source, NULL);
-
+
return set;
}
@@ -1227,11 +1222,11 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
/**
* gtk_icon_set_ref:
* @icon_set: a #GtkIconSet.
- *
+ *
* Increments the reference count on @icon_set.
- *
+ *
* Return value: @icon_set.
- **/
+ */
GtkIconSet*
gtk_icon_set_ref (GtkIconSet *icon_set)
{
@@ -1246,10 +1241,10 @@ gtk_icon_set_ref (GtkIconSet *icon_set)
/**
* gtk_icon_set_unref:
* @icon_set: a #GtkIconSet
- *
+ *
* Decrements the reference count on @icon_set, and frees memory
* if the reference count reaches 0.
- **/
+ */
void
gtk_icon_set_unref (GtkIconSet *icon_set)
{
@@ -1279,7 +1274,7 @@ GType
gtk_icon_set_get_type (void)
{
static GType our_type = 0;
-
+
if (our_type == 0)
our_type = g_boxed_type_register_static (I_("GtkIconSet"),
(GBoxedCopyFunc) gtk_icon_set_ref,
@@ -1291,9 +1286,9 @@ gtk_icon_set_get_type (void)
/**
* gtk_icon_set_copy:
* @icon_set: a #GtkIconSet
- *
- * Copies @icon_set by value.
- *
+ *
+ * Copies @icon_set by value.
+ *
* Return value: a new #GtkIconSet identical to the first.
**/
GtkIconSet*
@@ -1301,7 +1296,7 @@ gtk_icon_set_copy (GtkIconSet *icon_set)
{
GtkIconSet *copy;
GSList *tmp_list;
-
+
copy = gtk_icon_set_new ();
tmp_list = icon_set->sources;
@@ -1318,7 +1313,7 @@ gtk_icon_set_copy (GtkIconSet *icon_set)
copy->cache = copy_cache (icon_set, copy);
copy->cache_size = icon_set->cache_size;
copy->cache_serial = icon_set->cache_serial;
-
+
return copy;
}
@@ -1334,8 +1329,8 @@ sizes_equivalent (GtkIconSize lhs,
*/
#if 1
return lhs == rhs;
-#else
-
+#else
+
gint r_w, r_h, l_w, l_h;
icon_size_lookup_intern (NULL, rhs, &r_w, &r_h);
@@ -1354,7 +1349,7 @@ find_best_matching_source (GtkIconSet *icon_set,
{
GtkIconSource *source;
GSList *tmp_list;
-
+
/* We need to find the best icon source. Direction matters more
* than state, state matters more than size. icon_set->sources
* is sorted according to wildness, so if we take the first
@@ -1362,13 +1357,13 @@ find_best_matching_source (GtkIconSet *icon_set,
* multiple matches for a given "wildness" then the RC file contained
* dumb stuff, and we end up with an arbitrary matching source)
*/
-
+
source = NULL;
tmp_list = icon_set->sources;
while (tmp_list != NULL)
{
GtkIconSource *s = tmp_list->data;
-
+
if ((s->any_direction || (s->direction == direction)) &&
(s->any_state || (s->state == state)) &&
(s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))))
@@ -1379,13 +1374,13 @@ find_best_matching_source (GtkIconSet *icon_set,
break;
}
}
-
+
tmp_list = g_slist_next (tmp_list);
}
return source;
}
-
+
static gboolean
ensure_filename_pixbuf (GtkIconSet *icon_set,
GtkIconSource *source)
@@ -1393,9 +1388,9 @@ ensure_filename_pixbuf (GtkIconSet *icon_set,
if (source->filename_pixbuf == NULL)
{
GError *error = NULL;
-
+
source->filename_pixbuf = gdk_pixbuf_new_from_file (source->source.filename, &error);
-
+
if (source->filename_pixbuf == NULL)
{
/* Remove this icon source so we don't keep trying to
@@ -1403,18 +1398,18 @@ ensure_filename_pixbuf (GtkIconSet *icon_set,
*/
g_warning (_("Error loading icon: %s"), error->message);
g_error_free (error);
-
+
icon_set->sources = g_slist_remove (icon_set->sources, source);
-
+
gtk_icon_source_free (source);
return FALSE;
}
}
-
+
return TRUE;
}
-
+
static GdkPixbuf *
render_icon_name_pixbuf (GtkIconSource *icon_source,
GtkStyle *style,
@@ -1433,7 +1428,7 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
gint width, height, pixel_size;
gint *sizes, *s, dist;
GError *error = NULL;
-
+
if (widget && gtk_widget_has_screen (widget))
screen = gtk_widget_get_screen (widget);
else if (style && style->colormap)
@@ -1452,8 +1447,7 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
{
if (size == (GtkIconSize)-1)
{
- /* Find an available size close to 48
- */
+ /* Find an available size close to 48 */
sizes = gtk_icon_theme_get_icon_sizes (icon_theme, icon_source->source.icon_name);
dist = 1000;
width = height = 48;
@@ -1472,7 +1466,7 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
dist = 48 - *s;
}
}
- else
+ else
{
if (*s - 48 < dist)
{
@@ -1481,7 +1475,7 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
}
}
}
-
+
g_free (sizes);
}
else
@@ -1500,12 +1494,13 @@ render_icon_name_pixbuf (GtkIconSource *icon_source,
if (!tmp_pixbuf)
{
- g_warning ("Error loading theme icon '%s' for stock: %s",
- icon_source->source.icon_name, error->message);
- g_error_free (error);
+ g_warning ("Error loading theme icon '%s' for stock: %s",
+ icon_source->source.icon_name, error ? error->message : "");
+ if (error)
+ g_error_free (error);
return NULL;
}
-
+
tmp_source = *icon_source;
tmp_source.type = GTK_ICON_SOURCE_PIXBUF;
tmp_source.source.pixbuf = tmp_pixbuf;
@@ -1547,7 +1542,7 @@ find_and_render_icon_source (GtkIconSet *icon_set,
while (pixbuf == NULL)
{
GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, failed);
-
+
if (source == NULL)
break;
@@ -1612,7 +1607,7 @@ render_fallback_image (GtkStyle *style,
gtk_icon_source_set_pixbuf (&fallback_source, pixbuf);
g_object_unref (pixbuf);
}
-
+
return gtk_style_render_icon (style,
&fallback_source,
direction,
@@ -1636,16 +1631,16 @@ render_fallback_image (GtkStyle *style,
* @detail: detail to pass to the theme engine, or %NULL.
* Note that passing a detail of anything but %NULL
* will disable caching.
- *
+ *
* Renders an icon using gtk_style_render_icon(). In most cases,
* gtk_widget_render_icon() is better, since it automatically provides
* most of the arguments from the current widget settings. This
* function never returns %NULL; if the icon can't be rendered
* (perhaps because an image file fails to load), a default "missing
* image" icon will be returned instead.
- *
+ *
* Return value: a #GdkPixbuf to be displayed
- **/
+ */
GdkPixbuf*
gtk_icon_set_render_icon (GtkIconSet *icon_set,
GtkStyle *style,
@@ -1656,7 +1651,7 @@ gtk_icon_set_render_icon (GtkIconSet *icon_set,
const char *detail)
{
GdkPixbuf *icon;
-
+
g_return_val_if_fail (icon_set != NULL, NULL);
g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
@@ -1667,7 +1662,7 @@ gtk_icon_set_render_icon (GtkIconSet *icon_set,
{
icon = find_in_cache (icon_set, style, direction,
state, size);
-
+
if (icon)
{
g_object_ref (icon);
@@ -1684,7 +1679,7 @@ gtk_icon_set_render_icon (GtkIconSet *icon_set,
if (detail == NULL)
add_to_cache (icon_set, style, direction, state, size, icon);
-
+
return icon;
}
@@ -1726,7 +1721,7 @@ icon_source_compare (gconstpointer ap, gconstpointer bp)
* gtk_icon_set_render_icon(), but #GtkIconSet needs base images to
* work with. The base images and when to use them are described by
* a #GtkIconSource.
- *
+ *
* This function copies @source, so you can reuse the same source immediately
* without affecting the icon set.
*
@@ -1745,10 +1740,9 @@ icon_source_compare (gconstpointer ap, gconstpointer bp)
*
* gtk_icon_set_new_from_pixbuf() creates a new icon set with a
* default icon source based on the given pixbuf.
- *
- **/
+ */
void
-gtk_icon_set_add_source (GtkIconSet *icon_set,
+gtk_icon_set_add_source (GtkIconSet *icon_set,
const GtkIconSource *source)
{
g_return_if_fail (icon_set != NULL);
@@ -1759,7 +1753,7 @@ gtk_icon_set_add_source (GtkIconSet *icon_set,
g_warning ("Useless empty GtkIconSource");
return;
}
-
+
icon_set->sources = g_slist_insert_sorted (icon_set->sources,
gtk_icon_source_copy (source),
icon_source_compare);
@@ -1773,8 +1767,7 @@ gtk_icon_set_add_source (GtkIconSet *icon_set,
*
* Obtains a list of icon sizes this icon set can render. The returned
* array must be freed with g_free().
- *
- **/
+ */
void
gtk_icon_set_get_sizes (GtkIconSet *icon_set,
GtkIconSize **sizes,
@@ -1783,11 +1776,11 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
GSList *tmp_list;
gboolean all_sizes = FALSE;
GSList *specifics = NULL;
-
+
g_return_if_fail (icon_set != NULL);
g_return_if_fail (sizes != NULL);
g_return_if_fail (n_sizes != NULL);
-
+
tmp_list = icon_set->sources;
while (tmp_list != NULL)
{
@@ -1802,7 +1795,7 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
}
else
specifics = g_slist_prepend (specifics, GINT_TO_POINTER (source->size));
-
+
tmp_list = g_slist_next (tmp_list);
}
@@ -1812,11 +1805,11 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
gint i;
init_icon_sizes ();
-
+
*sizes = g_new (GtkIconSize, icon_sizes_used);
*n_sizes = icon_sizes_used - 1;
-
- i = 1;
+
+ i = 1;
while (i < icon_sizes_used)
{
(*sizes)[i - 1] = icon_sizes[i].size;
@@ -1826,7 +1819,7 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
else
{
gint i;
-
+
*n_sizes = g_slist_length (specifics);
*sizes = g_new (GtkIconSize, *n_sizes);
@@ -1847,21 +1840,21 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
/**
* gtk_icon_source_new:
- *
+ *
* Creates a new #GtkIconSource. A #GtkIconSource contains a #GdkPixbuf (or
* image filename) that serves as the base image for one or more of the
* icons in a #GtkIconSet, along with a specification for which icons in the
* icon set will be based on that pixbuf or image file. An icon set contains
* a set of icons that represent "the same" logical concept in different states,
* different global text directions, and different sizes.
- *
+ *
* So for example a web browser's "Back to Previous Page" icon might
* point in a different direction in Hebrew and in English; it might
* look different when insensitive; and it might change size depending
* on toolbar mode (small/large icons). So a single icon set would
* contain all those variants of the icon. #GtkIconSet contains a list
* of #GtkIconSource from which it can derive specific icon variants in
- * the set.
+ * the set.
*
* In the simplest case, #GtkIconSet contains one source pixbuf from
* which it derives all variants. The convenience function
@@ -1876,46 +1869,46 @@ gtk_icon_set_get_sizes (GtkIconSet *icon_set,
* By default, the icon source has all parameters wildcarded. That is,
* the icon source will be used as the base icon for any desired text
* direction, widget state, or icon size.
- *
+ *
* Return value: a new #GtkIconSource
- **/
+ */
GtkIconSource*
gtk_icon_source_new (void)
{
GtkIconSource *src;
-
+
src = g_new0 (GtkIconSource, 1);
src->direction = GTK_TEXT_DIR_NONE;
src->size = GTK_ICON_SIZE_INVALID;
src->state = GTK_STATE_NORMAL;
-
+
src->any_direction = TRUE;
src->any_state = TRUE;
src->any_size = TRUE;
-
+
return src;
}
/**
* gtk_icon_source_copy:
* @source: a #GtkIconSource
- *
+ *
* Creates a copy of @source; mostly useful for language bindings.
- *
+ *
* Return value: a new #GtkIconSource
- **/
+ */
GtkIconSource*
gtk_icon_source_copy (const GtkIconSource *source)
{
GtkIconSource *copy;
-
+
g_return_val_if_fail (source != NULL, NULL);
copy = g_new (GtkIconSource, 1);
*copy = *source;
-
+
switch (copy->type)
{
case GTK_ICON_SOURCE_EMPTY:
@@ -1945,10 +1938,10 @@ gtk_icon_source_copy (const GtkIconSource *source)
/**
* gtk_icon_source_free:
* @source: a #GtkIconSource
- *
+ *
* Frees a dynamically-allocated icon source, along with its
* filename, size, and pixbuf fields if those are not %NULL.
- **/
+ */
void
gtk_icon_source_free (GtkIconSource *source)
{
@@ -1962,7 +1955,7 @@ GType
gtk_icon_source_get_type (void)
{
static GType our_type = 0;
-
+
if (our_type == 0)
our_type = g_boxed_type_register_static (I_("GtkIconSource"),
(GBoxedCopyFunc) gtk_icon_source_copy,
@@ -2012,8 +2005,8 @@ icon_source_clear (GtkIconSource *source)
* @filename: image file to use
*
* Sets the name of an image file to use as a base image when creating
- * icon variants for #GtkIconSet. The filename must be absolute.
- **/
+ * icon variants for #GtkIconSet. The filename must be absolute.
+ */
void
gtk_icon_source_set_filename (GtkIconSource *source,
const gchar *filename)
@@ -2024,9 +2017,9 @@ gtk_icon_source_set_filename (GtkIconSource *source,
if (source->type == GTK_ICON_SOURCE_FILENAME &&
source->source.filename == filename)
return;
-
+
icon_source_clear (source);
-
+
if (filename != NULL)
{
source->type = GTK_ICON_SOURCE_FILENAME;
@@ -2044,7 +2037,7 @@ gtk_icon_source_set_filename (GtkIconSource *source,
*
* Sets the name of an icon to look up in the current icon theme
* to use as a base image when creating icon variants for #GtkIconSet.
- **/
+ */
void
gtk_icon_source_set_icon_name (GtkIconSource *source,
const gchar *icon_name)
@@ -2056,7 +2049,7 @@ gtk_icon_source_set_icon_name (GtkIconSource *source,
return;
icon_source_clear (source);
-
+
if (icon_name != NULL)
{
source->type = GTK_ICON_SOURCE_ICON_NAME;
@@ -2071,20 +2064,20 @@ gtk_icon_source_set_icon_name (GtkIconSource *source,
*
* Sets a pixbuf to use as a base image when creating icon variants
* for #GtkIconSet.
- **/
+ */
void
gtk_icon_source_set_pixbuf (GtkIconSource *source,
GdkPixbuf *pixbuf)
{
g_return_if_fail (source != NULL);
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
-
+
if (source->type == GTK_ICON_SOURCE_PIXBUF &&
source->source.pixbuf == pixbuf)
return;
icon_source_clear (source);
-
+
if (pixbuf != NULL)
{
source->type = GTK_ICON_SOURCE_PIXBUF;
@@ -2095,14 +2088,14 @@ gtk_icon_source_set_pixbuf (GtkIconSource *source,
/**
* gtk_icon_source_get_filename:
* @source: a #GtkIconSource
- *
+ *
* Retrieves the source filename, or %NULL if none is set. The
* filename is not a copy, and should not be modified or expected to
* persist beyond the lifetime of the icon source.
- *
+ *
* Return value: image filename. This string must not be modified
* or freed.
- **/
+ */
G_CONST_RETURN gchar*
gtk_icon_source_get_filename (const GtkIconSource *source)
{
@@ -2117,13 +2110,13 @@ gtk_icon_source_get_filename (const GtkIconSource *source)
/**
* gtk_icon_source_get_icon_name:
* @source: a #GtkIconSource
- *
+ *
* Retrieves the source icon name, or %NULL if none is set. The
* icon_name is not a copy, and should not be modified or expected to
* persist beyond the lifetime of the icon source.
- *
+ *
* Return value: icon name. This string must not be modified or freed.
- **/
+ */
G_CONST_RETURN gchar*
gtk_icon_source_get_icon_name (const GtkIconSource *source)
{
@@ -2139,7 +2132,7 @@ gtk_icon_source_get_icon_name (const GtkIconSource *source)
/**
* gtk_icon_source_get_pixbuf:
* @source: a #GtkIconSource
- *
+ *
* Retrieves the source pixbuf, or %NULL if none is set.
* In addition, if a filename source is in use, this
* function in some cases will return the pixbuf from
@@ -2147,14 +2140,14 @@ gtk_icon_source_get_icon_name (const GtkIconSource *source)
* for the GtkIconSource passed to the GtkStyle::render_icon()
* virtual function. The reference count on the pixbuf is
* not incremented.
- *
+ *
* Return value: source pixbuf
- **/
+ */
GdkPixbuf*
gtk_icon_source_get_pixbuf (const GtkIconSource *source)
{
g_return_val_if_fail (source != NULL, NULL);
-
+
if (source->type == GTK_ICON_SOURCE_PIXBUF)
return source->source.pixbuf;
else if (source->type == GTK_ICON_SOURCE_FILENAME)
@@ -2177,8 +2170,7 @@ gtk_icon_source_get_pixbuf (const GtkIconSource *source)
*
* #GtkIconSet prefers non-wildcarded sources (exact matches) over
* wildcarded sources, and will use an exact match when possible.
- *
- **/
+ */
void
gtk_icon_source_set_direction_wildcarded (GtkIconSource *source,
gboolean setting)
@@ -2206,7 +2198,7 @@ gtk_icon_source_set_direction_wildcarded (GtkIconSource *source,
* produce an appropriate icon for a given state, for example
* lightening an image on prelight, but will not modify source images
* that match exactly.
- **/
+ */
void
gtk_icon_source_set_state_wildcarded (GtkIconSource *source,
gboolean setting)
@@ -2234,40 +2226,40 @@ gtk_icon_source_set_state_wildcarded (GtkIconSource *source,
* #GtkIconSet will normally scale wildcarded source images to produce
* an appropriate icon at a given size, but will not change the size
* of source images that match exactly.
- **/
+ */
void
gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
gboolean setting)
{
g_return_if_fail (source != NULL);
- source->any_size = setting != FALSE;
+ source->any_size = setting != FALSE;
}
/**
* gtk_icon_source_get_size_wildcarded:
* @source: a #GtkIconSource
- *
+ *
* Gets the value set by gtk_icon_source_set_size_wildcarded().
- *
+ *
* Return value: %TRUE if this icon source is a base for any icon size variant
- **/
+ */
gboolean
gtk_icon_source_get_size_wildcarded (const GtkIconSource *source)
{
g_return_val_if_fail (source != NULL, TRUE);
-
+
return source->any_size;
}
/**
* gtk_icon_source_get_state_wildcarded:
* @source: a #GtkIconSource
- *
+ *
* Gets the value set by gtk_icon_source_set_state_wildcarded().
- *
+ *
* Return value: %TRUE if this icon source is a base for any widget state variant
- **/
+ */
gboolean
gtk_icon_source_get_state_wildcarded (const GtkIconSource *source)
{
@@ -2279,11 +2271,11 @@ gtk_icon_source_get_state_wildcarded (const GtkIconSource *source)
/**
* gtk_icon_source_get_direction_wildcarded:
* @source: a #GtkIconSource
- *
+ *
* Gets the value set by gtk_icon_source_set_direction_wildcarded().
- *
+ *
* Return value: %TRUE if this icon source is a base for any text direction variant
- **/
+ */
gboolean
gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
{
@@ -2299,13 +2291,12 @@ gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
*
* Sets the text direction this icon source is intended to be used
* with.
- *
+ *
* Setting the text direction on an icon source makes no difference
* if the text direction is wildcarded. Therefore, you should usually
* call gtk_icon_source_set_direction_wildcarded() to un-wildcard it
* in addition to calling this function.
- *
- **/
+ */
void
gtk_icon_source_set_direction (GtkIconSource *source,
GtkTextDirection direction)
@@ -2322,13 +2313,12 @@ gtk_icon_source_set_direction (GtkIconSource *source,
*
* Sets the widget state this icon source is intended to be used
* with.
- *
+ *
* Setting the widget state on an icon source makes no difference
* if the state is wildcarded. Therefore, you should usually
* call gtk_icon_source_set_state_wildcarded() to un-wildcard it
* in addition to calling this function.
- *
- **/
+ */
void
gtk_icon_source_set_state (GtkIconSource *source,
GtkStateType state)
@@ -2345,13 +2335,12 @@ gtk_icon_source_set_state (GtkIconSource *source,
*
* Sets the icon size this icon source is intended to be used
* with.
- *
+ *
* Setting the icon size on an icon source makes no difference
* if the size is wildcarded. Therefore, you should usually
* call gtk_icon_source_set_size_wildcarded() to un-wildcard it
* in addition to calling this function.
- *
- **/
+ */
void
gtk_icon_source_set_size (GtkIconSource *source,
GtkIconSize size)
@@ -2364,13 +2353,13 @@ gtk_icon_source_set_size (GtkIconSource *source,
/**
* gtk_icon_source_get_direction:
* @source: a #GtkIconSource
- *
+ *
* Obtains the text direction this icon source applies to. The return
- * value is only useful/meaningful if the text direction is <emphasis>not</emphasis>
+ * value is only useful/meaningful if the text direction is <emphasis>not</emphasis>
* wildcarded.
- *
+ *
* Return value: text direction this source matches
- **/
+ */
GtkTextDirection
gtk_icon_source_get_direction (const GtkIconSource *source)
{
@@ -2382,13 +2371,13 @@ gtk_icon_source_get_direction (const GtkIconSource *source)
/**
* gtk_icon_source_get_state:
* @source: a #GtkIconSource
- *
+ *
* Obtains the widget state this icon source applies to. The return
* value is only useful/meaningful if the widget state is <emphasis>not</emphasis>
* wildcarded.
- *
+ *
* Return value: widget state this source matches
- **/
+ */
GtkStateType
gtk_icon_source_get_state (const GtkIconSource *source)
{
@@ -2400,12 +2389,12 @@ gtk_icon_source_get_state (const GtkIconSource *source)
/**
* gtk_icon_source_get_size:
* @source: a #GtkIconSource
- *
+ *
* Obtains the icon size this source applies to. The return value
* is only useful/meaningful if the icon size is <emphasis>not</emphasis> wildcarded.
- *
+ *
* Return value: icon size this source matches.
- **/
+ */
GtkIconSize
gtk_icon_source_get_size (const GtkIconSource *source)
{
@@ -2463,7 +2452,7 @@ find_in_cache (GtkIconSet *icon_set,
GSList *prev;
ensure_cache_up_to_date (icon_set);
-
+
prev = NULL;
tmp_list = icon_set->cache;
while (tmp_list != NULL)
@@ -2482,10 +2471,10 @@ find_in_cache (GtkIconSet *icon_set,
tmp_list->next = icon_set->cache;
icon_set->cache = tmp_list;
}
-
+
return icon->pixbuf;
}
-
+
prev = tmp_list;
tmp_list = g_slist_next (tmp_list);
}
@@ -2511,7 +2500,7 @@ add_to_cache (GtkIconSet *icon_set,
* its address could be reused by another style, creating a
* really weird bug
*/
-
+
if (style)
g_object_ref (style);
@@ -2527,12 +2516,12 @@ add_to_cache (GtkIconSet *icon_set,
if (icon->style)
attach_to_style (icon_set, icon->style);
-
+
if (icon_set->cache_size >= NUM_CACHED_ICONS)
{
/* Remove oldest item in the cache */
GSList *tmp_list;
-
+
tmp_list = icon_set->cache;
/* Find next-to-last link */
@@ -2582,9 +2571,9 @@ clear_cache (GtkIconSet *icon_set,
last_style = icon->style;
}
}
-
- cached_icon_free (icon);
-
+
+ cached_icon_free (icon);
+
tmp_list = g_slist_next (tmp_list);
}
@@ -2599,7 +2588,7 @@ copy_cache (GtkIconSet *icon_set,
GSList *copy = NULL;
ensure_cache_up_to_date (icon_set);
-
+
tmp_list = icon_set->cache;
while (tmp_list != NULL)
{
@@ -2613,13 +2602,13 @@ copy_cache (GtkIconSet *icon_set,
attach_to_style (copy_recipient, icon_copy->style);
g_object_ref (icon_copy->style);
}
-
+
g_object_ref (icon_copy->pixbuf);
icon_copy->size = icon->size;
-
- copy = g_slist_prepend (copy, icon_copy);
-
+
+ copy = g_slist_prepend (copy, icon_copy);
+
tmp_list = g_slist_next (tmp_list);
}
@@ -2673,7 +2662,7 @@ iconsets_foreach (gpointer key,
* time all cache entries will have the same style,
* so this is faster anyway.
*/
-
+
clear_cache (icon_set, FALSE);
}
@@ -2681,7 +2670,7 @@ static void
style_dnotify (gpointer data)
{
GHashTable *table = data;
-
+
g_hash_table_foreach (table, iconsets_foreach, NULL);
g_hash_table_destroy (table);
@@ -2696,13 +2685,13 @@ _gtk_icon_set_invalidate_caches (void)
/**
* _gtk_icon_factory_list_ids:
- *
+ *
* Gets all known IDs stored in an existing icon factory.
* The strings in the returned list aren't copied.
* The list itself should be freed.
- *
+ *
* Return value: List of ids in icon factories
- **/
+ */
GList*
_gtk_icon_factory_list_ids (void)
{
@@ -2712,18 +2701,18 @@ _gtk_icon_factory_list_ids (void)
ids = NULL;
_gtk_icon_factory_ensure_default_icons ();
-
+
tmp_list = all_icon_factories;
while (tmp_list != NULL)
{
GList *these_ids;
-
+
GtkIconFactory *factory = GTK_ICON_FACTORY (tmp_list->data);
these_ids = g_hash_table_get_keys (factory->icons);
-
+
ids = g_list_concat (ids, these_ids);
-
+
tmp_list = g_slist_next (tmp_list);
}
@@ -2733,7 +2722,7 @@ _gtk_icon_factory_list_ids (void)
typedef struct {
GSList *sources;
gboolean in_source;
-
+
} IconFactoryParserData;
typedef struct {
@@ -2764,7 +2753,7 @@ icon_source_start_element (GMarkupParseContext *context,
IconSourceParserData *source_data;
gchar *error_msg;
GQuark error_domain;
-
+
parser_data = (IconFactoryParserData*)user_data;
if (!parser_data->in_source)
@@ -2787,7 +2776,7 @@ icon_source_start_element (GMarkupParseContext *context,
goto error;
}
}
-
+
for (i = 0; names[i]; i++)
{
if (strcmp (names[i], "stock-id") == 0)
@@ -2851,7 +2840,7 @@ icon_source_start_element (GMarkupParseContext *context,
{
gchar *tmp;
gint line_number, char_number;
-
+
g_markup_parse_context_get_position (context,
&line_number,
&char_number);
@@ -2865,7 +2854,7 @@ icon_source_start_element (GMarkupParseContext *context,
tmp);
#else
g_warning ("%s", tmp);
-#endif
+#endif
g_free (tmp);
g_free (stock_id);
g_free (filename);
@@ -2909,7 +2898,7 @@ gtk_icon_factory_buildable_custom_tag_end (GtkBuildable *buildable,
gpointer *user_data)
{
GtkIconFactory *icon_factory;
-
+
icon_factory = GTK_ICON_FACTORY (buildable);
if (strcmp (tagname, "sources") == 0)
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 6df05ef80e..db183310d7 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -3508,7 +3508,7 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *icon_theme,
* @icon_theme: a #GtkIconTheme
* @pixbuf: the pixbuf to wrap in a #GtkIconInfo
*
- * Creates a #GtkIconInfo for a #GtkPixbuf.
+ * Creates a #GtkIconInfo for a #GdkPixbuf.
*
* Returns: a #GtkIconInfo
*
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 865b8d56be..bb6ba29100 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -46,7 +46,6 @@
#undef DEBUG_ICON_VIEW
#define SCROLL_EDGE_SIZE 15
-#define ITEM_PADDING 6
#define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
@@ -150,6 +149,7 @@ struct _GtkIconViewPrivate
gint row_spacing;
gint column_spacing;
gint margin;
+ gint item_padding;
gint text_column;
gint markup_column;
@@ -160,8 +160,6 @@ struct _GtkIconViewPrivate
gint tooltip_column;
- guint draw_focus : 1;
-
/* Drag-and-drop. */
GdkModifierType start_button_mask;
gint pressed_button;
@@ -186,7 +184,9 @@ struct _GtkIconViewPrivate
guint empty_view_drop :1;
guint ctrl_pressed : 1;
- guint shift_pressed : 1;
+ guint shift_pressed : 1;
+
+ guint draw_focus : 1;
};
/* Signals */
@@ -220,7 +220,8 @@ enum
PROP_COLUMN_SPACING,
PROP_MARGIN,
PROP_REORDERABLE,
- PROP_TOOLTIP_COLUMN
+ PROP_TOOLTIP_COLUMN,
+ PROP_ITEM_PADDING
};
/* GObject vfuncs */
@@ -714,7 +715,6 @@ gtk_icon_view_class_init (GtkIconViewClass *klass)
0, G_MAXINT, 6,
GTK_PARAM_READWRITE));
-
/**
* GtkIconView:orientation:
*
@@ -758,6 +758,22 @@ gtk_icon_view_class_init (GtkIconViewClass *klass)
-1,
GTK_PARAM_READWRITE));
+ /**
+ * GtkIconView:item-padding:
+ *
+ * The item-padding property specifies the padding around each
+ * of the icon view's item.
+ *
+ * Since: 2.18
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ITEM_PADDING,
+ g_param_spec_int ("item-padding",
+ P_("Item Padding"),
+ P_("Padding around icon view items"),
+ 0, G_MAXINT, 6,
+ GTK_PARAM_READWRITE));
+
/* Style properties */
@@ -1106,6 +1122,7 @@ gtk_icon_view_init (GtkIconView *icon_view)
icon_view->priv->row_spacing = 6;
icon_view->priv->column_spacing = 6;
icon_view->priv->margin = 6;
+ icon_view->priv->item_padding = 6;
icon_view->priv->draw_focus = TRUE;
}
@@ -1216,6 +1233,10 @@ gtk_icon_view_set_property (GObject *object,
gtk_icon_view_set_tooltip_column (icon_view, g_value_get_int (value));
break;
+ case PROP_ITEM_PADDING:
+ gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1277,6 +1298,10 @@ gtk_icon_view_get_property (GObject *object,
g_value_set_int (value, icon_view->priv->tooltip_column);
break;
+ case PROP_ITEM_PADDING:
+ g_value_set_int (value, icon_view->priv->item_padding);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -1418,10 +1443,10 @@ gtk_icon_view_allocate_children (GtkIconView *icon_view)
/* totally ignore our child's requisition */
if (child->cell < 0)
{
- allocation.x = child->item->x + ITEM_PADDING;
- allocation.y = child->item->y + ITEM_PADDING;
- allocation.width = child->item->width - ITEM_PADDING * 2;
- allocation.height = child->item->height - ITEM_PADDING * 2;
+ allocation.x = child->item->x + icon_view->priv->item_padding;
+ allocation.y = child->item->y + icon_view->priv->item_padding;
+ allocation.width = child->item->width - icon_view->priv->item_padding * 2;
+ allocation.height = child->item->height - icon_view->priv->item_padding * 2;
}
else
{
@@ -1520,6 +1545,11 @@ gtk_icon_view_expose (GtkWidget *widget,
if (expose->window != icon_view->priv->bin_window)
return FALSE;
+ /* If a layout has been scheduled, do it now so that all
+ * cell view items have valid sizes before we proceed. */
+ if (icon_view->priv->layout_idle_id != 0)
+ gtk_icon_view_layout (icon_view);
+
cr = gdk_cairo_create (icon_view->priv->bin_window);
cairo_set_line_width (cr, 1.);
@@ -2858,16 +2888,16 @@ gtk_icon_view_get_cell_area (GtkIconView *icon_view,
if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
cell_area->x = item->box[info->position].x - item->before[info->position];
- cell_area->y = item->y + ITEM_PADDING;
+ cell_area->y = item->y + icon_view->priv->item_padding;
cell_area->width = item->box[info->position].width +
item->before[info->position] + item->after[info->position];
- cell_area->height = item->height - ITEM_PADDING * 2;
+ cell_area->height = item->height - icon_view->priv->item_padding * 2;
}
else
{
- cell_area->x = item->x + ITEM_PADDING;
+ cell_area->x = item->x + icon_view->priv->item_padding;
cell_area->y = item->box[info->position].y - item->before[info->position];
- cell_area->width = item->width - ITEM_PADDING * 2;
+ cell_area->width = item->width - icon_view->priv->item_padding * 2;
cell_area->height = item->box[info->position].height +
item->before[info->position] + item->after[info->position];
}
@@ -2925,7 +2955,7 @@ adjust_wrap_width (GtkIconView *icon_view,
wrap_width = item_width - pixbuf_width - icon_view->priv->spacing;
}
- wrap_width -= ITEM_PADDING * 2;
+ wrap_width -= icon_view->priv->item_padding * 2;
g_object_set (text_info->cell, "wrap-width", wrap_width, NULL);
g_object_set (text_info->cell, "width", wrap_width, NULL);
@@ -2986,8 +3016,8 @@ gtk_icon_view_calculate_item_size (GtkIconView *icon_view,
}
}
- item->width += ITEM_PADDING * 2;
- item->height += ITEM_PADDING * 2;
+ item->width += icon_view->priv->item_padding * 2;
+ item->height += icon_view->priv->item_padding * 2;
}
static void
@@ -3016,8 +3046,8 @@ gtk_icon_view_calculate_item_size2 (GtkIconView *icon_view,
item->height += max_height[i] + (i > 0 ? spacing : 0);
}
- cell_area.x = item->x + ITEM_PADDING;
- cell_area.y = item->y + ITEM_PADDING;
+ cell_area.x = item->x + icon_view->priv->item_padding;
+ cell_area.y = item->y + icon_view->priv->item_padding;
for (k = 0; k < 2; k++)
for (l = icon_view->priv->cell_list, i = 0; l; l = l->next, i++)
@@ -3032,7 +3062,7 @@ gtk_icon_view_calculate_item_size2 (GtkIconView *icon_view,
if (icon_view->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- /* We should not subtract ITEM_PADDING from item->height,
+ /* We should not subtract icon_view->priv->item_padding from item->height,
* because item->height is recalculated above using
* max_height which does not contain item padding.
*/
@@ -3044,7 +3074,7 @@ gtk_icon_view_calculate_item_size2 (GtkIconView *icon_view,
/* item->width is not recalculated and thus needs to be
* corrected for the padding.
*/
- cell_area.width = item->width - 2 * ITEM_PADDING;
+ cell_area.width = item->width - 2 * icon_view->priv->item_padding;
cell_area.height = max_height[i];
}
@@ -3063,9 +3093,9 @@ gtk_icon_view_calculate_item_size2 (GtkIconView *icon_view,
}
else
{
- if (item->box[info->position].width > item->width - ITEM_PADDING * 2)
+ if (item->box[info->position].width > item->width - icon_view->priv->item_padding * 2)
{
- item->width = item->box[info->position].width + ITEM_PADDING * 2;
+ item->width = item->box[info->position].width + icon_view->priv->item_padding * 2;
cell_area.width = item->width;
}
item->before[info->position] = item->box[info->position].y - cell_area.y;
@@ -3083,7 +3113,7 @@ gtk_icon_view_calculate_item_size2 (GtkIconView *icon_view,
}
}
- item->height += ITEM_PADDING * 2;
+ item->height += icon_view->priv->item_padding * 2;
}
static void
@@ -3444,6 +3474,9 @@ gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
GList *items, *l;
GdkRectangle box;
+ if (cell_at_pos)
+ *cell_at_pos = NULL;
+
for (items = icon_view->priv->items; items; items = items->next)
{
GtkIconViewItem *item = items->data;
@@ -3458,12 +3491,12 @@ gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
for (l = icon_view->priv->cell_list; l; l = l->next)
{
GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
-
+
if (!info->cell->visible)
continue;
-
+
gtk_icon_view_get_cell_box (icon_view, item, info, &box);
-
+
if ((x >= box.x && x <= box.x + box.width &&
y >= box.y && y <= box.y + box.height) ||
(x >= box.x &&
@@ -3473,16 +3506,13 @@ gtk_icon_view_get_item_at_coords (GtkIconView *icon_view,
{
if (cell_at_pos)
*cell_at_pos = info;
-
+
return item;
}
}
if (only_in_cell)
return NULL;
-
- if (cell_at_pos)
- *cell_at_pos = NULL;
}
return item;
@@ -6239,6 +6269,51 @@ gtk_icon_view_get_margin (GtkIconView *icon_view)
return icon_view->priv->margin;
}
+/**
+ * gtk_icon_view_set_item_padding:
+ * @icon_view: a #GtkIconView
+ * @column_spacing: the item padding
+ *
+ * Sets the ::item-padding property which specifies the padding
+ * around each of the icon view's items.
+ *
+ * Since: 2.18
+ */
+void
+gtk_icon_view_set_item_padding (GtkIconView *icon_view,
+ gint item_padding)
+{
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (icon_view->priv->item_padding != item_padding)
+ {
+ icon_view->priv->item_padding = item_padding;
+
+ gtk_icon_view_stop_editing (icon_view, TRUE);
+ gtk_icon_view_invalidate_sizes (icon_view);
+ gtk_icon_view_queue_layout (icon_view);
+
+ g_object_notify (G_OBJECT (icon_view), "item-padding");
+ }
+}
+
+/**
+ * gtk_icon_view_get_item_padding:
+ * @icon_view: a #GtkIconView
+ *
+ * Returns the value of the ::item-padding property.
+ *
+ * Return value: the padding around items
+ *
+ * Since: 2.18
+ */
+gint
+gtk_icon_view_get_item_padding (GtkIconView *icon_view)
+{
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), -1);
+
+ return icon_view->priv->item_padding;
+}
/* Get/set whether drag_motion requested the drag data and
* drag_data_received should thus not actually insert the data,
@@ -7155,7 +7230,7 @@ gtk_icon_view_set_drag_dest_item (GtkIconView *icon_view,
/* special case a drop on an empty model */
icon_view->priv->empty_view_drop = FALSE;
- if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
+ if (pos == GTK_ICON_VIEW_DROP_ABOVE && path
&& gtk_tree_path_get_depth (path) == 1
&& gtk_tree_path_get_indices (path)[0] == 0)
{
diff --git a/gtk/gtkiconview.h b/gtk/gtkiconview.h
index 65b0588d24..7b9e51d227 100644
--- a/gtk/gtkiconview.h
+++ b/gtk/gtkiconview.h
@@ -125,6 +125,9 @@ gint gtk_icon_view_get_column_spacing (GtkIconView *icon_view);
void gtk_icon_view_set_margin (GtkIconView *icon_view,
gint margin);
gint gtk_icon_view_get_margin (GtkIconView *icon_view);
+void gtk_icon_view_set_item_padding (GtkIconView *icon_view,
+ gint item_padding);
+gint gtk_icon_view_get_item_padding (GtkIconView *icon_view);
GtkTreePath * gtk_icon_view_get_path_at_pos (GtkIconView *icon_view,
diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
index 036560f377..4d80267108 100644
--- a/gtk/gtkimage.c
+++ b/gtk/gtkimage.c
@@ -45,6 +45,7 @@ struct _GtkImagePrivate
gchar *filename;
gint pixel_size;
+ guint need_calc_size : 1;
};
#define GTK_IMAGE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_IMAGE, GtkImagePrivate))
@@ -1710,6 +1711,7 @@ gtk_image_expose (GtkWidget *widget,
{
GtkImage *image;
GtkMisc *misc;
+ GtkImagePrivate *priv;
GdkRectangle area, image_bound;
gfloat xalign;
gint x, y, mask_x, mask_y;
@@ -1719,6 +1721,7 @@ gtk_image_expose (GtkWidget *widget,
image = GTK_IMAGE (widget);
misc = GTK_MISC (widget);
+ priv = GTK_IMAGE_GET_PRIVATE (image);
area = event->area;
@@ -1727,7 +1730,7 @@ gtk_image_expose (GtkWidget *widget,
* and size_request() if something explicitely forces
* a redraw.
*/
- if (widget->requisition.width == 0 && widget->requisition.height == 0)
+ if (priv->need_calc_size)
gtk_image_calc_size (image);
if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
@@ -1737,7 +1740,7 @@ gtk_image_expose (GtkWidget *widget,
xalign = misc->xalign;
else
xalign = 1.0 - misc->xalign;
-
+
x = floor (widget->allocation.x + misc->xpad
+ ((widget->allocation.width - widget->requisition.width) * xalign));
y = floor (widget->allocation.y + misc->ypad
@@ -2149,8 +2152,13 @@ gtk_image_reset (GtkImage *image)
void
gtk_image_clear (GtkImage *image)
{
- gtk_image_reset (image);
+ GtkImagePrivate *priv;
+
+ priv = GTK_IMAGE_GET_PRIVATE (image);
+
+ priv->need_calc_size = 1;
+ gtk_image_reset (image);
gtk_image_update_size (image, 0, 0);
}
@@ -2159,7 +2167,12 @@ gtk_image_calc_size (GtkImage *image)
{
GtkWidget *widget = GTK_WIDGET (image);
GdkPixbuf *pixbuf = NULL;
-
+ GtkImagePrivate *priv;
+
+ priv = GTK_IMAGE_GET_PRIVATE (image);
+
+ priv->need_calc_size = 0;
+
/* We update stock/icon set on every size request, because
* the theme could have affected the size; for other kinds of
* image, we just update the requisition when the image data
diff --git a/gtk/gtkimagemenuitem.c b/gtk/gtkimagemenuitem.c
index 8948c9312a..7f0785d64e 100644
--- a/gtk/gtkimagemenuitem.c
+++ b/gtk/gtkimagemenuitem.c
@@ -615,7 +615,6 @@ gtk_image_menu_item_update (GtkActivatable *activatable,
const gchar *property_name)
{
GtkImageMenuItem *image_menu_item;
- GtkWidget *image;
gboolean use_appearance;
image_menu_item = GTK_IMAGE_MENU_ITEM (activatable);
diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
index 62bab7c0c9..523f771dab 100644
--- a/gtk/gtkimcontextsimple.c
+++ b/gtk/gtkimcontextsimple.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <gdk/gdkkeysyms.h>
+#include "gtkprivate.h"
#include "gtkaccelgroup.h"
#include "gtkimcontextsimple.h"
#include "gtksettings.h"
@@ -61,7 +62,7 @@ struct _GtkComposeTableCompact
static const GtkComposeTableCompact gtk_compose_table_compact = {
gtk_compose_seqs_compact,
5,
- 23,
+ 24,
6
};
@@ -595,7 +596,7 @@ check_algorithmically (GtkIMContextSimple *context_simple,
* with Ctrl-Shift-U, then release the modifiers before typing any
* digits, and enter the digits without modifiers.
*/
-#define HEX_MOD_MASK (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
+#define HEX_MOD_MASK (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)
static gboolean
check_hex (GtkIMContextSimple *context_simple,
diff --git a/gtk/gtkimcontextsimpleseqs.h b/gtk/gtkimcontextsimpleseqs.h
index 9e3fc29e99..131b3db6e1 100644
--- a/gtk/gtkimcontextsimpleseqs.h
+++ b/gtk/gtkimcontextsimpleseqs.h
@@ -18,10 +18,9 @@
*/
/*
- * File auto-generated from script found at gtk/compose-parse.py, with the --gtk parameter,
+ * File auto-generated from script found at http://bugzilla.gnome.org/show_bug.cgi?id=321896
* using the input files
* Input : http://gitweb.freedesktop.org/?p=xorg/lib/libX11.git;a=blob_plain;f=nls/en_US.UTF-8/Compose.pre
- * Input : http://svn.gnome.org/viewcvs/gtk%2B/trunk/gtk/gtk-compose-lookaside.txt
* Input : http://www.cl.cam.ac.uk/~mgk25/ucs/keysyms.txt
* Input : http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
*
@@ -68,29 +67,30 @@
*/
static const guint16 gtk_compose_seqs_compact[] = {
-GDK_dead_stroke, 138, 226, 235, 235, 235,
-GDK_Greek_accentdieresis, 235, 239, 239, 239, 239,
-GDK_dead_grave, 239, 299, 386, 598, 598,
-GDK_dead_acute, 598, 664, 760, 1036, 1036,
-GDK_dead_circumflex, 1036, 1176, 1176, 1376, 1376,
-GDK_dead_tilde, 1376, 1458, 1521, 1661, 1661,
-GDK_dead_macron, 1661, 1707, 1707, 1779, 1779,
-GDK_dead_breve, 1779, 1833, 1833, 1857, 1857,
-GDK_dead_abovedot, 1857, 1887, 1890, 1922, 1922,
-GDK_dead_diaeresis, 1922, 2010, 2019, 2043, 2043,
-GDK_dead_abovering, 2043, 2053, 2053, 2053, 2053,
-GDK_dead_doubleacute, 2053, 2063, 2063, 2063, 2063,
-GDK_dead_caron, 2063, 2089, 2089, 2097, 2097,
-GDK_dead_cedilla, 2097, 2111, 2111, 2111, 2111,
-GDK_dead_ogonek, 2111, 2121, 2121, 2121, 2121,
-GDK_dead_iota, 2121, 2143, 2242, 2674, 3334,
-GDK_dead_voiced_sound, 3334, 3380, 3380, 3380, 3380,
-GDK_dead_semivoiced_sound, 3380, 3390, 3390, 3390, 3390,
-GDK_dead_belowdot, 3390, 3400, 3400, 3416, 3416,
-GDK_dead_hook, 3416, 3494, 3494, 3550, 3550,
-GDK_dead_psili, 3550, 3578, 3578, 3578, 3578,
-GDK_dead_dasia, 3578, 3610, 3610, 3610, 3610,
-GDK_Multi_key, 3610, 3610, 9589, 13297, 15157,
+GDK_dead_stroke, 144, 232, 241, 241, 241,
+GDK_Greek_accentdieresis, 241, 245, 245, 245, 245,
+GDK_dead_grave, 245, 307, 394, 606, 606,
+GDK_dead_acute, 606, 674, 770, 1046, 1046,
+GDK_dead_circumflex, 1046, 1186, 1186, 1386, 1386,
+GDK_dead_tilde, 1386, 1470, 1533, 1673, 1673,
+GDK_dead_macron, 1673, 1719, 1719, 1791, 1791,
+GDK_dead_breve, 1791, 1845, 1845, 1869, 1869,
+GDK_dead_abovedot, 1869, 1899, 1902, 1934, 1934,
+GDK_dead_diaeresis, 1934, 2022, 2031, 2055, 2055,
+GDK_dead_abovering, 2055, 2065, 2065, 2065, 2065,
+GDK_dead_doubleacute, 2065, 2075, 2075, 2075, 2075,
+GDK_dead_caron, 2075, 2121, 2121, 2129, 2129,
+GDK_dead_cedilla, 2129, 2143, 2143, 2143, 2143,
+GDK_dead_ogonek, 2143, 2153, 2153, 2153, 2153,
+GDK_dead_iota, 2153, 2175, 2274, 2706, 3366,
+GDK_dead_voiced_sound, 3366, 3412, 3412, 3412, 3412,
+GDK_dead_semivoiced_sound, 3412, 3422, 3422, 3422, 3422,
+GDK_dead_belowdot, 3422, 3438, 3438, 3454, 3454,
+GDK_dead_hook, 3454, 3532, 3532, 3588, 3588,
+GDK_dead_horn, 3588, 3598, 3598, 3598, 3598,
+GDK_dead_psili, 3598, 3626, 3626, 3626, 3626,
+GDK_dead_dasia, 3626, 3658, 3658, 3658, 3658,
+GDK_Multi_key, 3658, 3658, 9658, 13366, 15231,
GDK_space, 0x002F,
GDK_2, 0x01BB,
GDK_A, 0x023A,
@@ -143,6 +143,7 @@ GDK_Greek_upsilon, 0x03B0,
GDK_space, 0x0060,
GDK_V, 0x01DB,
GDK_v, 0x01DC,
+GDK_nobreakspace, 0x0300,
GDK_Abreve, 0x1EB0,
GDK_abreve, 0x1EB1,
GDK_Emacron, 0x1E14,
@@ -255,6 +256,7 @@ GDK_Multi_key, GDK_macron, GDK_o, 0x1E51,
GDK_space, 0x0027,
GDK_V, 0x01D7,
GDK_v, 0x01D8,
+GDK_nobreakspace, 0x0301,
GDK_Abreve, 0x1EAE,
GDK_abreve, 0x1EAF,
GDK_Emacron, 0x1E16,
@@ -510,6 +512,7 @@ GDK_space, 0x007E,
GDK_less, 0x2272,
GDK_equal, 0x2243,
GDK_greater, 0x2273,
+GDK_nobreakspace, 0x0303,
GDK_Oacute, 0x1E4C,
GDK_Odiaeresis, 0x1E4E,
GDK_Uacute, 0x1E78,
@@ -769,6 +772,16 @@ GDK_parenleft, 0x208D,
GDK_parenright, 0x208E,
GDK_plus, 0x208A,
GDK_minus, 0x208B,
+GDK_0, 0x2080,
+GDK_1, 0x2081,
+GDK_2, 0x2082,
+GDK_3, 0x2083,
+GDK_4, 0x2084,
+GDK_5, 0x2085,
+GDK_6, 0x2086,
+GDK_7, 0x2087,
+GDK_8, 0x2088,
+GDK_9, 0x2088,
GDK_equal, 0x208C,
GDK_V, 0x01D9,
GDK_v, 0x01DA,
@@ -1103,11 +1116,14 @@ GDK_kana_HI, 0x30D4,
GDK_kana_FU, 0x30D7,
GDK_kana_HE, 0x30DA,
GDK_kana_HO, 0x30DD,
+GDK_space, 0x0323,
GDK_plus, 0x2A25,
GDK_minus, 0x2A2A,
GDK_equal, 0x2A66,
+GDK_nobreakspace, 0x0323,
GDK_Abreve, 0x1EB6,
GDK_abreve, 0x1EB7,
+GDK_dead_belowdot, 0x0323,
GDK_Multi_key, GDK_plus, GDK_O, 0x1EE2,
GDK_Multi_key, GDK_plus, GDK_U, 0x1EF0,
GDK_Multi_key, GDK_plus, GDK_o, 0x1EE3,
@@ -1165,6 +1181,11 @@ GDK_Multi_key, GDK_asciicircum, GDK_e, 0x1EC3,
GDK_Multi_key, GDK_asciicircum, GDK_o, 0x1ED5,
GDK_Multi_key, GDK_b, GDK_A, 0x1EB2,
GDK_Multi_key, GDK_b, GDK_a, 0x1EB3,
+GDK_space, 0x031B,
+GDK_nobreakspace, 0x031B,
+GDK_Utilde, 0x1EEE,
+GDK_utilde, 0x1EEF,
+GDK_dead_horn, 0x031B,
GDK_Greek_ALPHA, 0x1F08,
GDK_Greek_EPSILON, 0x1F18,
GDK_Greek_ETA, 0x1F28,
@@ -1368,7 +1389,7 @@ GDK_apostrophe, GDK_Idiaeresis, 0x1E2E,
GDK_apostrophe, GDK_Ocircumflex, 0x1ED0,
GDK_apostrophe, GDK_Otilde, 0x1E4C,
GDK_apostrophe, GDK_Ooblique, 0x01FE,
-GDK_apostrophe, 0x00DC, 0x01D7,
+GDK_apostrophe, GDK_Udiaeresis, 0x01D7,
GDK_apostrophe, GDK_acircumflex, 0x1EA5,
GDK_apostrophe, GDK_aring, 0x01FB,
GDK_apostrophe, GDK_ae, 0x01FD,
@@ -1529,6 +1550,7 @@ GDK_minus, GDK_parenright, 0x007D,
GDK_minus, GDK_plus, 0x00B1,
GDK_minus, GDK_comma, 0x00AC,
GDK_minus, GDK_colon, 0x00F7,
+GDK_minus, GDK_greater, 0x2192,
GDK_minus, GDK_A, 0x00C3,
GDK_minus, GDK_D, 0x0110,
GDK_minus, GDK_E, 0x0112,
@@ -1603,6 +1625,7 @@ GDK_period, 0x1E62, 0x1E68,
GDK_period, 0x1E63, 0x1E69,
GDK_slash, GDK_slash, 0x005C,
GDK_slash, GDK_less, 0x005C,
+GDK_slash, GDK_equal, 0x2260,
GDK_slash, GDK_C, 0x00A2,
GDK_slash, GDK_D, 0x0110,
GDK_slash, GDK_G, 0x01E4,
@@ -1682,8 +1705,11 @@ GDK_semicolon, GDK_u, 0x0173,
GDK_less, GDK_space, 0x02C7,
GDK_less, GDK_quotedbl, 0x201C,
GDK_less, GDK_apostrophe, 0x2018,
+GDK_less, GDK_minus, 0x2190,
GDK_less, GDK_slash, 0x005C,
+GDK_less, GDK_3, 0x2665,
GDK_less, GDK_less, 0x00AB,
+GDK_less, GDK_equal, 0x2264,
GDK_less, GDK_C, 0x010C,
GDK_less, GDK_D, 0x010E,
GDK_less, GDK_E, 0x011A,
@@ -1703,6 +1729,7 @@ GDK_less, GDK_s, 0x0161,
GDK_less, GDK_t, 0x0165,
GDK_less, GDK_z, 0x017E,
GDK_less, 0x0338, 0x226E,
+GDK_equal, GDK_slash, 0x2260,
GDK_equal, GDK_C, 0x20AC,
GDK_equal, GDK_E, 0x20AC,
GDK_equal, GDK_L, 0x00A3,
@@ -1725,6 +1752,7 @@ GDK_equal, GDK_Cyrillic_U, 0x04F2,
GDK_greater, GDK_space, 0x005E,
GDK_greater, GDK_quotedbl, 0x201D,
GDK_greater, GDK_apostrophe, 0x2019,
+GDK_greater, GDK_equal, 0x2265,
GDK_greater, GDK_greater, 0x00BB,
GDK_greater, GDK_A, 0x00C2,
GDK_greater, GDK_E, 0x00CA,
@@ -2068,7 +2096,7 @@ GDK_underscore, GDK_Adiaeresis, 0x01DE,
GDK_underscore, GDK_AE, 0x01E2,
GDK_underscore, GDK_Otilde, 0x022C,
GDK_underscore, GDK_Odiaeresis, 0x022A,
-GDK_underscore, 0x00DC, 0x01D5,
+GDK_underscore, GDK_Udiaeresis, 0x01D5,
GDK_underscore, GDK_adiaeresis, 0x01DF,
GDK_underscore, GDK_ae, 0x01E3,
GDK_underscore, GDK_otilde, 0x022D,
@@ -2128,7 +2156,7 @@ GDK_grave, GDK_y, 0x1EF3,
GDK_grave, GDK_Acircumflex, 0x1EA6,
GDK_grave, GDK_Ecircumflex, 0x1EC0,
GDK_grave, GDK_Ocircumflex, 0x1ED2,
-GDK_grave, 0x00DC, 0x01DB,
+GDK_grave, GDK_Udiaeresis, 0x01DB,
GDK_grave, GDK_acircumflex, 0x1EA7,
GDK_grave, GDK_ecircumflex, 0x1EC1,
GDK_grave, GDK_ocircumflex, 0x1ED3,
@@ -2279,7 +2307,7 @@ GDK_c, GDK_t, 0x0165,
GDK_c, GDK_u, 0x01D4,
GDK_c, GDK_z, 0x017E,
GDK_c, GDK_bar, 0x00A2,
-GDK_c, 0x00DC, 0x01D9,
+GDK_c, GDK_Udiaeresis, 0x01D9,
GDK_c, GDK_udiaeresis, 0x01DA,
GDK_c, 0x01B7, 0x01EE,
GDK_c, 0x0292, 0x01EF,
@@ -2517,7 +2545,7 @@ GDK_macron, GDK_Adiaeresis, 0x01DE,
GDK_macron, GDK_AE, 0x01E2,
GDK_macron, GDK_Otilde, 0x022C,
GDK_macron, GDK_Odiaeresis, 0x022A,
-GDK_macron, 0x00DC, 0x01D5,
+GDK_macron, GDK_Udiaeresis, 0x01D5,
GDK_macron, GDK_adiaeresis, 0x01DF,
GDK_macron, GDK_ae, 0x01E3,
GDK_macron, GDK_otilde, 0x022D,
@@ -2586,7 +2614,7 @@ GDK_acute, GDK_Idiaeresis, 0x1E2E,
GDK_acute, GDK_Ocircumflex, 0x1ED0,
GDK_acute, GDK_Otilde, 0x1E4C,
GDK_acute, GDK_Ooblique, 0x01FE,
-GDK_acute, 0x00DC, 0x01D7,
+GDK_acute, GDK_Udiaeresis, 0x01D7,
GDK_acute, GDK_acircumflex, 0x1EA5,
GDK_acute, GDK_aring, 0x01FB,
GDK_acute, GDK_ae, 0x01FD,
@@ -4320,6 +4348,7 @@ GDK_parenleft, GDK_KP_4, GDK_KP_7, GDK_parenright, 0x32BC,
GDK_parenleft, GDK_KP_4, GDK_KP_8, GDK_parenright, 0x32BD,
GDK_parenleft, GDK_KP_4, GDK_KP_9, GDK_parenright, 0x32BE,
GDK_parenleft, GDK_KP_5, GDK_KP_0, GDK_parenright, 0x32BF,
+GDK_C, GDK_C, GDK_C, GDK_P, 0x262D,
GDK_Greek_iota, GDK_apostrophe, GDK_parenleft, GDK_Greek_ALPHA, 0x1F8D,
GDK_Greek_iota, GDK_apostrophe, GDK_parenleft, GDK_Greek_ETA, 0x1F9D,
GDK_Greek_iota, GDK_apostrophe, GDK_parenleft, GDK_Greek_OMEGA, 0x1FAD,
diff --git a/gtk/gtkimmodule.c b/gtk/gtkimmodule.c
index 58ed584116..49eb2abc00 100644
--- a/gtk/gtkimmodule.c
+++ b/gtk/gtkimmodule.c
@@ -685,17 +685,13 @@ _gtk_im_module_get_default_context_id (GdkWindow *client_window)
if (GDK_IS_DRAWABLE (client_window))
{
screen = gdk_drawable_get_screen (GDK_DRAWABLE (client_window));
- if (screen)
- settings = gtk_settings_get_for_screen (screen);
- else
- settings = gtk_settings_get_default ();
-
+ settings = gtk_settings_get_for_screen (screen);
g_object_get (G_OBJECT (settings), "gtk-im-module", &tmp, NULL);
if (tmp)
{
if (strcmp (tmp, SIMPLE_ID) == 0)
context_id = SIMPLE_ID;
- else
+ else
{
GtkIMModule *module;
module = g_hash_table_lookup (contexts_hash, tmp);
@@ -704,7 +700,7 @@ _gtk_im_module_get_default_context_id (GdkWindow *client_window)
}
g_free (tmp);
- if (context_id)
+ if (context_id)
return context_id;
}
}
diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c
index 034582053d..2ec8b32582 100644
--- a/gtk/gtkimmulticontext.c
+++ b/gtk/gtkimmulticontext.c
@@ -220,23 +220,28 @@ gtk_im_multicontext_set_slave (GtkIMMulticontext *multicontext,
g_signal_emit_by_name (multicontext, "preedit-changed");
}
+static const gchar *
+get_effective_context_id (GtkIMMulticontext *multicontext)
+{
+ if (multicontext->priv->context_id)
+ return multicontext->priv->context_id;
+
+ if (!global_context_id)
+ global_context_id = _gtk_im_module_get_default_context_id (multicontext->priv->client_window);
+
+ return global_context_id;
+}
+
static GtkIMContext *
gtk_im_multicontext_get_slave (GtkIMMulticontext *multicontext)
{
if (!multicontext->slave)
{
GtkIMContext *slave;
-
+
g_free (multicontext->context_id);
-
- if (multicontext->priv->context_id)
- multicontext->context_id = g_strdup (multicontext->priv->context_id);
- else
- {
- if (!global_context_id)
- global_context_id = _gtk_im_module_get_default_context_id (multicontext->priv->client_window);
- multicontext->context_id = g_strdup (global_context_id);
- }
+
+ multicontext->context_id = g_strdup (get_effective_context_id (multicontext));
slave = _gtk_im_module_create (multicontext->context_id);
gtk_im_multicontext_set_slave (multicontext, slave, FALSE);
g_object_unref (slave);
@@ -264,28 +269,29 @@ gtk_im_multicontext_set_client_window (GtkIMContext *context,
multicontext->priv->client_window = window;
- gtk_im_multicontext_set_slave (multicontext, NULL, FALSE);
-
- if (window == NULL)
- return;
-
- screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
- if (screen)
- settings = gtk_settings_get_for_screen (screen);
- else
- settings = gtk_settings_get_default ();
-
- connected = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (settings),
- "gtk-im-module-connected"));
- if (!connected)
+ if (window)
{
- g_signal_connect (settings, "notify::gtk-im-module",
- G_CALLBACK (im_module_setting_changed), NULL);
- g_object_set_data (G_OBJECT (settings), "gtk-im-module-connected",
- GINT_TO_POINTER (TRUE));
+ screen = gdk_drawable_get_screen (GDK_DRAWABLE (window));
+ settings = gtk_settings_get_for_screen (screen);
- global_context_id = NULL;
+ connected = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (settings),
+ "gtk-im-module-connected"));
+ if (!connected)
+ {
+ g_signal_connect (settings, "notify::gtk-im-module",
+ G_CALLBACK (im_module_setting_changed), NULL);
+ g_object_set_data (G_OBJECT (settings), "gtk-im-module-connected",
+ GINT_TO_POINTER (TRUE));
+
+ global_context_id = NULL;
+ }
}
+
+ if (g_strcmp0 (multicontext->context_id, get_effective_context_id (multicontext)) != 0)
+ gtk_im_multicontext_set_slave (multicontext, NULL, FALSE);
+
+ if (multicontext->slave)
+ gtk_im_context_set_client_window (multicontext->slave, window);
}
static void
@@ -327,16 +333,7 @@ gtk_im_multicontext_focus_in (GtkIMContext *context)
GtkIMMulticontext *multicontext = GTK_IM_MULTICONTEXT (context);
GtkIMContext *slave;
- /* If the global context type is different from the context we were
- * using before, get rid of the old slave and create a new one
- * for the new global context type.
- */
- if (multicontext->context_id == NULL ||
- (multicontext->priv->context_id != NULL &&
- strcmp (multicontext->priv->context_id, multicontext->context_id) != 0) ||
- (multicontext->priv->context_id == NULL &&
- (global_context_id == NULL ||
- strcmp (global_context_id, multicontext->context_id) != 0)))
+ if (g_strcmp0 (multicontext->context_id, get_effective_context_id (multicontext)) != 0)
gtk_im_multicontext_set_slave (multicontext, NULL, FALSE);
slave = gtk_im_multicontext_get_slave (multicontext);
diff --git a/gtk/gtkinfobar.c b/gtk/gtkinfobar.c
index 9ada2c93a3..be1e875269 100644
--- a/gtk/gtkinfobar.c
+++ b/gtk/gtkinfobar.c
@@ -569,6 +569,11 @@ gtk_info_bar_update_colors (GtkInfoBar *info_bar)
fg = &other_default_border_color;
bg = &other_default_fill_color;
break;
+
+ default:
+ g_assert_not_reached();
+ fg = NULL;
+ bg = NULL;
}
}
diff --git a/gtk/gtkinputdialog.h b/gtk/gtkinputdialog.h
index 4c1647b992..6e95356bea 100644
--- a/gtk/gtkinputdialog.h
+++ b/gtk/gtkinputdialog.h
@@ -34,9 +34,7 @@
* distribution.
*/
-#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gtk/gtk.h> can be included directly."
-#endif
+#ifndef GTK_DISABLE_DEPRECATED
#ifndef __GTK_INPUTDIALOG_H__
#define __GTK_INPUTDIALOG_H__
@@ -92,11 +90,11 @@ struct _GtkInputDialogClass
void (*_gtk_reserved4) (void);
};
-
GType gtk_input_dialog_get_type (void) G_GNUC_CONST;
GtkWidget* gtk_input_dialog_new (void);
-
G_END_DECLS
#endif /* __GTK_INPUTDIALOG_H__ */
+
+#endif /* GTK_DISABLE_DEPRECATED */
diff --git a/gtk/gtkkeyhash.c b/gtk/gtkkeyhash.c
index 3de8830ebe..298f94c5d6 100644
--- a/gtk/gtkkeyhash.c
+++ b/gtk/gtkkeyhash.c
@@ -420,8 +420,8 @@ _gtk_key_hash_lookup (GtkKeyHash *key_hash,
xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK;
vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK;
- if ((entry->modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) ||
- (entry->modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods))
+ if ((entry->modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask & ~vmods) ||
+ (entry->modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask & ~xmods))
{
gint i;
@@ -430,7 +430,7 @@ _gtk_key_hash_lookup (GtkKeyHash *key_hash,
GTK_NOTE (KEYBINDINGS,
g_message (" found exact match, keyval = %u, modifiers = 0x%04x",
entry->keyval, entry->modifiers));
-
+
if (!have_exact)
{
g_slist_free (results);
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 4577eec3b1..acf7f53bfa 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -3841,6 +3841,7 @@ get_layout_index (GtkLabel *label,
gint trailing = 0;
const gchar *cluster;
const gchar *cluster_end;
+ gboolean inside;
*index = 0;
@@ -3851,24 +3852,21 @@ get_layout_index (GtkLabel *label,
x *= PANGO_SCALE;
y *= PANGO_SCALE;
- if (pango_layout_xy_to_index (label->layout,
- x, y,
- index, &trailing))
- {
- cluster = label->text + *index;
- cluster_end = cluster;
- while (trailing)
- {
- cluster_end = g_utf8_next_char (cluster_end);
- --trailing;
- }
-
- *index += (cluster_end - cluster);
+ inside = pango_layout_xy_to_index (label->layout,
+ x, y,
+ index, &trailing);
- return TRUE;
+ cluster = label->text + *index;
+ cluster_end = cluster;
+ while (trailing)
+ {
+ cluster_end = g_utf8_next_char (cluster_end);
+ --trailing;
}
- return FALSE;
+ *index += (cluster_end - cluster);
+
+ return inside;
}
static void
diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c
index 470c9f82b1..8ab1f18fbf 100644
--- a/gtk/gtkliststore.c
+++ b/gtk/gtkliststore.c
@@ -337,7 +337,6 @@ static void
gtk_list_store_set_n_columns (GtkListStore *list_store,
gint n_columns)
{
- GType *new_columns;
int i;
if (list_store->n_columns == n_columns)
@@ -494,10 +493,16 @@ static gboolean
gtk_list_store_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
+ gboolean retval;
+
g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
iter->user_data = g_sequence_iter_next (iter->user_data);
- return !g_sequence_iter_is_end (iter->user_data);
+ retval = g_sequence_iter_is_end (iter->user_data);
+ if (retval)
+ iter->stamp = 0;
+
+ return !retval;
}
static gboolean
@@ -509,7 +514,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
/* this is a list, nodes have no children */
if (parent)
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
if (g_sequence_get_length (list_store->seq) > 0)
{
@@ -518,7 +526,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model,
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
@@ -551,6 +562,8 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
GtkListStore *list_store = (GtkListStore *) tree_model;
GSequenceIter *child;
+ iter->stamp = 0;
+
if (parent)
return FALSE;
@@ -570,6 +583,7 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
+ iter->stamp = 0;
return FALSE;
}
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 11aee08fbc..bfee6da93b 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -686,6 +686,10 @@ do_post_parse_initialization (int *argc,
gettext_initialization ();
+#ifdef SIGPIPE
+ signal (SIGPIPE, SIG_IGN);
+#endif
+
if (g_fatal_warnings)
{
GLogLevelFlags fatal_mask;
@@ -845,9 +849,9 @@ gtk_get_option_group (gboolean open_default_display)
gboolean
gtk_init_with_args (int *argc,
char ***argv,
- char *parameter_string,
+ const char *parameter_string,
GOptionEntry *entries,
- char *translation_domain,
+ const char *translation_domain,
GError **error)
{
GOptionContext *context;
@@ -985,6 +989,15 @@ gtk_init_check (int *argc,
* the GUI for some reason. If you want your program to fall back to a
* textual interface you want to call gtk_init_check() instead.
* </para></note>
+ *
+ * <note><para>
+ * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
+ * during initialization, to ignore SIGPIPE signals, since these are
+ * almost never wanted in graphical applications. If you do need to
+ * handle SIGPIPE for some reason, reset the handler after gtk_init(),
+ * but notice that other libraries (e.g. libdbus or gvfs) might do
+ * similar things.
+ * </para></note>
**/
void
gtk_init (int *argc, char ***argv)
@@ -1559,7 +1572,15 @@ gtk_main_do_event (GdkEvent *event)
gdk_window_end_paint (event->any.window);
}
else
- gtk_widget_send_expose (event_widget, event);
+ {
+ /* The app may paint with a previously allocated cairo_t,
+ which will draw directly to the window. We can't catch cairo
+ drap operatoins to automatically flush the window, thus we
+ need to explicitly flush any outstanding moves or double
+ buffering */
+ gdk_window_flush (event->any.window);
+ gtk_widget_send_expose (event_widget, event);
+ }
break;
case GDK_PROPERTY_NOTIFY:
diff --git a/gtk/gtkmain.h b/gtk/gtkmain.h
index 975057e864..21de92ed42 100644
--- a/gtk/gtkmain.h
+++ b/gtk/gtkmain.h
@@ -99,9 +99,9 @@ gboolean gtk_init_check (int *argc,
gboolean gtk_init_with_args (int *argc,
char ***argv,
- char *parameter_string,
+ const char *parameter_string,
GOptionEntry *entries,
- char *translation_domain,
+ const char *translation_domain,
GError **error);
GOptionGroup *gtk_get_option_group (gboolean open_default_display);
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 533a266ced..77873cb022 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -111,3 +111,4 @@ VOID:UINT,STRING,UINT
VOID:UINT,UINT
VOID:VOID
OBJECT:OBJECT,INT,INT
+VOID:POINTER,POINTER,POINTER,POINTER,STRING
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 0fd5d3d4ad..0bdf1dea76 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -2730,6 +2730,11 @@ get_arrows_visible_area (GtkMenu *menu,
lower->width = (border->width - 2 * border->x) / 2;
lower->height = scroll_arrow_height;
break;
+
+ default:
+ g_assert_not_reached();
+ upper->x = upper->y = upper->width = upper->height = 0;
+ lower->x = lower->y = lower->width = lower->height = 0;
}
*arrow_space = scroll_arrow_height - 2 * widget->style->ythickness;
@@ -4172,7 +4177,6 @@ gtk_menu_position (GtkMenu *menu)
GtkRequisition requisition;
GtkMenuPrivate *private;
gint x, y;
- gboolean initially_pushed_in;
gint scroll_offset;
gint menu_height;
GdkScreen *screen;
diff --git a/gtk/gtkmountoperation-x11.c b/gtk/gtkmountoperation-x11.c
index d4efdaf84c..a20c8cf428 100644
--- a/gtk/gtkmountoperation-x11.c
+++ b/gtk/gtkmountoperation-x11.c
@@ -665,7 +665,7 @@ pid_get_env (GPid pid,
ret = g_strdup (env + n + key_len + 1);
/* skip invalid UTF-8 */
- if (!g_utf8_validate (ret, -1, (const gchar *) &end))
+ if (!g_utf8_validate (ret, -1, (const gchar **) &end))
*end = '\0';
break;
}
@@ -707,7 +707,7 @@ pid_get_command_line (GPid pid)
}
/* skip invalid UTF-8 */
- if (!g_utf8_validate (cmdline_contents, -1, (const gchar *) &end))
+ if (!g_utf8_validate (cmdline_contents, -1, (const gchar **) &end))
*end = '\0';
out:
@@ -861,6 +861,7 @@ get_pixbuf_for_window_with_pid (GtkMountOperationLookupContext *context,
static const gchar *well_known_commands[] =
{
+ /* translators: this string is a name for the 'less' command */
"less", N_("Terminal Pager"),
"top", N_("Top Command"),
"bash", N_("Bourne Again Shell"),
@@ -951,6 +952,8 @@ _gtk_mount_operation_kill_process (GPid pid,
if (kill ((pid_t) pid, SIGTERM) != 0)
{
+ int errsv = errno;
+
/* TODO: On EPERM, we could use a setuid helper using polkit (very easy to implement
* via pkexec(1)) to allow the user to e.g. authenticate to gain the authorization
* to kill the process. But that's not how things currently work.
@@ -959,10 +962,10 @@ _gtk_mount_operation_kill_process (GPid pid,
ret = FALSE;
g_set_error (error,
G_IO_ERROR,
- g_io_error_from_errno (errno),
+ g_io_error_from_errno (errsv),
_("Cannot end process with pid %d: %s"),
pid,
- strerror (errno));
+ g_strerror (errsv));
}
return ret;
diff --git a/gtk/gtkmountoperation.c b/gtk/gtkmountoperation.c
index 6137388c0b..4a1c9f8a8b 100644
--- a/gtk/gtkmountoperation.c
+++ b/gtk/gtkmountoperation.c
@@ -981,21 +981,22 @@ update_process_list_store (GtkMountOperation *mount_operation,
diff_sorted_arrays (current_pids, processes, pid_equal, pid_indices_to_add, pid_indices_to_remove);
- if (pid_indices_to_add->len > 0)
- lookup_context = _gtk_mount_operation_lookup_context_get (gtk_widget_get_display (mount_operation->priv->process_tree_view));
- for (n = 0; n < pid_indices_to_add->len; n++)
- {
- pid = g_array_index (processes, GPid, n);
- add_pid_to_process_list_store (mount_operation, lookup_context, list_store, pid);
- }
-
for (n = 0; n < pid_indices_to_remove->len; n++)
{
pid = g_array_index (current_pids, GPid, n);
remove_pid_from_process_list_store (mount_operation, list_store, pid);
}
+
if (pid_indices_to_add->len > 0)
- _gtk_mount_operation_lookup_context_free (lookup_context);
+ {
+ lookup_context = _gtk_mount_operation_lookup_context_get (gtk_widget_get_display (mount_operation->priv->process_tree_view));
+ for (n = 0; n < pid_indices_to_add->len; n++)
+ {
+ pid = g_array_index (processes, GPid, n);
+ add_pid_to_process_list_store (mount_operation, lookup_context, list_store, pid);
+ }
+ _gtk_mount_operation_lookup_context_free (lookup_context);
+ }
/* select the first item, if we went from a zero to a non-zero amount of processes */
if (current_pids->len == 0 && pid_indices_to_add->len > 0)
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index aa1a5ade06..e42e2fa7dc 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -3094,8 +3094,6 @@ static gint
gtk_notebook_focus_in (GtkWidget *widget,
GdkEventFocus *event)
{
- GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
-
gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
return FALSE;
@@ -3978,6 +3976,8 @@ gtk_notebook_set_focus_child (GtkContainer *container,
}
}
}
+ else
+ notebook->child_has_focus = FALSE;
GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
}
@@ -5799,9 +5799,14 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
GtkNotebookPage *page,
guint page_num)
{
+ gboolean child_has_focus;
+
if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
return;
+ /* save the value here, changing visibility changes focus */
+ child_has_focus = notebook->child_has_focus;
+
if (notebook->cur_page)
gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
@@ -5818,7 +5823,7 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
* element on the new page, if possible, or if not, to the
* notebook itself.
*/
- if (notebook->child_has_focus)
+ if (child_has_focus)
{
if (notebook->cur_page->last_focus_child &&
gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
@@ -7193,6 +7198,8 @@ gtk_notebook_child_reordered (GtkNotebook *notebook,
* Sets the packing parameters for the tab label of the page
* containing @child. See gtk_box_pack_start() for the exact meaning
* of the parameters.
+ *
+ * Deprecated: 2.20: Modify the "expand" and "fill" child properties instead.
**/
void
gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
@@ -7244,6 +7251,8 @@ gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
*
* Query the packing attributes for the tab label of the page
* containing @child.
+ *
+ * Deprecated: 2.20: Modify the "expand" and "fill" child properties instead.
**/
void
gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h
index 0659cc92d2..41bbe66979 100644
--- a/gtk/gtknotebook.h
+++ b/gtk/gtknotebook.h
@@ -261,6 +261,7 @@ void gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
const gchar *menu_text);
G_CONST_RETURN gchar *gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
GtkWidget *child);
+#ifndef GTK_DISABLE_DEPRECATED
void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
GtkWidget *child,
gboolean *expand,
@@ -271,6 +272,7 @@ void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
gboolean expand,
gboolean fill,
GtkPackType pack_type);
+#endif
void gtk_notebook_reorder_child (GtkNotebook *notebook,
GtkWidget *child,
gint position);
diff --git a/gtk/gtkpagesetupunixdialog.c b/gtk/gtkpagesetupunixdialog.c
index 0fae189579..1e903391d9 100644
--- a/gtk/gtkpagesetupunixdialog.c
+++ b/gtk/gtkpagesetupunixdialog.c
@@ -146,7 +146,7 @@ gtk_page_setup_unix_dialog_class_init (GtkPageSetupUnixDialogClass *class)
object_class->finalize = gtk_page_setup_unix_dialog_finalize;
- g_type_class_add_private (class, sizeof (GtkPageSetupUnixDialogPrivate));
+ g_type_class_add_private (class, sizeof (GtkPageSetupUnixDialogPrivate));
}
static void
@@ -154,21 +154,24 @@ gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
{
GtkPageSetupUnixDialogPrivate *priv;
GtkTreeIter iter;
+ gchar *tmp;
priv = dialog->priv = GTK_PAGE_SETUP_UNIX_DIALOG_GET_PRIVATE (dialog);
priv->print_backends = NULL;
priv->printer_list = gtk_list_store_new (PRINTER_LIST_N_COLS,
- G_TYPE_STRING,
+ G_TYPE_STRING,
G_TYPE_OBJECT);
gtk_list_store_append (priv->printer_list, &iter);
+ tmp = g_strdup_printf ("<b>%s</b>\n%s", _("Any Printer"), _("For portable documents"));
gtk_list_store_set (priv->printer_list, &iter,
- PRINTER_LIST_COL_NAME, _("<b>Any Printer</b>\nFor portable documents"),
+ PRINTER_LIST_COL_NAME, tmp,
PRINTER_LIST_COL_PRINTER, NULL,
-1);
-
+ g_free (tmp);
+
priv->page_setup_list = gtk_list_store_new (PAGE_SETUP_LIST_N_COLS,
G_TYPE_OBJECT,
G_TYPE_BOOLEAN);
@@ -260,7 +263,7 @@ printer_added_cb (GtkPrintBackend *backend,
GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
GtkTreeIter iter;
gchar *str;
- const gchar *location;;
+ const gchar *location;
if (gtk_printer_is_virtual (printer))
return;
@@ -271,18 +274,17 @@ printer_added_cb (GtkPrintBackend *backend,
str = g_strdup_printf ("<b>%s</b>\n%s",
gtk_printer_get_name (printer),
location);
-
+
gtk_list_store_append (priv->printer_list, &iter);
gtk_list_store_set (priv->printer_list, &iter,
PRINTER_LIST_COL_NAME, str,
PRINTER_LIST_COL_PRINTER, printer,
-1);
- g_object_set_data_full (G_OBJECT (printer),
- "gtk-print-tree-iter",
+ g_object_set_data_full (G_OBJECT (printer),
+ "gtk-print-tree-iter",
gtk_tree_iter_copy (&iter),
(GDestroyNotify) gtk_tree_iter_free);
-
g_free (str);
if (priv->waiting_for_printer != NULL &&
@@ -316,7 +318,7 @@ printer_status_cb (GtkPrintBackend *backend,
GtkPageSetupUnixDialogPrivate *priv = dialog->priv;
GtkTreeIter *iter;
gchar *str;
- const gchar *location;;
+ const gchar *location;
iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
diff --git a/gtk/gtkprintbackend.c b/gtk/gtkprintbackend.c
index 567273bdd7..3c64823ebe 100644
--- a/gtk/gtkprintbackend.c
+++ b/gtk/gtkprintbackend.c
@@ -50,9 +50,8 @@ struct _GtkPrintBackendPrivate
guint printer_list_requested : 1;
guint printer_list_done : 1;
GtkPrintBackendStatus status;
- char *hostname;
- char *username;
- char *password;
+ char **auth_info_required;
+ char **auth_info;
};
enum {
@@ -359,8 +358,10 @@ static GList * fallback_printer_list_papers (GtkPrinter
static GtkPageSetup * fallback_printer_get_default_page_size (GtkPrinter *printer);
static GtkPrintCapabilities fallback_printer_get_capabilities (GtkPrinter *printer);
static void request_password (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
+ gpointer auth_info_required,
+ gpointer auth_info_default,
+ gpointer auth_info_display,
+ gpointer auth_info_visible,
const gchar *prompt);
static void
@@ -441,8 +442,8 @@ gtk_print_backend_class_init (GtkPrintBackendClass *class)
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkPrintBackendClass, request_password),
NULL, NULL,
- _gtk_marshal_VOID__STRING_STRING_STRING,
- G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ _gtk_marshal_VOID__POINTER_POINTER_POINTER_POINTER_STRING,
+ G_TYPE_NONE, 5, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING);
}
static void
@@ -455,9 +456,8 @@ gtk_print_backend_init (GtkPrintBackend *backend)
priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_object_unref);
- priv->hostname = NULL;
- priv->username = NULL;
- priv->password = NULL;
+ priv->auth_info_required = NULL;
+ priv->auth_info = NULL;
}
static void
@@ -662,40 +662,29 @@ gtk_print_backend_print_stream (GtkPrintBackend *backend,
}
void
-gtk_print_backend_set_password (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
- const gchar *password)
+gtk_print_backend_set_password (GtkPrintBackend *backend,
+ gchar **auth_info_required,
+ gchar **auth_info)
{
g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
if (GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password)
- GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, hostname, username, password);
+ GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, auth_info_required, auth_info);
}
static void
-store_password (GtkEntry *entry,
- GtkPrintBackend *backend)
+store_entry (GtkEntry *entry,
+ gpointer user_data)
{
- GtkPrintBackendPrivate *priv = backend->priv;
+ gchar **data = (gchar **) user_data;
- if (priv->password != NULL)
+ if (*data != NULL)
{
- memset (priv->password, 0, strlen (priv->password));
- g_free (priv->password);
+ memset (*data, 0, strlen (*data));
+ g_free (*data);
}
- priv->password = g_strdup (gtk_entry_get_text (entry));
-}
-
-static void
-store_username (GtkEntry *entry,
- GtkPrintBackend *backend)
-{
- GtkPrintBackendPrivate *priv = backend->priv;
-
- g_free (priv->username);
- priv->username = g_strdup (gtk_entry_get_text (entry));
+ *data = g_strdup (gtk_entry_get_text (entry));
}
static void
@@ -704,21 +693,24 @@ password_dialog_response (GtkWidget *dialog,
GtkPrintBackend *backend)
{
GtkPrintBackendPrivate *priv = backend->priv;
+ gint i;
if (response_id == GTK_RESPONSE_OK)
- gtk_print_backend_set_password (backend, priv->hostname, priv->username, priv->password);
+ gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info);
else
- gtk_print_backend_set_password (backend, priv->hostname, priv->username, NULL);
+ gtk_print_backend_set_password (backend, priv->auth_info_required, NULL);
- if (priv->password != NULL)
- {
- memset (priv->password, 0, strlen (priv->password));
- g_free (priv->password);
- priv->password = NULL;
- }
+ for (i = 0; i < g_strv_length (priv->auth_info_required); i++)
+ if (priv->auth_info[i] != NULL)
+ {
+ memset (priv->auth_info[i], 0, strlen (priv->auth_info[i]));
+ g_free (priv->auth_info[i]);
+ priv->auth_info[i] = NULL;
+ }
+ g_free (priv->auth_info);
+ priv->auth_info = NULL;
- g_free (priv->username);
- priv->username = NULL;
+ g_strfreev (priv->auth_info_required);
gtk_widget_destroy (dialog);
@@ -726,16 +718,27 @@ password_dialog_response (GtkWidget *dialog,
}
static void
-request_password (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
- const gchar *prompt)
+request_password (GtkPrintBackend *backend,
+ gpointer auth_info_required,
+ gpointer auth_info_default,
+ gpointer auth_info_display,
+ gpointer auth_info_visible,
+ const gchar *prompt)
{
GtkPrintBackendPrivate *priv = backend->priv;
- GtkWidget *dialog, *username_box, *password_box, *main_box, *label, *icon, *vbox,
- *password_prompt, *username_prompt,
- *password_entry, *username_entry;
+ GtkWidget *dialog, *box, *main_box, *label, *icon, *vbox, *entry;
+ GtkWidget *focus = NULL;
gchar *markup;
+ gint length;
+ gint i;
+ gchar **ai_required = (gchar **) auth_info_required;
+ gchar **ai_default = (gchar **) auth_info_default;
+ gchar **ai_display = (gchar **) auth_info_display;
+ gboolean *ai_visible = (gboolean *) auth_info_visible;
+
+ priv->auth_info_required = g_strdupv (ai_required);
+ length = g_strv_length (ai_required);
+ priv->auth_info = g_new0 (gchar *, length);
dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
@@ -766,27 +769,6 @@ request_password (GtkPrintBackend *backend,
g_free (markup);
- /* Right - 2. */
- username_box = gtk_hbox_new (TRUE, 0);
-
- username_prompt = gtk_label_new (_("Username:"));
- gtk_misc_set_alignment (GTK_MISC (username_prompt), 0.0, 0.5);
-
- username_entry = gtk_entry_new ();
- gtk_entry_set_text (GTK_ENTRY (username_entry), username);
-
-
- /* Right - 3. */
- password_box = gtk_hbox_new (TRUE, 0);
-
- password_prompt = gtk_label_new (_("Password:"));
- gtk_misc_set_alignment (GTK_MISC (password_prompt), 0.0, 0.5);
-
- password_entry = gtk_entry_new ();
- gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
- gtk_entry_set_activates_default (GTK_ENTRY (password_entry), TRUE);
-
-
/* Packing */
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_box, TRUE, FALSE, 0);
@@ -794,26 +776,42 @@ request_password (GtkPrintBackend *backend,
gtk_box_pack_start (GTK_BOX (main_box), vbox, FALSE, FALSE, 6);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 6);
- gtk_box_pack_start (GTK_BOX (vbox), username_box, FALSE, TRUE, 6);
- gtk_box_pack_start (GTK_BOX (vbox), password_box, FALSE, TRUE, 6);
+
+ /* Right - 2. */
+ for (i = 0; i < length; i++)
+ {
+ priv->auth_info[i] = g_strdup (ai_default[i]);
+ if (ai_display[i] != NULL)
+ {
+ box = gtk_hbox_new (TRUE, 0);
+
+ label = gtk_label_new (ai_display[i]);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (username_box), username_prompt, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (username_box), username_entry, TRUE, TRUE, 0);
+ entry = gtk_entry_new ();
+ focus = entry;
- gtk_box_pack_start (GTK_BOX (password_box), password_prompt, TRUE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (password_box), password_entry, TRUE, TRUE, 0);
+ if (ai_default[i] != NULL)
+ gtk_entry_set_text (GTK_ENTRY (entry), ai_default[i]);
+ gtk_entry_set_visibility (GTK_ENTRY (entry), ai_visible[i]);
+ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
- gtk_widget_grab_focus (password_entry);
+ gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 6);
- priv->hostname = g_strdup (hostname);
- priv->username = g_strdup (username);
+ gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0);
- g_signal_connect (password_entry, "changed",
- G_CALLBACK (store_password), backend);
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (store_entry), &(priv->auth_info[i]));
+ }
+ }
- g_signal_connect (username_entry, "changed",
- G_CALLBACK (store_username), backend);
+ if (focus != NULL)
+ {
+ gtk_widget_grab_focus (focus);
+ focus = NULL;
+ }
g_object_ref (backend);
g_signal_connect (G_OBJECT (dialog), "response",
diff --git a/gtk/gtkprintbackend.h b/gtk/gtkprintbackend.h
index 7d75f8e417..c4b43b10d2 100644
--- a/gtk/gtkprintbackend.h
+++ b/gtk/gtkprintbackend.h
@@ -121,15 +121,16 @@ struct _GtkPrintBackendClass
void (*printer_status_changed) (GtkPrintBackend *backend,
GtkPrinter *printer);
void (*request_password) (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
+ gpointer auth_info_required,
+ gpointer auth_info_default,
+ gpointer auth_info_display,
+ gpointer auth_info_visible,
const gchar *prompt);
/* not a signal */
void (*set_password) (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
- const gchar *password);
+ gchar **auth_info_required,
+ gchar **auth_info);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
@@ -153,9 +154,8 @@ void gtk_print_backend_print_stream (GtkPrintBackend *pri
GList * gtk_print_backend_load_modules (void);
void gtk_print_backend_destroy (GtkPrintBackend *print_backend);
void gtk_print_backend_set_password (GtkPrintBackend *backend,
- const gchar *hostname,
- const gchar *username,
- const gchar *password);
+ gchar **auth_info_required,
+ gchar **auth_info);
/* Backend-only functions for GtkPrintBackend */
diff --git a/gtk/gtkprintcontext.c b/gtk/gtkprintcontext.c
index c280881f80..80eac79fa7 100644
--- a/gtk/gtkprintcontext.c
+++ b/gtk/gtkprintcontext.c
@@ -177,11 +177,11 @@ _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
case GTK_PAGE_ORIENTATION_PORTRAIT:
break;
case GTK_PAGE_ORIENTATION_LANDSCAPE:
- cairo_translate (cr, width, 0);
+ cairo_translate (cr, 0, height);
cairo_matrix_init (&matrix,
- 0, 1,
- -1, 0,
- 0, 0);
+ 0, -1,
+ 1, 0,
+ 0, 0);
cairo_transform (cr, &matrix);
break;
case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
@@ -193,11 +193,11 @@ _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
cairo_transform (cr, &matrix);
break;
case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
- cairo_translate (cr, 0, height);
+ cairo_translate (cr, width, 0);
cairo_matrix_init (&matrix,
- 0, -1,
- 1, 0,
- 0, 0);
+ 0, 1,
+ -1, 0,
+ 0, 0);
cairo_transform (cr, &matrix);
break;
}
diff --git a/gtk/gtkprinteroption.c b/gtk/gtkprinteroption.c
index 983dc65d56..47fcd32755 100644
--- a/gtk/gtkprinteroption.c
+++ b/gtk/gtkprinteroption.c
@@ -63,6 +63,7 @@ static void
gtk_printer_option_init (GtkPrinterOption *option)
{
option->value = g_strdup ("");
+ option->activates_default = FALSE;
}
static void
@@ -215,6 +216,23 @@ gtk_printer_option_has_choice (GtkPrinterOption *option,
return FALSE;
}
+void
+gtk_printer_option_set_activates_default (GtkPrinterOption *option,
+ gboolean activates)
+{
+ g_return_if_fail (GTK_IS_PRINTER_OPTION (option));
+
+ option->activates_default = activates;
+}
+
+gboolean
+gtk_printer_option_get_activates_default (GtkPrinterOption *option)
+{
+ g_return_val_if_fail (GTK_IS_PRINTER_OPTION (option), FALSE);
+
+ return option->activates_default;
+}
+
#define __GTK_PRINTER_OPTION_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkprinteroption.h b/gtk/gtkprinteroption.h
index cce6986960..f1831a31c2 100644
--- a/gtk/gtkprinteroption.h
+++ b/gtk/gtkprinteroption.h
@@ -70,6 +70,8 @@ struct _GtkPrinterOption
char **choices;
char **choices_display;
+ gboolean activates_default;
+
gboolean has_conflict;
char *group;
};
@@ -92,24 +94,27 @@ struct _GtkPrinterOptionClass
GType gtk_printer_option_get_type (void) G_GNUC_CONST;
-GtkPrinterOption *gtk_printer_option_new (const char *name,
- const char *display_text,
- GtkPrinterOptionType type);
-void gtk_printer_option_set (GtkPrinterOption *option,
- const char *value);
-void gtk_printer_option_set_has_conflict (GtkPrinterOption *option,
- gboolean has_conflict);
-void gtk_printer_option_clear_has_conflict (GtkPrinterOption *option);
-void gtk_printer_option_set_boolean (GtkPrinterOption *option,
- gboolean value);
-void gtk_printer_option_allocate_choices (GtkPrinterOption *option,
- int num);
-void gtk_printer_option_choices_from_array (GtkPrinterOption *option,
- int num_choices,
- char *choices[],
- char *choices_display[]);
-gboolean gtk_printer_option_has_choice (GtkPrinterOption *option,
- const char *choice);
+GtkPrinterOption *gtk_printer_option_new (const char *name,
+ const char *display_text,
+ GtkPrinterOptionType type);
+void gtk_printer_option_set (GtkPrinterOption *option,
+ const char *value);
+void gtk_printer_option_set_has_conflict (GtkPrinterOption *option,
+ gboolean has_conflict);
+void gtk_printer_option_clear_has_conflict (GtkPrinterOption *option);
+void gtk_printer_option_set_boolean (GtkPrinterOption *option,
+ gboolean value);
+void gtk_printer_option_allocate_choices (GtkPrinterOption *option,
+ int num);
+void gtk_printer_option_choices_from_array (GtkPrinterOption *option,
+ int num_choices,
+ char *choices[],
+ char *choices_display[]);
+gboolean gtk_printer_option_has_choice (GtkPrinterOption *option,
+ const char *choice);
+void gtk_printer_option_set_activates_default (GtkPrinterOption *option,
+ gboolean activates);
+gboolean gtk_printer_option_get_activates_default (GtkPrinterOption *option);
G_END_DECLS
diff --git a/gtk/gtkprinteroptionwidget.c b/gtk/gtkprinteroptionwidget.c
index 38cdf00801..468768fb33 100644
--- a/gtk/gtkprinteroptionwidget.c
+++ b/gtk/gtkprinteroptionwidget.c
@@ -767,6 +767,8 @@ construct_widgets (GtkPrinterOptionWidget *widget)
case GTK_PRINTER_OPTION_TYPE_STRING:
priv->entry = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
+ gtk_printer_option_get_activates_default (source));
gtk_widget_show (priv->entry);
gtk_box_pack_start (GTK_BOX (widget), priv->entry, TRUE, TRUE, 0);
g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed_cb), widget);
@@ -792,6 +794,8 @@ construct_widgets (GtkPrinterOptionWidget *widget)
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
g_object_set (priv->combo, "local-only", FALSE, NULL);
+ gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
+ gtk_printer_option_get_activates_default (source));
label = gtk_label_new_with_mnemonic (_("_Name:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
@@ -850,7 +854,7 @@ update_widgets (GtkPrinterOptionWidget *widget)
switch (source->type)
{
case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
- if (strcmp (source->value, "True") == 0)
+ if (g_ascii_strcasecmp (source->value, "True") == 0)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), TRUE);
else
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), FALSE);
diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c
index c31f324acb..6b5aa15fc5 100644
--- a/gtk/gtkprintoperation-unix.c
+++ b/gtk/gtkprintoperation-unix.c
@@ -91,9 +91,26 @@ unix_start_page (GtkPrintOperation *op,
(op->priv->page_position % op->priv->manual_number_up == 0))
{
if (type == CAIRO_SURFACE_TYPE_PS)
- cairo_ps_surface_set_size (op_unix->surface, w, h);
+ {
+ cairo_ps_surface_set_size (op_unix->surface, w, h);
+ cairo_ps_surface_dsc_begin_page_setup (op_unix->surface);
+ switch (gtk_page_setup_get_orientation (page_setup))
+ {
+ case GTK_PAGE_ORIENTATION_PORTRAIT:
+ case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
+ cairo_ps_surface_dsc_comment (op_unix->surface, "%%PageOrientation: Portrait");
+ break;
+
+ case GTK_PAGE_ORIENTATION_LANDSCAPE:
+ case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
+ cairo_ps_surface_dsc_comment (op_unix->surface, "%%PageOrientation: Landscape");
+ break;
+ }
+ }
else if (type == CAIRO_SURFACE_TYPE_PDF)
- cairo_pdf_surface_set_size (op_unix->surface, w, h);
+ {
+ cairo_pdf_surface_set_size (op_unix->surface, w, h);
+ }
}
}
@@ -190,7 +207,7 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
gchar *cmd;
gchar *preview_cmd;
GtkSettings *settings;
- GtkPrintSettings *print_settings;
+ GtkPrintSettings *print_settings = NULL;
GtkPageSetup *page_setup;
GKeyFile *key_file = NULL;
gchar *data = NULL;
@@ -218,8 +235,28 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
key_file = g_key_file_new ();
- print_settings = gtk_print_operation_get_print_settings (op);
- gtk_print_settings_to_key_file (print_settings, key_file, NULL);
+ print_settings = gtk_print_settings_copy (gtk_print_operation_get_print_settings (op));
+
+ if (print_settings != NULL)
+ {
+ gtk_print_settings_set_reverse (print_settings, FALSE);
+ gtk_print_settings_set_page_set (print_settings, GTK_PAGE_SET_ALL);
+ gtk_print_settings_set_scale (print_settings, 1.0);
+ gtk_print_settings_set_number_up (print_settings, 1);
+ gtk_print_settings_set_number_up_layout (print_settings, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
+
+ /* These removals are neccessary because cups-* settings have higher priority
+ * than normal settings.
+ */
+ gtk_print_settings_unset (print_settings, "cups-reverse");
+ gtk_print_settings_unset (print_settings, "cups-page-set");
+ gtk_print_settings_unset (print_settings, "cups-scale");
+ gtk_print_settings_unset (print_settings, "cups-number-up");
+ gtk_print_settings_unset (print_settings, "cups-number-up-layout");
+
+ gtk_print_settings_to_key_file (print_settings, key_file, NULL);
+ g_object_unref (print_settings);
+ }
page_setup = gtk_print_context_get_page_setup (op->priv->print_context);
gtk_page_setup_to_key_file (page_setup, key_file, NULL);
@@ -372,9 +409,9 @@ job_status_changed_cb (GtkPrintJob *job,
static void
-printer_changed_cb (GtkPrintUnixDialog *print_dialog,
- GParamSpec *pspec,
- gpointer user_data)
+print_setup_changed_cb (GtkPrintUnixDialog *print_dialog,
+ GParamSpec *pspec,
+ gpointer user_data)
{
GtkPageSetup *page_setup;
GtkPrintSettings *print_settings;
@@ -450,7 +487,8 @@ get_print_dialog (GtkPrintOperation *op,
gtk_print_unix_dialog_add_custom_tab (GTK_PRINT_UNIX_DIALOG (pd),
priv->custom_widget, label);
- g_signal_connect (pd, "notify::selected-printer", (GCallback) printer_changed_cb, op);
+ g_signal_connect (pd, "notify::selected-printer", (GCallback) print_setup_changed_cb, op);
+ g_signal_connect (pd, "notify::page-setup", (GCallback) print_setup_changed_cb, op);
}
return pd;
diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c
index 3da48cb708..b7210f0d8b 100644
--- a/gtk/gtkprintoperation-win32.c
+++ b/gtk/gtkprintoperation-win32.c
@@ -444,6 +444,7 @@ win32_start_page (GtkPrintOperation *op,
GtkPrintOperationWin32 *op_win32 = op->priv->platform_data;
LPDEVMODEW devmode;
GtkPaperSize *paper_size;
+ double x_off, y_off;
devmode = GlobalLock (op_win32->devmode);
@@ -468,6 +469,10 @@ win32_start_page (GtkPrintOperation *op,
ResetDCW (op_win32->hdc, devmode);
GlobalUnlock (op_win32->devmode);
+
+ x_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETX);
+ y_off = GetDeviceCaps (op_win32->hdc, PHYSICALOFFSETY);
+ cairo_surface_set_device_offset (op_win32->surface, -x_off, -y_off);
StartPage (op_win32->hdc);
}
diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c
index 765e7d0b25..9e7b58137c 100644
--- a/gtk/gtkprintoperation.c
+++ b/gtk/gtkprintoperation.c
@@ -70,16 +70,23 @@ enum
PROP_STATUS,
PROP_STATUS_STRING,
PROP_CUSTOM_TAB_LABEL,
- PROP_EMBED_PAGE_SETUP
+ PROP_EMBED_PAGE_SETUP,
+ PROP_HAS_SELECTION,
+ PROP_SUPPORT_SELECTION,
+ PROP_N_PAGES_TO_PRINT
};
static guint signals[LAST_SIGNAL] = { 0 };
static int job_nr = 0;
+typedef struct _PrintPagesData PrintPagesData;
-static void preview_iface_init (GtkPrintOperationPreviewIface *iface);
-static GtkPageSetup *create_page_setup (GtkPrintOperation *op);
-static void common_render_page (GtkPrintOperation *op,
- gint page_nr);
+static void preview_iface_init (GtkPrintOperationPreviewIface *iface);
+static GtkPageSetup *create_page_setup (GtkPrintOperation *op);
+static void common_render_page (GtkPrintOperation *op,
+ gint page_nr);
+static void increment_page_sequence (PrintPagesData *data);
+static void prepare_data (PrintPagesData *data);
+static void clamp_page_ranges (PrintPagesData *data);
G_DEFINE_TYPE_WITH_CODE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT,
@@ -257,13 +264,23 @@ preview_start_page (GtkPrintOperation *op,
GtkPrintContext *print_context,
GtkPageSetup *page_setup)
{
- g_signal_emit_by_name (op, "got-page-size", print_context, page_setup);
+ if ((op->priv->manual_number_up < 2) ||
+ (op->priv->page_position % op->priv->manual_number_up == 0))
+ g_signal_emit_by_name (op, "got-page-size", print_context, page_setup);
}
static void
preview_end_page (GtkPrintOperation *op,
GtkPrintContext *print_context)
{
+ cairo_t *cr;
+
+ cr = gtk_print_context_get_cairo_context (print_context);
+
+ if ((op->priv->manual_number_up < 2) ||
+ ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
+ (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
+ cairo_show_page (cr);
}
static void
@@ -325,6 +342,12 @@ gtk_print_operation_set_property (GObject *object,
case PROP_EMBED_PAGE_SETUP:
gtk_print_operation_set_embed_page_setup (op, g_value_get_boolean (value));
break;
+ case PROP_HAS_SELECTION:
+ gtk_print_operation_set_has_selection (op, g_value_get_boolean (value));
+ break;
+ case PROP_SUPPORT_SELECTION:
+ gtk_print_operation_set_support_selection (op, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -387,12 +410,46 @@ gtk_print_operation_get_property (GObject *object,
case PROP_EMBED_PAGE_SETUP:
g_value_set_boolean (value, priv->embed_page_setup);
break;
+ case PROP_HAS_SELECTION:
+ g_value_set_boolean (value, priv->has_selection);
+ break;
+ case PROP_SUPPORT_SELECTION:
+ g_value_set_boolean (value, priv->support_selection);
+ break;
+ case PROP_N_PAGES_TO_PRINT:
+ g_value_set_int (value, priv->nr_of_pages_to_print);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+struct _PrintPagesData
+{
+ GtkPrintOperation *op;
+ gint uncollated_copies;
+ gint collated_copies;
+ gint uncollated, collated, total;
+
+ gint range, num_ranges;
+ GtkPageRange *ranges;
+ GtkPageRange one_range;
+
+ gint page;
+ gint sheet;
+ gint first_position, last_position;
+ gint first_sheet;
+ gint num_of_sheets;
+ gint *pages;
+
+ GtkWidget *progress;
+
+ gboolean initialized;
+ gboolean is_preview;
+ gboolean done;
+};
+
typedef struct
{
GtkPrintOperationPreview *preview;
@@ -400,8 +457,8 @@ typedef struct
GtkWindow *parent;
cairo_surface_t *surface;
gchar *filename;
- guint page_nr;
gboolean wait;
+ PrintPagesData *pages_data;
} PreviewOp;
static void
@@ -423,6 +480,10 @@ preview_print_idle_done (gpointer data)
gtk_print_operation_preview_end_preview (pop->preview);
+ g_object_unref (pop->pages_data->op);
+ g_free (pop->pages_data->pages);
+ g_free (pop->pages_data);
+
g_object_unref (op);
g_free (pop);
}
@@ -432,9 +493,8 @@ preview_print_idle (gpointer data)
{
PreviewOp *pop;
GtkPrintOperation *op;
- gboolean retval = TRUE;
- cairo_t *cr;
GtkPrintOperationPrivate *priv;
+ gboolean done = FALSE;
pop = (PreviewOp *) data;
op = GTK_PRINT_OPERATION (pop->preview);
@@ -443,24 +503,23 @@ preview_print_idle (gpointer data)
if (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_READY)
{
- /* TODO: print out sheets not pages and follow ranges */
- if (pop->page_nr >= op->priv->nr_of_pages)
- retval = FALSE;
-
- if (pop->page_nr > 0)
+ if (!pop->pages_data->initialized)
{
- cr = gtk_print_context_get_cairo_context (pop->print_context);
- _gtk_print_operation_platform_backend_preview_end_page (op, pop->surface, cr);
+ pop->pages_data->initialized = TRUE;
+ prepare_data (pop->pages_data);
}
-
- if (retval)
+ else
{
- gtk_print_operation_preview_render_page (pop->preview, pop->page_nr);
- pop->page_nr++;
+ increment_page_sequence (pop->pages_data);
+
+ if (!pop->pages_data->done)
+ gtk_print_operation_preview_render_page (pop->preview, pop->pages_data->page);
+ else
+ done = priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_READY;
}
}
- return retval;
+ return !done;
}
static void
@@ -484,7 +543,6 @@ preview_ready (GtkPrintOperationPreview *preview,
GtkPrintContext *context,
PreviewOp *pop)
{
- pop->page_nr = 0;
pop->print_context = context;
g_object_ref (preview);
@@ -511,6 +569,9 @@ gtk_print_operation_preview_handler (GtkPrintOperation *op,
pop->filename = NULL;
pop->preview = preview;
pop->parent = parent;
+ pop->pages_data = g_new0 (PrintPagesData, 1);
+ pop->pages_data->op = g_object_ref (GTK_PRINT_OPERATION (preview));
+ pop->pages_data->is_preview = TRUE;
page_setup = gtk_print_context_get_page_setup (context);
@@ -1213,7 +1274,7 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class)
* Since: 2.18
*/
g_object_class_install_property (gobject_class,
- PROP_TRACK_PRINT_STATUS,
+ PROP_SUPPORT_SELECTION,
g_param_spec_boolean ("support-selection",
P_("Support Selection"),
P_("TRUE if the print operation will support print of selection."),
@@ -1230,7 +1291,7 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class)
* Since: 2.18
*/
g_object_class_install_property (gobject_class,
- PROP_TRACK_PRINT_STATUS,
+ PROP_HAS_SELECTION,
g_param_spec_boolean ("has-selection",
P_("Has Selection"),
P_("TRUE if a selecion exists."),
@@ -1252,6 +1313,30 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class)
P_("TRUE if page setup combos are embedded in GtkPrintDialog"),
FALSE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkPrintOperation:n-pages-to-print:
+ *
+ * The number of pages that will be printed.
+ *
+ * Note that this value is set during print preparation phase
+ * (%GTK_PRINT_STATUS_PREPARING), so this value should never be
+ * get before the data generation phase (%GTK_PRINT_STATUS_GENERATING_DATA).
+ * You can connect to the #GtkPrintOperation::status-changed signal
+ * and call gtk_print_operation_get_n_pages_to_print() when
+ * print status is %GTK_PRINT_STATUS_GENERATING_DATA.
+ * This is typically used to track the progress of print operation.
+ *
+ * Since: 2.18
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_N_PAGES_TO_PRINT,
+ g_param_spec_int ("n-pages-to-print",
+ P_("Number of Pages To Print"),
+ P_("The number of pages that will be printed."),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READABLE));
}
/**
@@ -1984,30 +2069,6 @@ run_pdf (GtkPrintOperation *op,
return GTK_PRINT_OPERATION_RESULT_APPLY;
}
-typedef struct
-{
- GtkPrintOperation *op;
- gint uncollated_copies;
- gint collated_copies;
- gint uncollated, collated, total;
-
- gint range, num_ranges;
- GtkPageRange *ranges;
- GtkPageRange one_range;
-
- gint page;
- gint sheet;
- gint first_position, last_position;
- gint first_sheet;
- gint num_of_sheets;
- gint *pages;
-
- GtkWidget *progress;
-
- gboolean initialized;
- gboolean is_preview;
- gboolean done;
-} PrintPagesData;
static void
clamp_page_ranges (PrintPagesData *data)
@@ -2055,6 +2116,12 @@ increment_page_sequence (PrintPagesData *data)
GtkPrintOperationPrivate *priv = data->op->priv;
gint inc;
+ if (data->total == -1)
+ {
+ data->total = 0;
+ return;
+ }
+
/* check whether we reached last position */
if (priv->page_position == data->last_position &&
!(data->collated_copies > 1 && data->collated < (data->collated_copies - 1)))
@@ -2079,7 +2146,8 @@ increment_page_sequence (PrintPagesData *data)
inc = 1;
/* changing sheet */
- if ((priv->page_position + 1) % priv->manual_number_up == 0 ||
+ if (priv->manual_number_up < 2 ||
+ (priv->page_position + 1) % priv->manual_number_up == 0 ||
priv->page_position == data->last_position ||
priv->page_position == priv->nr_of_pages_to_print - 1)
{
@@ -2188,7 +2256,7 @@ update_progress (PrintPagesData *data)
text = g_strdup (_("Preparing"));
}
else if (priv->status == GTK_PRINT_STATUS_GENERATING_DATA)
- text = g_strdup_printf (_("Printing %d"), data->total - 1);
+ text = g_strdup_printf (_("Printing %d"), data->total);
if (text)
{
@@ -2448,6 +2516,10 @@ common_render_page (GtkPrintOperation *op,
x = columns - 1 - (priv->page_position / rows) % columns;
y = rows - 1 - priv->page_position % rows;
break;
+ default:
+ g_assert_not_reached();
+ x = 0;
+ y = 0;
}
if (priv->manual_number_up == 4 || priv->manual_number_up == 9 || priv->manual_number_up == 16)
@@ -2531,27 +2603,27 @@ prepare_data (PrintPagesData *data)
priv = data->op->priv;
+ if (priv->manual_collation)
+ {
+ data->uncollated_copies = priv->manual_num_copies;
+ data->collated_copies = 1;
+ }
+ else
+ {
+ data->uncollated_copies = 1;
+ data->collated_copies = priv->manual_num_copies;
+ }
+
if (!data->initialized)
{
data->initialized = TRUE;
page_setup = create_page_setup (data->op);
- _gtk_print_context_set_page_setup (priv->print_context,
- page_setup);
+ _gtk_print_context_set_page_setup (priv->print_context,
+ page_setup);
g_object_unref (page_setup);
g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
- if (priv->manual_collation)
- {
- data->uncollated_copies = priv->manual_num_copies;
- data->collated_copies = 1;
- }
- else
- {
- data->uncollated_copies = 1;
- data->collated_copies = priv->manual_num_copies;
- }
-
return;
}
@@ -2618,14 +2690,19 @@ prepare_data (PrintPagesData *data)
counter++;
}
- data->total = 0;
+ data->total = -1;
data->collated = 0;
data->uncollated = 0;
- if (priv->nr_of_pages_to_print % priv->manual_number_up == 0)
- data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up;
+ if (priv->manual_number_up > 1)
+ {
+ if (priv->nr_of_pages_to_print % priv->manual_number_up == 0)
+ data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up;
+ else
+ data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up + 1;
+ }
else
- data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up + 1;
+ data->num_of_sheets = priv->nr_of_pages_to_print;
if (priv->manual_reverse)
{
@@ -2716,11 +2793,10 @@ print_pages_idle (gpointer user_data)
goto out;
}
+ increment_page_sequence (data);
+
if (!data->done)
- {
- common_render_page (data->op, data->page);
- increment_page_sequence (data);
- }
+ common_render_page (data->op, data->page);
else
done = priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_READY;
@@ -2859,12 +2935,12 @@ print_pages (GtkPrintOperation *op,
&priv->num_page_ranges);
priv->manual_num_copies = 1;
priv->manual_collation = FALSE;
- priv->manual_reverse = FALSE;
- priv->manual_page_set = GTK_PAGE_SET_ALL;
- priv->manual_scale = 1.0;
+ priv->manual_reverse = gtk_print_settings_get_reverse (priv->print_settings);
+ priv->manual_page_set = gtk_print_settings_get_page_set (priv->print_settings);
+ priv->manual_scale = gtk_print_settings_get_scale (priv->print_settings) / 100.0;
priv->manual_orientation = TRUE;
- priv->manual_number_up = 1;
- priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
+ priv->manual_number_up = gtk_print_settings_get_number_up (priv->print_settings);
+ priv->manual_number_up_layout = gtk_print_settings_get_number_up_layout (priv->print_settings);
}
priv->print_pages_idle_id = gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE + 10,
@@ -3175,5 +3251,31 @@ gtk_print_operation_get_has_selection (GtkPrintOperation *op)
return op->priv->has_selection;
}
+/**
+ * gtk_print_operation_get_n_pages_to_print:
+ * @op: a #GtkPrintOperation
+ *
+ * Returns the number of pages that will be printed.
+ *
+ * Note that this value is set during print preparation phase
+ * (%GTK_PRINT_STATUS_PREPARING), so this function should never be
+ * called before the data generation phase (%GTK_PRINT_STATUS_GENERATING_DATA).
+ * You can connect to the #GtkPrintOperation::status-changed signal
+ * and call gtk_print_operation_get_n_pages_to_print() when
+ * print status is %GTK_PRINT_STATUS_GENERATING_DATA.
+ * This is typically used to track the progress of print operation.
+ *
+ * Returns: the number of pages that will be printed
+ *
+ * Since: 2.18
+ **/
+gint
+gtk_print_operation_get_n_pages_to_print (GtkPrintOperation *op)
+{
+ g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), -1);
+
+ return op->priv->nr_of_pages_to_print;
+}
+
#define __GTK_PRINT_OPERATION_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkprintoperation.h b/gtk/gtkprintoperation.h
index 7ac38d4c2a..ef9a2879f3 100644
--- a/gtk/gtkprintoperation.h
+++ b/gtk/gtkprintoperation.h
@@ -187,6 +187,7 @@ gboolean gtk_print_operation_get_has_selection (GtkPrintOper
void gtk_print_operation_set_embed_page_setup (GtkPrintOperation *op,
gboolean embed);
gboolean gtk_print_operation_get_embed_page_setup (GtkPrintOperation *op);
+gint gtk_print_operation_get_n_pages_to_print (GtkPrintOperation *op);
GtkPageSetup *gtk_print_run_page_setup_dialog (GtkWindow *parent,
GtkPageSetup *page_setup,
diff --git a/gtk/gtkprintsettings.c b/gtk/gtkprintsettings.c
index e50208017b..f35552a198 100644
--- a/gtk/gtkprintsettings.c
+++ b/gtk/gtkprintsettings.c
@@ -1152,7 +1152,7 @@ gtk_print_settings_set_n_copies (GtkPrintSettings *settings,
gint
gtk_print_settings_get_number_up (GtkPrintSettings *settings)
{
- return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_NUMBER_UP);
+ return gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_NUMBER_UP, 1);
}
/**
@@ -1185,7 +1185,7 @@ gtk_print_settings_set_number_up (GtkPrintSettings *settings,
gint
gtk_print_settings_get_resolution (GtkPrintSettings *settings)
{
- return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION);
+ return gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION, 300);
}
/**
@@ -1224,7 +1224,7 @@ gtk_print_settings_set_resolution (GtkPrintSettings *settings,
gint
gtk_print_settings_get_resolution_x (GtkPrintSettings *settings)
{
- return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION_X);
+ return gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_X, 300);
}
/**
@@ -1240,7 +1240,7 @@ gtk_print_settings_get_resolution_x (GtkPrintSettings *settings)
gint
gtk_print_settings_get_resolution_y (GtkPrintSettings *settings)
{
- return gtk_print_settings_get_int (settings, GTK_PRINT_SETTINGS_RESOLUTION_Y);
+ return gtk_print_settings_get_int_with_default (settings, GTK_PRINT_SETTINGS_RESOLUTION_Y, 300);
}
/**
@@ -1281,7 +1281,7 @@ gtk_print_settings_set_resolution_xy (GtkPrintSettings *settings,
gdouble
gtk_print_settings_get_printer_lpi (GtkPrintSettings *settings)
{
- return gtk_print_settings_get_double (settings, GTK_PRINT_SETTINGS_PRINTER_LPI);
+ return gtk_print_settings_get_double_with_default (settings, GTK_PRINT_SETTINGS_PRINTER_LPI, 150.0);
}
/**
diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c
index 38b43a1a5c..5e6f771be5 100644
--- a/gtk/gtkprintunixdialog.c
+++ b/gtk/gtkprintunixdialog.c
@@ -380,6 +380,32 @@ get_toplevel (GtkWidget *widget)
}
static void
+set_busy_cursor (GtkPrintUnixDialog *dialog,
+ gboolean busy)
+{
+ GtkWindow *toplevel;
+ GdkDisplay *display;
+ GdkCursor *cursor;
+
+ toplevel = get_toplevel (GTK_WIDGET (dialog));
+ if (!toplevel || !GTK_WIDGET_REALIZED (toplevel))
+ return;
+
+ display = gtk_widget_get_display (GTK_WIDGET (toplevel));
+
+ if (busy)
+ cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+ else
+ cursor = NULL;
+
+ gdk_window_set_cursor (GTK_WIDGET (toplevel)->window, cursor);
+ gdk_display_flush (display);
+
+ if (cursor)
+ gdk_cursor_unref (cursor);
+}
+
+static void
add_custom_button_to_dialog (GtkDialog *dialog,
const gchar *mnemonic_label,
const gchar *stock_id,
@@ -418,72 +444,81 @@ error_dialogs (GtkPrintUnixDialog *print_dialog,
{
printer = gtk_print_unix_dialog_get_selected_printer (print_dialog);
- /* Shows overwrite confirmation dialog in the case of printing to file which
- * already exists. */
- if (printer != NULL && gtk_printer_is_virtual (printer))
+ if (printer != NULL)
{
- option = gtk_printer_option_set_lookup (priv->options,
- "gtk-main-page-custom-input");
+ if (priv->request_details_tag || !gtk_printer_is_accepting_jobs (printer))
+ {
+ g_signal_stop_emission_by_name (print_dialog, "response");
+ return TRUE;
+ }
- if (option != NULL &&
- option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
+ /* Shows overwrite confirmation dialog in the case of printing to file which
+ * already exists. */
+ if (gtk_printer_is_virtual (printer))
{
- file = g_file_new_for_uri (option->value);
+ option = gtk_printer_option_set_lookup (priv->options,
+ "gtk-main-page-custom-input");
- if (file != NULL &&
- g_file_query_exists (file, NULL))
+ if (option != NULL &&
+ option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
{
- toplevel = get_toplevel (GTK_WIDGET (print_dialog));
-
- basename = g_file_get_basename (file);
- dirname = g_file_get_parse_name (g_file_get_parent (file));
-
- dialog = gtk_message_dialog_new (toplevel,
- GTK_DIALOG_MODAL |
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_NONE,
- _("A file named \"%s\" already exists. Do you want to replace it?"),
- basename);
-
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- _("The file already exists in \"%s\". Replacing it will "
- "overwrite its contents."),
- dirname);
-
- gtk_dialog_add_button (GTK_DIALOG (dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
- add_custom_button_to_dialog (GTK_DIALOG (dialog),
- _("_Replace"),
- GTK_STOCK_PRINT,
- GTK_RESPONSE_ACCEPT);
- gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
- GTK_RESPONSE_ACCEPT,
- GTK_RESPONSE_CANCEL,
- -1);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog),
- GTK_RESPONSE_ACCEPT);
-
- if (toplevel->group)
- gtk_window_group_add_window (toplevel->group,
- GTK_WINDOW (dialog));
+ file = g_file_new_for_uri (option->value);
- response = gtk_dialog_run (GTK_DIALOG (dialog));
-
- gtk_widget_destroy (dialog);
-
- g_free (dirname);
- g_free (basename);
-
- if (response != GTK_RESPONSE_ACCEPT)
+ if (file != NULL &&
+ g_file_query_exists (file, NULL))
{
- g_signal_stop_emission_by_name (print_dialog, "response");
- g_object_unref (file);
- return TRUE;
+ toplevel = get_toplevel (GTK_WIDGET (print_dialog));
+
+ basename = g_file_get_basename (file);
+ dirname = g_file_get_parse_name (g_file_get_parent (file));
+
+ dialog = gtk_message_dialog_new (toplevel,
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("A file named \"%s\" already exists. Do you want to replace it?"),
+ basename);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The file already exists in \"%s\". Replacing it will "
+ "overwrite its contents."),
+ dirname);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ add_custom_button_to_dialog (GTK_DIALOG (dialog),
+ _("_Replace"),
+ GTK_STOCK_PRINT,
+ GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_CANCEL,
+ -1);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ if (toplevel->group)
+ gtk_window_group_add_window (toplevel->group,
+ GTK_WINDOW (dialog));
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+
+ g_free (dirname);
+ g_free (basename);
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ {
+ g_signal_stop_emission_by_name (print_dialog, "response");
+ g_object_unref (file);
+ return TRUE;
+ }
}
- }
- g_object_unref (file);
+ g_object_unref (file);
+ }
}
}
}
@@ -561,7 +596,7 @@ gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
}
static void
-disconnect_printer_details_request (GtkPrintUnixDialog *dialog)
+disconnect_printer_details_request (GtkPrintUnixDialog *dialog, gboolean details_failed)
{
GtkPrintUnixDialogPrivate *priv = dialog->priv;
@@ -570,6 +605,21 @@ disconnect_printer_details_request (GtkPrintUnixDialog *dialog)
g_signal_handler_disconnect (priv->request_details_printer,
priv->request_details_tag);
priv->request_details_tag = 0;
+ set_busy_cursor (dialog, FALSE);
+ if (details_failed)
+ gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
+ g_object_get_data (G_OBJECT (priv->request_details_printer),
+ "gtk-print-tree-iter"),
+ PRINTER_LIST_COL_STATE,
+ _("Getting printer information failed"),
+ -1);
+ else
+ gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
+ g_object_get_data (G_OBJECT (priv->request_details_printer),
+ "gtk-print-tree-iter"),
+ PRINTER_LIST_COL_STATE,
+ gtk_printer_get_state_message (priv->request_details_printer),
+ -1);
g_object_unref (priv->request_details_printer);
priv->request_details_printer = NULL;
}
@@ -584,7 +634,7 @@ gtk_print_unix_dialog_finalize (GObject *object)
GList *node;
unschedule_idle_mark_conflicts (dialog);
- disconnect_printer_details_request (dialog);
+ disconnect_printer_details_request (dialog, FALSE);
if (priv->current_printer)
{
@@ -1739,7 +1789,7 @@ printer_details_acquired (GtkPrinter *printer,
{
GtkPrintUnixDialogPrivate *priv = dialog->priv;
- disconnect_printer_details_request (dialog);
+ disconnect_printer_details_request (dialog, !success);
if (success)
{
@@ -1767,7 +1817,7 @@ selected_printer_changed (GtkTreeSelection *selection,
priv->waiting_for_printer = NULL;
}
- disconnect_printer_details_request (dialog);
+ disconnect_printer_details_request (dialog, FALSE);
printer = NULL;
if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
@@ -1806,6 +1856,11 @@ selected_printer_changed (GtkTreeSelection *selection,
/* take the reference */
priv->request_details_printer = printer;
gtk_printer_request_details (printer);
+ set_busy_cursor (dialog, TRUE);
+ gtk_list_store_set (GTK_LIST_STORE (priv->printer_list),
+ g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter"),
+ PRINTER_LIST_COL_STATE, _("Getting printer information..."),
+ -1);
return;
}
@@ -2537,6 +2592,7 @@ draw_page_cb (GtkWidget *widget,
gdouble paper_width, paper_height;
gdouble pos_x, pos_y;
gint pages_per_sheet;
+ gboolean ltr = TRUE;
orientation = gtk_page_setup_get_orientation (priv->page_setup);
landscape =
@@ -2835,8 +2891,14 @@ draw_page_cb (GtkWidget *widget,
g_free (text);
pango_layout_get_size (layout, &layout_w, &layout_h);
- cairo_translate (cr, pos_x - layout_w / PANGO_SCALE - 2 * RULER_DISTANCE,
- widget->allocation.y + (widget->allocation.height - layout_h / PANGO_SCALE) / 2);
+ ltr = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_LTR;
+
+ if (ltr)
+ cairo_translate (cr, pos_x - layout_w / PANGO_SCALE - 2 * RULER_DISTANCE,
+ widget->allocation.y + (widget->allocation.height - layout_h / PANGO_SCALE) / 2);
+ else
+ cairo_translate (cr, pos_x + w + shadow_offset + 2 * RULER_DISTANCE,
+ widget->allocation.y + (widget->allocation.height - layout_h / PANGO_SCALE) / 2);
pango_cairo_show_layout (cr, layout);
@@ -2863,17 +2925,34 @@ draw_page_cb (GtkWidget *widget,
cairo_set_line_width (cr, 1);
- cairo_move_to (cr, pos_x - RULER_DISTANCE, pos_y);
- cairo_line_to (cr, pos_x - RULER_DISTANCE, pos_y + h);
- cairo_stroke (cr);
+ if (ltr)
+ {
+ cairo_move_to (cr, pos_x - RULER_DISTANCE, pos_y);
+ cairo_line_to (cr, pos_x - RULER_DISTANCE, pos_y + h);
+ cairo_stroke (cr);
- cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
- cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
- cairo_stroke (cr);
+ cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
+ cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
+ cairo_stroke (cr);
- cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
- cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
- cairo_stroke (cr);
+ cairo_move_to (cr, pos_x - RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
+ cairo_line_to (cr, pos_x - RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
+ cairo_stroke (cr);
+ }
+ else
+ {
+ cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y);
+ cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE, pos_y + h);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y - 0.5);
+ cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y - 0.5);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE - RULER_RADIUS, pos_y + h + 0.5);
+ cairo_line_to (cr, pos_x + w + shadow_offset + RULER_DISTANCE + RULER_RADIUS, pos_y + h + 0.5);
+ cairo_stroke (cr);
+ }
cairo_move_to (cr, pos_x, pos_y + h + shadow_offset + RULER_DISTANCE);
cairo_line_to (cr, pos_x + w, pos_y + h + shadow_offset + RULER_DISTANCE);
@@ -2998,21 +3077,32 @@ update_number_up_layout (GtkPrintUnixDialog *dialog)
{
option = priv->number_up_layout_2_option;
- if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM ||
- layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT)
- enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
-
- if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
- layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
- enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
-
- if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM ||
- layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT)
- enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
-
- if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP ||
- layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT)
- enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
+ switch (layout)
+ {
+ case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
+ case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
+ enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
+ break;
+
+ case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
+ case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
+ enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
+ break;
+
+ case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
+ case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
+ enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
+ break;
+
+ case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
+ case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
+ enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
+ break;
+
+ default:
+ g_assert_not_reached();
+ enum_value = NULL;
+ }
}
else
{
@@ -3700,12 +3790,16 @@ populate_dialog (GtkPrintUnixDialog *print_dialog)
create_main_page (print_dialog);
create_page_setup_page (print_dialog);
create_job_page (print_dialog);
+ /* Translators: this will appear as tab label in print dialog. */
create_optional_page (print_dialog, _("Image Quality"),
&priv->image_quality_table,
&priv->image_quality_page);
+ /* Translators: this will appear as tab label in print dialog. */
create_optional_page (print_dialog, _("Color"),
&priv->color_table,
&priv->color_page);
+ /* Translators: this will appear as tab label in print dialog. */
+ /* It's a typographical term, as in "Binding and finishing" */
create_optional_page (print_dialog, _("Finishing"),
&priv->finishing_table,
&priv->finishing_page);
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 5e51844c5b..7ba5a5db62 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -103,6 +103,15 @@ gboolean _gtk_fnmatch (const char *pattern,
#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+/* Many keyboard shortcuts for Mac are the same as for X
+ * except they use Command key instead of Control (e.g. Cut,
+ * Copy, Paste). This symbol is for those simple cases. */
+#ifndef GDK_WINDOWING_QUARTZ
+#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_CONTROL_MASK
+#else
+#define GTK_DEFAULT_ACCEL_MOD_MASK GDK_META_MASK
+#endif
+
G_END_DECLS
#endif /* __GTK_PRIVATE_H__ */
diff --git a/gtk/gtkradiobutton.c b/gtk/gtkradiobutton.c
index 0d7277846b..f07113fe22 100644
--- a/gtk/gtkradiobutton.c
+++ b/gtk/gtkradiobutton.c
@@ -486,7 +486,7 @@ gtk_radio_button_focus (GtkWidget *widget,
{
GtkWidget *child = tmp_list->data;
- if (GTK_WIDGET_REALIZED (child) && GTK_WIDGET_IS_SENSITIVE (child))
+ if (GTK_WIDGET_MAPPED (child) && GTK_WIDGET_IS_SENSITIVE (child))
{
new_focus = child;
break;
@@ -522,7 +522,7 @@ gtk_radio_button_focus (GtkWidget *widget,
{
GtkWidget *child = tmp_list->data;
- if (GTK_WIDGET_REALIZED (child) && GTK_WIDGET_IS_SENSITIVE (child))
+ if (GTK_WIDGET_MAPPED (child) && GTK_WIDGET_IS_SENSITIVE (child))
{
new_focus = child;
break;
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index ce4e5e4282..17c0d6f43a 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -844,6 +844,52 @@ gtk_range_get_inverted (GtkRange *range)
}
/**
+ * gtk_range_set_flippable:
+ * @range: a #GtkRange
+ * @flippable: %TRUE to make the range flippable
+ *
+ * If a range is flippable, it will switch its direction if it is
+ * horizontal and its direction is %GTK_TEXT_DIR_RTL.
+ *
+ * See gtk_widget_get_direction().
+ *
+ * Since: 2.18
+ **/
+void
+gtk_range_set_flippable (GtkRange *range,
+ gboolean flippable)
+{
+ g_return_if_fail (GTK_IS_RANGE (range));
+
+ flippable = flippable ? TRUE : FALSE;
+
+ if (flippable != range->flippable)
+ {
+ range->flippable = flippable;
+
+ gtk_widget_queue_draw (GTK_WIDGET (range));
+ }
+}
+
+/**
+ * gtk_range_get_flippable:
+ * @range: a #GtkRange
+ *
+ * Gets the value set by gtk_range_set_flippable().
+ *
+ * Return value: %TRUE if the range is flippable
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_range_get_flippable (GtkRange *range)
+{
+ g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
+
+ return range->flippable;
+}
+
+/**
* gtk_range_set_lower_stepper_sensitivity:
* @range: a #GtkRange
* @sensitivity: the lower stepper's sensitivity policy.
diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h
index f7f3b96aa7..268a5223e1 100644
--- a/gtk/gtkrange.h
+++ b/gtk/gtkrange.h
@@ -147,6 +147,10 @@ void gtk_range_set_inverted (GtkRange *range
gboolean setting);
gboolean gtk_range_get_inverted (GtkRange *range);
+void gtk_range_set_flippable (GtkRange *range,
+ gboolean flippable);
+gboolean gtk_range_get_flippable (GtkRange *range);
+
void gtk_range_set_lower_stepper_sensitivity (GtkRange *range,
GtkSensitivityType sensitivity);
GtkSensitivityType gtk_range_get_lower_stepper_sensitivity (GtkRange *range);
diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c
index a2ac58b932..70540a3130 100644
--- a/gtk/gtkrc.c
+++ b/gtk/gtkrc.c
@@ -659,11 +659,15 @@ gtk_rc_color_hash_changed (GtkSettings *settings,
GParamSpec *pspec,
GtkRcContext *context)
{
- if (context->color_hash)
- g_hash_table_unref (context->color_hash);
-
+ GHashTable *old_hash;
+
+ old_hash = context->color_hash;
+
g_object_get (settings, "color-hash", &context->color_hash, NULL);
+ if (old_hash)
+ g_hash_table_unref (old_hash);
+
gtk_rc_reparse_all_for_settings (settings, TRUE);
}
@@ -3148,8 +3152,10 @@ gtk_rc_parse_style (GtkRcContext *context,
break;
case GTK_RC_TOKEN_COLOR:
if (our_hash == NULL)
- gtk_rc_style_prepend_empty_color_hash (rc_style);
- our_hash = rc_priv->color_hashes->data;
+ {
+ gtk_rc_style_prepend_empty_color_hash (rc_style);
+ our_hash = rc_priv->color_hashes->data;
+ }
token = gtk_rc_parse_logical_color (scanner, rc_style, our_hash);
break;
case G_TOKEN_IDENTIFIER:
diff --git a/gtk/gtkrc.key.mac b/gtk/gtkrc.key.mac
new file mode 100644
index 0000000000..7b6e8d1e4f
--- /dev/null
+++ b/gtk/gtkrc.key.mac
@@ -0,0 +1,240 @@
+binding "gtk-mac-alt-arrows"
+{
+ bind "<alt>Right" { "move-cursor" (words, 1, 0) }
+ bind "<alt>KP_Right" { "move-cursor" (words, 1, 0) }
+ bind "<alt>Left" { "move-cursor" (words, -1, 0) }
+ bind "<alt>KP_Left" { "move-cursor" (words, -1, 0) }
+ bind "<shift><alt>Right" { "move-cursor" (words, 1, 1) }
+ bind "<shift><alt>KP_Right" { "move-cursor" (words, 1, 1) }
+ bind "<shift><alt>Left" { "move-cursor" (words, -1, 1) }
+ bind "<shift><alt>KP_Left" { "move-cursor" (words, -1, 1) }
+}
+
+class "GtkTextView" binding "gtk-mac-alt-arrows"
+class "GtkLabel" binding "gtk-mac-alt-arrows"
+class "GtkEntry" binding "gtk-mac-alt-arrows"
+
+
+binding "gtk-mac-alt-delete"
+{
+ bind "<alt>Delete" { "delete-from-cursor" (word-ends, 1) }
+ bind "<alt>KP_Delete" { "delete-from-cursor" (word-ends, 1) }
+ bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
+}
+
+class "GtkTextView" binding "gtk-mac-alt-delete"
+class "GtkEntry" binding "gtk-mac-alt-delete"
+
+
+binding "gtk-mac-cmd-c"
+{
+ bind "<meta>x" { "cut-clipboard" () }
+ bind "<meta>c" { "copy-clipboard" () }
+ bind "<meta>v" { "paste-clipboard" () }
+ unbind "<ctrl>x"
+ unbind "<ctrl>c"
+ unbind "<ctrl>v"
+}
+
+class "GtkTextView" binding "gtk-mac-cmd-c"
+class "GtkEntry" binding "gtk-mac-cmd-c"
+
+
+binding "gtk-mac-text-view"
+{
+ bind "<shift><meta>a" { "select-all" (0) }
+ bind "<meta>a" { "select-all" (1) }
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>a"
+}
+
+class "GtkTextView" binding "gtk-mac-text-view"
+
+
+binding "gtk-mac-label"
+{
+ bind "<meta>a" {
+ "move-cursor" (paragraph-ends, -1, 0)
+ "move-cursor" (paragraph-ends, 1, 1)
+ }
+ bind "<shift><meta>a" { "move-cursor" (paragraph-ends, 0, 0) }
+ bind "<meta>c" { "copy-clipboard" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>c"
+}
+
+class "GtkLabel" binding "gtk-mac-label"
+
+
+binding "gtk-mac-entry"
+{
+ bind "<meta>a" {
+ "move-cursor" (buffer-ends, -1, 0)
+ "move-cursor" (buffer-ends, 1, 1)
+ }
+ bind "<shift><meta>a" { "move-cursor" (visual-positions, 0, 0) }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+}
+
+class "GtkEntry" binding "gtk-mac-entry"
+
+
+binding "gtk-mac-file-chooser"
+{
+ bind "<meta>v" { "location-popup-on-paste" () }
+ unbind "<ctrl>v"
+
+ bind "<meta><shift>G" { "location-popup" () }
+ bind "<meta><shift>H" { "home-folder" () }
+ bind "<meta>Up" { "up-folder" () }
+}
+
+class "GtkFileChooserDefault" binding "gtk-mac-file-chooser"
+
+
+binding "gtk-mac-tree-view"
+{
+ bind "<meta>a" { "select-all" () }
+ bind "<shift><meta>a" { "unselect-all" () }
+ bind "<meta>f" { "start-interactive-search" () }
+ bind "<meta>F" { "start-interactive-search" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>f"
+ unbind "<ctrl>F"
+}
+
+class "GtkTreeView" binding "gtk-mac-tree-view"
+
+
+binding "gtk-mac-icon-view"
+{
+ bind "<meta>a" { "select-all" () }
+ bind "<shift><meta>a" { "unselect-all" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+}
+
+class "GtkIconView" binding "gtk-mac-icon-view"
+binding "gtk-mac-alt-arrows"
+{
+ bind "<alt>Right" { "move-cursor" (words, 1, 0) }
+ bind "<alt>KP_Right" { "move-cursor" (words, 1, 0) }
+ bind "<alt>Left" { "move-cursor" (words, -1, 0) }
+ bind "<alt>KP_Left" { "move-cursor" (words, -1, 0) }
+ bind "<shift><alt>Right" { "move-cursor" (words, 1, 1) }
+ bind "<shift><alt>KP_Right" { "move-cursor" (words, 1, 1) }
+ bind "<shift><alt>Left" { "move-cursor" (words, -1, 1) }
+ bind "<shift><alt>KP_Left" { "move-cursor" (words, -1, 1) }
+}
+
+class "GtkTextView" binding "gtk-mac-alt-arrows"
+class "GtkLabel" binding "gtk-mac-alt-arrows"
+class "GtkEntry" binding "gtk-mac-alt-arrows"
+
+
+binding "gtk-mac-alt-delete"
+{
+ bind "<alt>Delete" { "delete-from-cursor" (word-ends, 1) }
+ bind "<alt>KP_Delete" { "delete-from-cursor" (word-ends, 1) }
+ bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
+}
+
+class "GtkTextView" binding "gtk-mac-alt-delete"
+class "GtkEntry" binding "gtk-mac-alt-delete"
+
+
+binding "gtk-mac-cmd-c"
+{
+ bind "<meta>x" { "cut-clipboard" () }
+ bind "<meta>c" { "copy-clipboard" () }
+ bind "<meta>v" { "paste-clipboard" () }
+ unbind "<ctrl>x"
+ unbind "<ctrl>c"
+ unbind "<ctrl>v"
+}
+
+class "GtkTextView" binding "gtk-mac-cmd-c"
+class "GtkEntry" binding "gtk-mac-cmd-c"
+
+
+binding "gtk-mac-text-view"
+{
+ bind "<shift><meta>a" { "select-all" (0) }
+ bind "<meta>a" { "select-all" (1) }
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>a"
+}
+
+class "GtkTextView" binding "gtk-mac-text-view"
+
+
+binding "gtk-mac-label"
+{
+ bind "<meta>a" {
+ "move-cursor" (paragraph-ends, -1, 0)
+ "move-cursor" (paragraph-ends, 1, 1)
+ }
+ bind "<shift><meta>a" { "move-cursor" (paragraph-ends, 0, 0) }
+ bind "<meta>c" { "copy-clipboard" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>c"
+}
+
+class "GtkLabel" binding "gtk-mac-label"
+
+
+binding "gtk-mac-entry"
+{
+ bind "<meta>a" {
+ "move-cursor" (buffer-ends, -1, 0)
+ "move-cursor" (buffer-ends, 1, 1)
+ }
+ bind "<shift><meta>a" { "move-cursor" (visual-positions, 0, 0) }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+}
+
+class "GtkEntry" binding "gtk-mac-entry"
+
+
+binding "gtk-mac-file-chooser"
+{
+ bind "<meta>v" { "location-popup-on-paste" () }
+ unbind "<ctrl>v"
+
+ bind "<meta><shift>G" { "location-popup" () }
+ bind "<meta><shift>H" { "home-folder" () }
+ bind "<meta>Up" { "up-folder" () }
+}
+
+class "GtkFileChooserDefault" binding "gtk-mac-file-chooser"
+
+
+binding "gtk-mac-tree-view"
+{
+ bind "<meta>a" { "select-all" () }
+ bind "<shift><meta>a" { "unselect-all" () }
+ bind "<meta>f" { "start-interactive-search" () }
+ bind "<meta>F" { "start-interactive-search" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+ unbind "<ctrl>f"
+ unbind "<ctrl>F"
+}
+
+class "GtkTreeView" binding "gtk-mac-tree-view"
+
+
+binding "gtk-mac-icon-view"
+{
+ bind "<meta>a" { "select-all" () }
+ bind "<shift><meta>a" { "unselect-all" () }
+ unbind "<ctrl>a"
+ unbind "<shift><ctrl>a"
+}
+
+class "GtkIconView" binding "gtk-mac-icon-view"
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index 87aa469da4..2f4cc98fb6 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -1423,7 +1423,7 @@ marks_start_element (GMarkupParseContext *context,
;
else if (strcmp (element_name, "mark") == 0)
{
- gdouble value;
+ gdouble value = 0;
gboolean has_value = FALSE;
GtkPositionType position = GTK_POS_BOTTOM;
const gchar *msg_context = NULL;
@@ -1578,7 +1578,6 @@ gtk_scale_buildable_custom_finished (GtkBuildable *buildable,
{
GtkScale *scale = GTK_SCALE (buildable);
MarksSubparserData *marks_data;
- GtkWidget *toplevel;
if (strcmp (tagname, "marks") == 0)
{
diff --git a/gtk/gtksearchenginetracker.c b/gtk/gtksearchenginetracker.c
index e3d5a3ae3c..62447f8c29 100644
--- a/gtk/gtksearchenginetracker.c
+++ b/gtk/gtksearchenginetracker.c
@@ -31,9 +31,15 @@
typedef struct _TrackerClient TrackerClient;
+typedef enum
+{
+ TRACKER_0_6 = 1 << 0,
+ TRACKER_0_7 = 1 << 1
+} TrackerVersion;
+
typedef void (*TrackerArrayReply) (char **result, GError *error, gpointer user_data);
-static TrackerClient * (*tracker_connect) (gboolean enable_warnings) = NULL;
+static TrackerClient * (*tracker_connect) (gboolean enable_warnings, gint timeout) = NULL;
static void (*tracker_disconnect) (TrackerClient *client) = NULL;
static int (*tracker_get_version) (TrackerClient *client, GError **error) = NULL;
static void (*tracker_cancel_last_call) (TrackerClient *client) = NULL;
@@ -52,22 +58,24 @@ static struct TrackerDlMapping
{
const char *fn_name;
gpointer *fn_ptr_ref;
+ TrackerVersion versions;
} tracker_dl_mapping[] =
{
-#define MAP(a) { #a, (gpointer *)&a }
- MAP (tracker_connect),
- MAP (tracker_disconnect),
- MAP (tracker_get_version),
- MAP (tracker_cancel_last_call),
- MAP (tracker_search_metadata_by_text_async),
- MAP (tracker_search_metadata_by_text_and_location_async),
+#define MAP(a,v) { #a, (gpointer *)&a, v }
+ MAP (tracker_connect, TRACKER_0_6 | TRACKER_0_7),
+ MAP (tracker_disconnect, TRACKER_0_6 | TRACKER_0_7),
+ MAP (tracker_get_version, TRACKER_0_6),
+ MAP (tracker_cancel_last_call, TRACKER_0_6 | TRACKER_0_7),
+ MAP (tracker_search_metadata_by_text_async, TRACKER_0_6 | TRACKER_0_7),
+ MAP (tracker_search_metadata_by_text_and_location_async, TRACKER_0_6 | TRACKER_0_7),
#undef MAP
};
-static void
+static TrackerVersion
open_libtracker (void)
{
static gboolean done = FALSE;
+ static TrackerVersion version = 0;
if (!done)
{
@@ -78,16 +86,29 @@ open_libtracker (void)
done = TRUE;
flags = G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL;
- tracker = g_module_open ("libtrackerclient.so.0", flags);
+ tracker = g_module_open ("libtracker-client-0.7.so.0", flags);
+ version = TRACKER_0_7;
+
+ if (!tracker)
+ {
+ tracker = g_module_open ("libtrackerclient.so.0", flags);
+ version = TRACKER_0_6;
+ }
if (!tracker)
- tracker = g_module_open ("libtracker.so.0", flags);
+ {
+ tracker = g_module_open ("libtracker.so.0", flags);
+ version = TRACKER_0_6;
+ }
if (!tracker)
- return;
+ return 0;
for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++)
{
+ if ((tracker_dl_mapping[i].versions & version) == 0)
+ continue;
+
if (!g_module_symbol (tracker, tracker_dl_mapping[i].fn_name,
tracker_dl_mapping[i].fn_ptr_ref))
{
@@ -98,10 +119,12 @@ open_libtracker (void)
for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++)
tracker_dl_mapping[i].fn_ptr_ref = NULL;
- return;
+ return 0;
}
}
}
+
+ return version;
}
struct _GtkSearchEngineTrackerPrivate
@@ -109,6 +132,7 @@ struct _GtkSearchEngineTrackerPrivate
GtkQuery *query;
TrackerClient *client;
gboolean query_pending;
+ TrackerVersion version;
};
G_DEFINE_TYPE (GtkSearchEngineTracker, _gtk_search_engine_tracker, GTK_TYPE_SEARCH_ENGINE);
@@ -161,7 +185,11 @@ search_callback (gchar **results,
{
gchar *uri;
- uri = g_filename_to_uri (*results_p, NULL, NULL);
+ if (tracker->priv->version == TRACKER_0_6)
+ uri = g_filename_to_uri (*results_p, NULL, NULL);
+ else
+ uri = *results_p;
+
if (uri)
hit_uris = g_list_prepend (hit_uris, uri);
}
@@ -170,7 +198,8 @@ search_callback (gchar **results,
_gtk_search_engine_finished (GTK_SEARCH_ENGINE (tracker));
g_strfreev (results);
- g_list_foreach (hit_uris, (GFunc)g_free, NULL);
+ if (tracker->priv->version == TRACKER_0_6)
+ g_list_foreach (hit_uris, (GFunc)g_free, NULL);
g_list_free (hit_uris);
}
@@ -195,9 +224,14 @@ gtk_search_engine_tracker_start (GtkSearchEngine *engine)
location = NULL;
if (location_uri)
{
- location = g_filename_from_uri (location_uri, NULL, NULL);
- g_free (location_uri);
- }
+ if (tracker->priv->version == TRACKER_0_6)
+ {
+ location = g_filename_from_uri (location_uri, NULL, NULL);
+ g_free (location_uri);
+ }
+ else
+ location = location_uri;
+ }
if (location)
{
@@ -287,34 +321,39 @@ _gtk_search_engine_tracker_new (void)
{
GtkSearchEngineTracker *engine;
TrackerClient *tracker_client;
+ TrackerVersion version;
GError *err = NULL;
- open_libtracker ();
+ version = open_libtracker ();
if (!tracker_connect)
return NULL;
- tracker_client = tracker_connect (FALSE);
+ tracker_client = tracker_connect (FALSE, -1);
if (!tracker_client)
return NULL;
- if (!tracker_get_version)
- return NULL;
+ if (version == TRACKER_0_6)
+ {
+ if (!tracker_get_version)
+ return NULL;
- tracker_get_version (tracker_client, &err);
+ tracker_get_version (tracker_client, &err);
- if (err != NULL)
- {
- g_error_free (err);
- tracker_disconnect (tracker_client);
- return NULL;
+ if (err != NULL)
+ {
+ g_error_free (err);
+ tracker_disconnect (tracker_client);
+ return NULL;
+ }
}
engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_TRACKER, NULL);
engine->priv->client = tracker_client;
engine->priv->query_pending = FALSE;
+ engine->priv->version = version;
return GTK_SEARCH_ENGINE (engine);
}
diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c
index 7195b86a51..f6187b21c8 100644
--- a/gtk/gtkselection.c
+++ b/gtk/gtkselection.c
@@ -3067,7 +3067,7 @@ gtk_selection_default_handler (GtkWidget *widget,
{
gtk_selection_data_set (data,
gdk_atom_intern_static_string ("NULL"),
- 32, "", 0);
+ 32, NULL, 0);
}
else
{
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index 2e507e39f3..96ee7f28aa 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -35,6 +35,12 @@
#include <pango/pangofc-fontmap.h>
#endif
+#ifdef GDK_WINDOWING_QUARTZ
+#define DEFAULT_KEY_THEME "Mac"
+#else
+#define DEFAULT_KEY_THEME NULL
+#endif
+
#define DEFAULT_TIMEOUT_INITIAL 200
#define DEFAULT_TIMEOUT_REPEAT 20
#define DEFAULT_TIMEOUT_EXPAND 500
@@ -312,7 +318,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_param_spec_string ("gtk-key-theme-name",
P_("Key Theme Name"),
P_("Name of key theme RC file to load"),
- NULL,
+ DEFAULT_KEY_THEME,
GTK_PARAM_READWRITE),
NULL);
g_assert (result == PROP_KEY_THEME_NAME);
@@ -743,7 +749,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
*
* A comma-separated list of print backends to use in the print
* dialog. Available print backends depend on the GTK+ installation,
- * and may include "pdf", "cups" or "lpr".
+ * and may include "file", "cups", "lpr" or "papi".
*
* Since: 2.10
*/
@@ -2227,8 +2233,8 @@ settings_update_color_scheme (GtkSettings *settings)
}
static gboolean
-add_color_to_hash (gchar *name,
- GdkColor *color,
+add_color_to_hash (gchar *name,
+ GdkColor *color,
GHashTable *target)
{
GdkColor *old;
@@ -2237,7 +2243,7 @@ add_color_to_hash (gchar *name,
if (!old || !gdk_color_equal (old, color))
{
g_hash_table_insert (target, g_strdup (name), gdk_color_copy (color));
-
+
return TRUE;
}
@@ -2245,7 +2251,7 @@ add_color_to_hash (gchar *name,
}
static gboolean
-add_colors_to_hash_from_string (GHashTable *hash,
+add_colors_to_hash_from_string (GHashTable *hash,
const gchar *colors)
{
gchar *s, *p, *name;
@@ -2293,24 +2299,27 @@ add_colors_to_hash_from_string (GHashTable *hash,
static gboolean
update_color_hash (ColorSchemeData *data,
- const gchar *str,
+ const gchar *str,
GtkSettingsSource source)
{
gboolean changed = FALSE;
gint i;
GHashTable *old_hash;
+ GHashTableIter iter;
+ gchar *name;
+ GdkColor *color;
- if ((str == NULL || *str == '\0') &&
+ if ((str == NULL || *str == '\0') &&
(data->lastentry[source] == NULL || data->lastentry[source][0] == '\0'))
return FALSE;
if (str && data->lastentry[source] && strcmp (str, data->lastentry[source]) == 0)
return FALSE;
- /* For the RC_FILE source we merge the values rather than over-writing
+ /* For the RC_FILE source we merge the values rather than over-writing
* them, since multiple rc files might define independent sets of colors
*/
- if ((source != GTK_SETTINGS_SOURCE_RC_FILE) &&
+ if ((source != GTK_SETTINGS_SOURCE_RC_FILE) &&
data->tables[source] && g_hash_table_size (data->tables[source]) > 0)
{
g_hash_table_unref (data->tables[source]);
@@ -2319,22 +2328,36 @@ update_color_hash (ColorSchemeData *data,
}
if (data->tables[source] == NULL)
- data->tables[source] = g_hash_table_new_full (g_str_hash, g_str_equal,
+ data->tables[source] = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) gdk_color_free);
g_free (data->lastentry[source]);
data->lastentry[source] = g_strdup (str);
-
+
changed |= add_colors_to_hash_from_string (data->tables[source], str);
if (!changed)
return FALSE;
-
+
/* Rebuild the merged hash table. */
- old_hash = data->color_hash;
- data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
- (GDestroyNotify) gdk_color_free);
+ if (data->color_hash)
+ {
+ old_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) gdk_color_free);
+
+ g_hash_table_iter_init (&iter, data->color_hash);
+ while (g_hash_table_iter_next (&iter, &name, &color))
+ {
+ g_hash_table_insert (old_hash, name, color);
+ g_hash_table_iter_steal (&iter);
+ }
+ }
+ else
+ {
+ old_hash = NULL;
+ }
+
for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
{
if (data->tables[i])
@@ -2361,13 +2384,13 @@ update_color_hash (ColorSchemeData *data,
{
changed = TRUE;
break;
- }
+ }
}
}
g_hash_table_unref (old_hash);
}
- else
+ else
changed = TRUE;
return changed;
diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c
index 5926b52557..6cd02c0e2e 100644
--- a/gtk/gtksizegroup.c
+++ b/gtk/gtksizegroup.c
@@ -223,6 +223,10 @@ queue_resize_on_widget (GtkWidget *widget,
if (widget == parent)
real_queue_resize (parent);
}
+ else if (tmp_list->data == widget)
+ {
+ g_warning ("A container and its child are part of this SizeGroup");
+ }
else
queue_resize_on_widget (tmp_list->data, FALSE);
@@ -249,6 +253,10 @@ queue_resize_on_widget (GtkWidget *widget,
if (widget == parent)
real_queue_resize (parent);
}
+ else if (tmp_list->data == widget)
+ {
+ g_warning ("A container and its child are part of this SizeGroup");
+ }
else
queue_resize_on_widget (tmp_list->data, FALSE);
diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c
index 8929648795..f059f8d6de 100644
--- a/gtk/gtksocket.c
+++ b/gtk/gtksocket.c
@@ -372,7 +372,6 @@ _gtk_socket_end_embedding (GtkSocket *socket)
{
GtkSocketPrivate *private = _gtk_socket_get_private (socket);
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
- gint i;
if (GTK_IS_WINDOW (toplevel))
_gtk_socket_windowing_end_embedding_toplevel (socket);
@@ -383,12 +382,7 @@ _gtk_socket_end_embedding (GtkSocket *socket)
socket->current_height = 0;
private->resize_count = 0;
- /* Remove from end to avoid indexes shifting. This is evil */
- for (i = socket->accel_group->n_accels - 1; i >= 0; i--)
- {
- GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
- gtk_accel_group_disconnect (socket->accel_group, accel_entry->closure);
- }
+ gtk_accel_group_disconnect (socket->accel_group, NULL);
}
static void
@@ -594,22 +588,9 @@ _gtk_socket_remove_grabbed_key (GtkSocket *socket,
guint keyval,
GdkModifierType modifiers)
{
- gint i;
-
- for (i = 0; i < socket->accel_group->n_accels; i++)
- {
- GtkAccelGroupEntry *accel_entry = &socket->accel_group->priv_accels[i];
- if (accel_entry->key.accel_key == keyval &&
- accel_entry->key.accel_mods == modifiers)
- {
- gtk_accel_group_disconnect (socket->accel_group,
- accel_entry->closure);
- return;
- }
- }
-
- g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
- keyval, modifiers);
+ if (!gtk_accel_group_disconnect_key (socket->accel_group, keyval, modifiers))
+ g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
+ keyval, modifiers);
}
static void
diff --git a/gtk/gtkspinner.c b/gtk/gtkspinner.c
new file mode 100644
index 0000000000..036d0b1812
--- /dev/null
+++ b/gtk/gtkspinner.c
@@ -0,0 +1,627 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2007 John Stowers, Neil Jagdish Patel.
+ * Copyright (C) 2009 Bastien Nocera, David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Code adapted from egg-spinner
+ * by Christian Hergert <christian.hergert@gmail.com>
+ */
+
+/*
+ * Modified by the GTK+ Team and others 2007. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gtkintl.h"
+#include "gtkaccessible.h"
+#include "gtkimage.h"
+#include "gtkspinner.h"
+#include "gtkstyle.h"
+#include "gtkalias.h"
+
+
+/**
+ * SECTION:gtkspinner
+ * @Short_description: Show a spinner animation
+ * @Title: GtkSpinner
+ * @See_also: #GtkCellRendererSpinner, #GtkProgressBar
+ *
+ * A GtkSpinner widget displays an icon-size spinning animation.
+ * It is often used as an alternative to a #GtkProgressBar for
+ * displaying indefinite activity, instead of actual progress.
+ *
+ * To start the animation, use gtk_spinner_start(), to stop it
+ * use gtk_spinner_stop().
+ */
+
+
+#define GTK_SPINNER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SPINNER, GtkSpinnerPrivate))
+
+G_DEFINE_TYPE (GtkSpinner, gtk_spinner, GTK_TYPE_DRAWING_AREA);
+
+enum {
+ PROP_0,
+ PROP_ACTIVE
+};
+
+struct _GtkSpinnerPrivate
+{
+ guint current;
+ guint num_steps;
+ guint cycle_duration;
+ gboolean active;
+ guint timeout;
+};
+
+static void gtk_spinner_class_init (GtkSpinnerClass *klass);
+static void gtk_spinner_init (GtkSpinner *spinner);
+static void gtk_spinner_dispose (GObject *gobject);
+static void gtk_spinner_realize (GtkWidget *widget);
+static void gtk_spinner_unrealize (GtkWidget *widget);
+static gboolean gtk_spinner_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static void gtk_spinner_screen_changed (GtkWidget *widget,
+ GdkScreen *old_screen);
+static void gtk_spinner_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
+static void gtk_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gtk_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_spinner_set_active (GtkSpinner *spinner,
+ gboolean active);
+static AtkObject *gtk_spinner_get_accessible (GtkWidget *widget);
+static GType gtk_spinner_accessible_get_type (void);
+
+static void
+gtk_spinner_class_init (GtkSpinnerClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ g_type_class_add_private (gobject_class, sizeof (GtkSpinnerPrivate));
+ gobject_class->dispose = gtk_spinner_dispose;
+ gobject_class->get_property = gtk_spinner_get_property;
+ gobject_class->set_property = gtk_spinner_set_property;
+
+ widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->expose_event = gtk_spinner_expose;
+ widget_class->realize = gtk_spinner_realize;
+ widget_class->unrealize = gtk_spinner_unrealize;
+ widget_class->screen_changed = gtk_spinner_screen_changed;
+ widget_class->style_set = gtk_spinner_style_set;
+ widget_class->get_accessible = gtk_spinner_get_accessible;
+
+ /* GtkSpinner:active:
+ *
+ * Whether the spinner is active
+ *
+ * Since 2.20
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ACTIVE,
+ g_param_spec_boolean ("active",
+ P_("Active"),
+ P_("Whether the spinner is active"),
+ FALSE,
+ G_PARAM_READWRITE));
+ /**
+ * GtkSpinner:num-steps:
+ *
+ * The number of steps for the spinner to complete a full loop.
+ * The animation will complete a full cycle in one second by default
+ * (see the #GtkSpinner:cycle-duration style property).
+ *
+ * Since: 2.20
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_uint ("num-steps",
+ P_("Number of steps"),
+ P_("The number of steps for the spinner to complete a full loop. The animation will complete a full cycle in one second by default (see #GtkSpinner:cycle-duration)."),
+ 1,
+ G_MAXUINT,
+ 12,
+ G_PARAM_READABLE));
+
+ /**
+ * GtkSpinner:cycle-duration:
+ *
+ * The duration in milliseconds for the spinner to complete a full cycle.
+ *
+ * Since: 2.20
+ */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_uint ("cycle-duration",
+ P_("Animation duration"),
+ P_("The length of time in milliseconds for the spinner to complete a full loop"),
+ 500,
+ G_MAXUINT,
+ 1000,
+ G_PARAM_READABLE));
+}
+
+static void
+gtk_spinner_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (object)->priv;
+
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ g_value_set_boolean (value, priv->active);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_spinner_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (param_id)
+ {
+ case PROP_ACTIVE:
+ gtk_spinner_set_active (GTK_SPINNER (object), g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+gtk_spinner_init (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER_GET_PRIVATE (spinner);
+ priv->current = 0;
+ priv->timeout = 0;
+
+ spinner->priv = priv;
+
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (spinner), GTK_NO_WINDOW);
+}
+
+static gboolean
+gtk_spinner_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ GtkStateType state_type;
+ GtkSpinnerPrivate *priv;
+ int width, height;
+
+ priv = GTK_SPINNER (widget)->priv;
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ if ((width < 12) || (height <12))
+ gtk_widget_set_size_request (widget, 12, 12);
+
+ state_type = GTK_STATE_NORMAL;
+ if (!GTK_WIDGET_IS_SENSITIVE (widget))
+ state_type = GTK_STATE_INSENSITIVE;
+
+ gtk_paint_spinner (widget->style,
+ widget->window,
+ state_type,
+ priv->current,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+static gboolean
+gtk_spinner_timeout (gpointer data)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (data)->priv;
+
+ if (priv->current + 1 >= priv->num_steps)
+ priv->current = 0;
+ else
+ priv->current++;
+
+ gtk_widget_queue_draw (GTK_WIDGET (data));
+
+ return TRUE;
+}
+
+static void
+gtk_spinner_add_timeout (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = spinner->priv;
+
+ priv->timeout = gdk_threads_add_timeout ((guint) priv->cycle_duration / priv->num_steps, gtk_spinner_timeout, spinner);
+}
+
+static void
+gtk_spinner_remove_timeout (GtkSpinner *spinner)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = spinner->priv;
+
+ g_source_remove (priv->timeout);
+ priv->timeout = 0;
+}
+
+static void
+gtk_spinner_realize (GtkWidget *widget)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (widget)->priv;
+
+ GTK_WIDGET_CLASS (gtk_spinner_parent_class)->realize (widget);
+
+ if (priv->active)
+ gtk_spinner_add_timeout (GTK_SPINNER (widget));
+}
+
+static void
+gtk_spinner_unrealize (GtkWidget *widget)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (widget)->priv;
+
+ if (priv->timeout != 0)
+ {
+ gtk_spinner_remove_timeout (GTK_SPINNER (widget));
+ }
+
+ GTK_WIDGET_CLASS (gtk_spinner_parent_class)->unrealize (widget);
+}
+
+static void
+gtk_spinner_screen_changed (GtkWidget* widget, GdkScreen* old_screen)
+{
+ GtkSpinner *spinner;
+ GdkScreen* new_screen;
+ GdkColormap* colormap;
+
+ spinner = GTK_SPINNER (widget);
+
+ new_screen = gtk_widget_get_screen (widget);
+ colormap = gdk_screen_get_rgba_colormap (new_screen);
+
+ if (!colormap)
+ {
+ colormap = gdk_screen_get_rgb_colormap (new_screen);
+ }
+
+ gtk_widget_set_colormap (widget, colormap);
+}
+
+static void
+gtk_spinner_style_set (GtkWidget *widget,
+ GtkStyle *prev_style)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (widget)->priv;
+
+ gtk_widget_style_get (GTK_WIDGET (widget),
+ "num-steps", &(priv->num_steps),
+ "cycle-duration", &(priv->cycle_duration),
+ NULL);
+
+ if (priv->current > priv->num_steps)
+ priv->current = 0;
+}
+
+static void
+gtk_spinner_dispose (GObject *gobject)
+{
+ GtkSpinnerPrivate *priv;
+
+ priv = GTK_SPINNER (gobject)->priv;
+
+ if (priv->timeout != 0)
+ {
+ gtk_spinner_remove_timeout (GTK_SPINNER (gobject));
+ }
+
+ G_OBJECT_CLASS (gtk_spinner_parent_class)->dispose (gobject);
+}
+
+static void
+gtk_spinner_set_active (GtkSpinner *spinner, gboolean active)
+{
+ GtkSpinnerPrivate *priv;
+
+ active = active != FALSE;
+
+ priv = GTK_SPINNER (spinner)->priv;
+
+ if (priv->active != active)
+ {
+ priv->active = active;
+ g_object_notify (G_OBJECT (spinner), "active");
+
+ if (active && GTK_WIDGET_REALIZED (GTK_WIDGET (spinner)) && priv->timeout == 0)
+ {
+ gtk_spinner_add_timeout (spinner);
+ }
+ else if (!active && priv->timeout != 0)
+ {
+ gtk_spinner_remove_timeout (spinner);
+ }
+ }
+}
+
+static GType
+gtk_spinner_accessible_factory_get_accessible_type (void)
+{
+ return gtk_spinner_accessible_get_type ();
+}
+
+static AtkObject *
+gtk_spinner_accessible_new (GObject *obj)
+{
+ AtkObject *accessible;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (obj), NULL);
+
+ accessible = g_object_new (gtk_spinner_accessible_get_type (), NULL);
+ atk_object_initialize (accessible, obj);
+
+ return accessible;
+}
+
+static AtkObject*
+gtk_spinner_accessible_factory_create_accessible (GObject *obj)
+{
+ return gtk_spinner_accessible_new (obj);
+}
+
+static void
+gtk_spinner_accessible_factory_class_init (AtkObjectFactoryClass *klass)
+{
+ klass->create_accessible = gtk_spinner_accessible_factory_create_accessible;
+ klass->get_accessible_type = gtk_spinner_accessible_factory_get_accessible_type;
+}
+
+static GType
+gtk_spinner_accessible_factory_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type)
+ {
+ const GTypeInfo tinfo =
+ {
+ sizeof (AtkObjectFactoryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_spinner_accessible_factory_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (AtkObjectFactory),
+ 0, /* n_preallocs */
+ NULL, NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_OBJECT_FACTORY,
+ I_("GtkSpinnerAccessibleFactory"),
+ &tinfo, 0);
+ }
+ return type;
+}
+
+static AtkObjectClass *a11y_parent_class = NULL;
+
+static void
+gtk_spinner_accessible_initialize (AtkObject *accessible,
+ gpointer widget)
+{
+ atk_object_set_name (accessible, _("Spinner"));
+ atk_object_set_description (accessible, _("Provides visual status"));
+
+ a11y_parent_class->initialize (accessible, widget);
+}
+
+static void
+gtk_spinner_accessible_class_init (AtkObjectClass *klass)
+{
+ a11y_parent_class = g_type_class_peek_parent (klass);
+
+ klass->initialize = gtk_spinner_accessible_initialize;
+}
+
+static void
+gtk_spinner_accessible_image_get_size (AtkImage *image,
+ gint *width,
+ gint *height)
+{
+ GtkWidget *widget;
+
+ widget = GTK_ACCESSIBLE (image)->widget;
+ if (!widget)
+ {
+ *width = *height = 0;
+ }
+ else
+ {
+ *width = widget->allocation.width;
+ *height = widget->allocation.height;
+ }
+}
+
+static void
+gtk_spinner_accessible_image_interface_init (AtkImageIface *iface)
+{
+ iface->get_image_size = gtk_spinner_accessible_image_get_size;
+}
+
+static GType
+gtk_spinner_accessible_get_type (void)
+{
+ static GType type = 0;
+
+ /* Action interface
+ Name etc. ... */
+ if (G_UNLIKELY (type == 0))
+ {
+ const GInterfaceInfo atk_image_info = {
+ (GInterfaceInitFunc) gtk_spinner_accessible_image_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ GType type;
+ GType parent_atk_type;
+ GTypeInfo tinfo = { 0 };
+ GTypeQuery query;
+ AtkObjectFactory *factory;
+
+ if ((type = g_type_from_name ("GtkSpinnerAccessible")))
+ return type;
+
+ factory = atk_registry_get_factory (atk_get_default_registry (),
+ GTK_TYPE_IMAGE);
+ if (!factory)
+ return G_TYPE_INVALID;
+
+ parent_atk_type = atk_object_factory_get_accessible_type (factory);
+ if (!parent_atk_type)
+ return G_TYPE_INVALID;
+
+ /*
+ * Figure out the size of the class and instance
+ * we are deriving from
+ */
+ g_type_query (parent_atk_type, &query);
+
+ tinfo.class_init = (GClassInitFunc) gtk_spinner_accessible_class_init;
+ tinfo.class_size = query.class_size;
+ tinfo.instance_size = query.instance_size;
+
+ /* Register the type */
+ type = g_type_register_static (parent_atk_type,
+ "GtkSpinnerAccessible",
+ &tinfo, 0);
+
+ g_type_add_interface_static (type, ATK_TYPE_IMAGE,
+ &atk_image_info);
+ }
+
+ return type;
+}
+
+static AtkObject *
+gtk_spinner_get_accessible (GtkWidget *widget)
+{
+ static gboolean first_time = TRUE;
+
+ if (first_time)
+ {
+ AtkObjectFactory *factory;
+ AtkRegistry *registry;
+ GType derived_type;
+ GType derived_atk_type;
+
+ /*
+ * Figure out whether accessibility is enabled by looking at the
+ * type of the accessible object which would be created for
+ * the parent type of GtkSpinner.
+ */
+ derived_type = g_type_parent (GTK_TYPE_SPINNER);
+
+ registry = atk_get_default_registry ();
+ factory = atk_registry_get_factory (registry,
+ derived_type);
+ derived_atk_type = atk_object_factory_get_accessible_type (factory);
+ if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
+ atk_registry_set_factory_type (registry,
+ GTK_TYPE_SPINNER,
+ gtk_spinner_accessible_factory_get_type ());
+ first_time = FALSE;
+ }
+ return GTK_WIDGET_CLASS (gtk_spinner_parent_class)->get_accessible (widget);
+}
+
+/**
+ * gtk_spinner_new:
+ *
+ * Returns a new spinner widget. Not yet started.
+ *
+ * Return value: a new #GtkSpinner
+ *
+ * Since: 2.20
+ */
+GtkWidget *
+gtk_spinner_new (void)
+{
+ return g_object_new (GTK_TYPE_SPINNER, NULL);
+}
+
+/**
+ * gtk_spinner_start:
+ * @spinner: a #GtkSpinner
+ *
+ * Starts the animation of the spinner.
+ *
+ * Since: 2.20
+ */
+void
+gtk_spinner_start (GtkSpinner *spinner)
+{
+ g_return_if_fail (GTK_IS_SPINNER (spinner));
+
+ gtk_spinner_set_active (spinner, TRUE);
+}
+
+/**
+ * gtk_spinner_stop:
+ * @spinner: a #GtkSpinner
+ *
+ * Stops the animation of the spinner.
+ *
+ * Since: 2.20
+ */
+void
+gtk_spinner_stop (GtkSpinner *spinner)
+{
+ g_return_if_fail (GTK_IS_SPINNER (spinner));
+
+ gtk_spinner_set_active (spinner, FALSE);
+}
+
+#define __GTK_SPINNER_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtkspinner.h b/gtk/gtkspinner.h
new file mode 100644
index 0000000000..6f9aa72809
--- /dev/null
+++ b/gtk/gtkspinner.h
@@ -0,0 +1,65 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright (C) 2007 John Stowers, Neil Jagdish Patel.
+ * Copyright (C) 2009 Bastien Nocera, David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Code adapted from egg-spinner
+ * by Christian Hergert <christian.hergert@gmail.com>
+ */
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_SPINNER_H__
+#define __GTK_SPINNER_H__
+
+#include <gtk/gtkdrawingarea.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SPINNER (gtk_spinner_get_type ())
+#define GTK_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SPINNER, GtkSpinner))
+#define GTK_SPINNER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GTK_SPINNER, GtkSpinnerClass))
+#define GTK_IS_SPINNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SPINNER))
+#define GTK_IS_SPINNER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GTK_TYPE_SPINNER))
+#define GTK_SPINNER_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SPINNER, GtkSpinnerClass))
+
+typedef struct _GtkSpinner GtkSpinner;
+typedef struct _GtkSpinnerClass GtkSpinnerClass;
+typedef struct _GtkSpinnerPrivate GtkSpinnerPrivate;
+
+struct _GtkSpinner
+{
+ GtkDrawingArea parent;
+ GtkSpinnerPrivate *priv;
+};
+
+struct _GtkSpinnerClass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+GType gtk_spinner_get_type (void) G_GNUC_CONST;
+GtkWidget *gtk_spinner_new (void);
+void gtk_spinner_start (GtkSpinner *spinner);
+void gtk_spinner_stop (GtkSpinner *spinner);
+
+G_END_DECLS
+
+#endif /* __GTK_SPINNER_H__ */
diff --git a/gtk/gtkstatusbar.c b/gtk/gtkstatusbar.c
index 2bddfa88b6..0a494c912a 100644
--- a/gtk/gtkstatusbar.c
+++ b/gtk/gtkstatusbar.c
@@ -198,6 +198,8 @@ gtk_statusbar_init (GtkStatusbar *statusbar)
box = GTK_BOX (statusbar);
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), TRUE);
+
box->spacing = 2;
box->homogeneous = FALSE;
@@ -616,10 +618,10 @@ gtk_statusbar_create_window (GtkStatusbar *statusbar)
GdkWindowAttr attributes;
gint attributes_mask;
GdkRectangle rect;
-
+
g_return_if_fail (GTK_WIDGET_REALIZED (statusbar));
g_return_if_fail (statusbar->has_resize_grip);
-
+
widget = GTK_WIDGET (statusbar);
get_grip_rect (statusbar, &rect);
@@ -640,6 +642,8 @@ gtk_statusbar_create_window (GtkStatusbar *statusbar)
gdk_window_set_user_data (statusbar->grip_window, widget);
+ gdk_window_raise (statusbar->grip_window);
+
set_grip_cursor (statusbar);
}
@@ -858,10 +862,10 @@ gtk_statusbar_size_allocate (GtkWidget *widget,
if (statusbar->has_resize_grip)
{
- get_grip_rect (statusbar, &rect);
-
+ get_grip_rect (statusbar, &rect);
+
extra_children = has_extra_children (statusbar);
-
+
/* If there are extra children, we don't want them to occupy
* the space where we draw the resize grip, so we temporarily
* shrink the allocation.
@@ -882,14 +886,6 @@ gtk_statusbar_size_allocate (GtkWidget *widget,
if (statusbar->has_resize_grip)
{
- if (statusbar->grip_window)
- {
- gdk_window_raise (statusbar->grip_window);
- gdk_window_move_resize (statusbar->grip_window,
- rect.x, rect.y,
- rect.width, rect.height);
- }
-
if (extra_children)
{
allocation->width += rect.width;
@@ -913,12 +909,23 @@ gtk_statusbar_size_allocate (GtkWidget *widget,
/* shrink the label to make room for the grip */
*allocation = child->allocation;
allocation->width = MAX (1, allocation->width - rect.width);
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
allocation->x += child->allocation.width - allocation->width;
gtk_widget_size_allocate (child, allocation);
}
}
+
+ if (statusbar->grip_window)
+ {
+ get_grip_rect (statusbar, &rect);
+
+ gdk_window_raise (statusbar->grip_window);
+ gdk_window_move_resize (statusbar->grip_window,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
}
}
diff --git a/gtk/gtkstatusicon.c b/gtk/gtkstatusicon.c
index 0d6a262d8d..f400bff73c 100644
--- a/gtk/gtkstatusicon.c
+++ b/gtk/gtkstatusicon.c
@@ -370,6 +370,10 @@ gtk_status_icon_class_init (GtkStatusIconClass *class)
* the default handler for the #GtkStatusIcon::query-tooltip signal
* will take care of displaying the tooltip.
*
+ * Note that some platforms have limitations on the length of tooltips
+ * that they allow on status icons, e.g. Windows only shows the first
+ * 64 characters.
+ *
* Since: 2.16
*/
g_object_class_install_property (gobject_class,
@@ -698,7 +702,7 @@ wndproc (HWND hwnd,
if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
{
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
priv->nid.hWnd = NULL;
continue;
}
@@ -898,7 +902,7 @@ gtk_status_icon_init (GtkStatusIcon *status_icon)
if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
{
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_ADD) failed", __FILE__, __LINE__-2);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
priv->nid.hWnd = NULL;
}
@@ -1348,7 +1352,7 @@ find_icon_size (GtkWidget *widget,
dist = G_MAXINT;
size = GTK_ICON_SIZE_MENU;
- for (s = GTK_ICON_SIZE_MENU; s < GTK_ICON_SIZE_DIALOG; s++)
+ for (s = GTK_ICON_SIZE_MENU; s <= GTK_ICON_SIZE_DIALOG; s++)
{
if (gtk_icon_size_lookup_for_settings (settings, s, &w, &h) &&
w <= pixel_size && h <= pixel_size)
@@ -1387,7 +1391,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags |= NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
if (prev_hicon)
DestroyIcon (prev_hicon);
#endif
@@ -1436,7 +1440,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags |= NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
if (prev_hicon)
DestroyIcon (prev_hicon);
#endif
@@ -1457,7 +1461,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags &= ~NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
#endif
#ifdef GDK_WINDOWING_QUARTZ
[priv->status_item setImage:NULL];
@@ -1487,7 +1491,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags |= NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
if (prev_hicon)
DestroyIcon (prev_hicon);
g_object_unref (pixbuf);
@@ -1531,7 +1535,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags |= NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
if (prev_hicon)
DestroyIcon (prev_hicon);
g_object_unref (pixbuf);
@@ -1578,7 +1582,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags |= NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
if (prev_hicon)
DestroyIcon (prev_hicon);
g_object_unref (pixbuf);
@@ -1611,7 +1615,7 @@ gtk_status_icon_update_image (GtkStatusIcon *status_icon)
priv->nid.uFlags &= ~NIF_ICON;
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIcon(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
#endif
#ifdef GDK_WINDOWING_QUARTZ
{
@@ -2733,7 +2737,7 @@ gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon,
}
if (priv->nid.hWnd != NULL && priv->visible)
if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
- g_warning ("%s:%d:Shell_NotifyIconW(NIM_MODIFY) failed", __FILE__, __LINE__-1);
+ g_warning (G_STRLOC ": Shell_NotifyIconW(NIM_MODIFY) failed");
g_free (priv->tooltip_text);
priv->tooltip_text = g_strdup (text);
diff --git a/gtk/gtkstock.c b/gtk/gtkstock.c
index 153ef0877c..f896dec8f5 100644
--- a/gtk/gtkstock.c
+++ b/gtk/gtkstock.c
@@ -27,6 +27,7 @@
#include "config.h"
#include <string.h>
+#include "gtkprivate.h"
#include "gtkstock.h"
#include "gtkiconfactory.h"
#include "gtkintl.h"
diff --git a/gtk/gtkstyle.c b/gtk/gtkstyle.c
index 769fe79143..01f8ff02a6 100644
--- a/gtk/gtkstyle.c
+++ b/gtk/gtkstyle.c
@@ -313,6 +313,14 @@ static void gtk_default_draw_resize_grip (GtkStyle *style,
gint y,
gint width,
gint height);
+static void gtk_default_draw_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
static void rgb_to_hls (gdouble *r,
gdouble *g,
@@ -511,6 +519,7 @@ gtk_style_class_init (GtkStyleClass *klass)
klass->draw_expander = gtk_default_draw_expander;
klass->draw_layout = gtk_default_draw_layout;
klass->draw_resize_grip = gtk_default_draw_resize_grip;
+ klass->draw_spinner = gtk_default_draw_spinner;
g_type_class_add_private (object_class, sizeof (GtkStylePrivate));
@@ -1764,8 +1773,9 @@ gtk_style_get_style_property (GtkStyle *style,
GtkRcPropertyParser parser;
const GValue *peek_value;
- klass = g_type_class_peek (widget_type);
+ klass = g_type_class_ref (widget_type);
pspec = gtk_widget_class_find_style_property (klass, property_name);
+ g_type_class_unref (klass);
if (!pspec)
{
@@ -5598,6 +5608,80 @@ gtk_default_draw_resize_grip (GtkStyle *style,
}
}
+static void
+gtk_default_draw_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkColor *color;
+ cairo_t *cr;
+ guint num_steps;
+ gdouble dx, dy;
+ gdouble radius;
+ gdouble half;
+ gint i;
+ guint real_step;
+
+ gtk_style_get (style, GTK_TYPE_SPINNER,
+ "num-steps", &num_steps,
+ NULL);
+ real_step = step % num_steps;
+
+ /* get cairo context */
+ cr = gdk_cairo_create (window);
+
+ /* set a clip region for the expose event */
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_clip (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* draw clip region */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ color = &style->fg[state_type];
+ dx = width / 2;
+ dy = height / 2;
+ radius = MIN (width / 2, height / 2);
+ half = num_steps / 2;
+
+ for (i = 0; i < num_steps; i++)
+ {
+ gint inset = 0.7 * radius;
+
+ /* transparency is a function of time and intial value */
+ gdouble t = (gdouble) ((i + num_steps - real_step)
+ % num_steps) / num_steps;
+
+ cairo_save (cr);
+
+ cairo_set_source_rgba (cr,
+ color->red / 65535.,
+ color->green / 65535.,
+ color->blue / 65535.,
+ t);
+
+ cairo_set_line_width (cr, 2.0);
+ cairo_move_to (cr,
+ dx + (radius - inset) * cos (i * G_PI / half),
+ dy + (radius - inset) * sin (i * G_PI / half));
+ cairo_line_to (cr,
+ dx + radius * cos (i * G_PI / half),
+ dy + radius * sin (i * G_PI / half));
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+ }
+
+ /* free memory */
+ cairo_destroy (cr);
+}
+
void
_gtk_style_shade (const GdkColor *a,
GdkColor *b,
@@ -6632,6 +6716,38 @@ gtk_paint_resize_grip (GtkStyle *style,
}
/**
+ * gtk_paint_spinner:
+ * @style: a #GtkStyle
+ * @window: a #GdkWindow
+ * @state_type: a state
+ * @widget: the widget
+ * @step: the nth step, a value between 0 and GtkSpinner::num-steps
+ * @x: the x origin of the rectangle in which to draw the resize grip
+ * @y: the y origin of the rectangle in which to draw the resize grip
+ * @width: the width of the rectangle in which to draw the resize grip
+ * @height: the height of the rectangle in which to draw the resize grip
+ *
+ * Draws a spinner on @window using the given parameters.
+ */
+void
+gtk_paint_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ g_return_if_fail (GTK_IS_STYLE (style));
+ g_return_if_fail (GTK_STYLE_GET_CLASS (style)->draw_spinner != NULL);
+ g_return_if_fail (style->depth == gdk_drawable_get_depth (window));
+
+ GTK_STYLE_GET_CLASS (style)->draw_spinner (style, window, state_type,
+ step, x, y, width, height);
+}
+
+/**
* gtk_border_new:
*
* Allocates a new #GtkBorder structure and initializes its elements to zero.
diff --git a/gtk/gtkstyle.h b/gtk/gtkstyle.h
index a6af1779c1..3e1401bcf4 100644
--- a/gtk/gtkstyle.h
+++ b/gtk/gtkstyle.h
@@ -403,6 +403,14 @@ struct _GtkStyleClass
gint y,
gint width,
gint height);
+ void (*draw_spinner) (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
@@ -416,7 +424,6 @@ struct _GtkStyleClass
void (*_gtk_reserved9) (void);
void (*_gtk_reserved10) (void);
void (*_gtk_reserved11) (void);
- void (*_gtk_reserved12) (void);
};
struct _GtkBorder
@@ -856,7 +863,14 @@ void gtk_paint_resize_grip (GtkStyle *style,
gint y,
gint width,
gint height);
-
+void gtk_paint_spinner (GtkStyle *style,
+ GdkWindow *window,
+ GtkStateType state_type,
+ guint step,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
GType gtk_border_get_type (void) G_GNUC_CONST;
GtkBorder *gtk_border_new (void) G_GNUC_MALLOC;
diff --git a/gtk/gtktestutils.c b/gtk/gtktestutils.c
index 383af9a7a1..64bf351976 100644
--- a/gtk/gtktestutils.c
+++ b/gtk/gtktestutils.c
@@ -21,6 +21,8 @@
/* need to get the prototypes of all get_type functions */
#define GTK_ENABLE_BROKEN
#undef GTK_DISABLE_DEPRECATED
+/* Need to get GDK_WINDOW_OBJECT */
+#undef GDK_DISABLE_DEPRECATED
#include "config.h"
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c
index ceaa11344a..f82b6d875b 100644
--- a/gtk/gtktextbuffer.c
+++ b/gtk/gtktextbuffer.c
@@ -3807,11 +3807,7 @@ gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
else
{
if (interactive)
- {
- gtk_text_buffer_begin_user_action (buffer);
- gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
- gtk_text_buffer_end_user_action (buffer);
- }
+ gtk_text_buffer_delete_interactive (buffer, &start, &end, default_editable);
else
gtk_text_buffer_delete (buffer, &start, &end);
@@ -3887,13 +3883,14 @@ gtk_text_buffer_backspace (GtkTextBuffer *buffer,
if (gtk_text_buffer_delete_interactive (buffer, &start, &end,
default_editable))
{
- if (backspace_deletes_character)
+ /* special case \r\n, since we never want to reinsert \r */
+ if (backspace_deletes_character && strcmp ("\r\n", cluster_text))
{
gchar *normalized_text = g_utf8_normalize (cluster_text,
strlen (cluster_text),
G_NORMALIZE_NFD);
glong len = g_utf8_strlen (normalized_text, -1);
-
+
if (len > 1)
gtk_text_buffer_insert_interactive (buffer,
&start,
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c
index 319b8ce645..8c5d419b63 100644
--- a/gtk/gtktextlayout.c
+++ b/gtk/gtktextlayout.c
@@ -1812,56 +1812,59 @@ allocate_child_widgets (GtkTextLayout *text_layout,
{
PangoLayout *layout = display->layout;
PangoLayoutIter *run_iter;
-
+
run_iter = pango_layout_get_iter (layout);
-
do
{
PangoLayoutRun *run = pango_layout_iter_get_run_readonly (run_iter);
-
+
if (run && is_shape (run))
{
gint byte_index;
GtkTextIter text_iter;
- GtkTextChildAnchor *anchor = 0;
- GList *widgets = 0;
-
- /* The pango iterator iterates in visual order.
+ GtkTextChildAnchor *anchor = NULL;
+ GList *widgets = NULL;
+ GList *l;
+
+ /* The pango iterator iterates in visual order.
* We use the byte index to find the child widget.
*/
-
byte_index = pango_layout_iter_get_index (run_iter);
line_display_index_to_iter (text_layout, display, &text_iter, byte_index, 0);
anchor = gtk_text_iter_get_child_anchor (&text_iter);
- widgets = gtk_text_child_anchor_get_widgets (anchor);
-
- if (widgets)
+ if (anchor)
+ widgets = gtk_text_child_anchor_get_widgets (anchor);
+
+ for (l = widgets; l; l = l->next)
{
PangoRectangle extents;
- GtkWidget *child = widgets->data;
+ GtkWidget *child = l->data;
- /* We emit "allocate_child" with the x,y of
- * the widget with respect to the top of the line
- * and the left side of the buffer
- */
-
- pango_layout_iter_get_run_extents (run_iter,
- NULL,
- &extents);
-
- g_signal_emit (text_layout,
- signals[ALLOCATE_CHILD],
- 0,
- child,
- PANGO_PIXELS (extents.x) + display->x_offset,
- PANGO_PIXELS (extents.y) + display->top_margin);
-
- g_list_free (widgets);
+ if (_gtk_anchored_child_get_layout (child) == text_layout)
+ {
+
+ /* We emit "allocate_child" with the x,y of
+ * the widget with respect to the top of the line
+ * and the left side of the buffer
+ */
+ pango_layout_iter_get_run_extents (run_iter,
+ NULL,
+ &extents);
+
+ g_signal_emit (text_layout,
+ signals[ALLOCATE_CHILD],
+ 0,
+ child,
+ PANGO_PIXELS (extents.x) + display->x_offset,
+ PANGO_PIXELS (extents.y) + display->top_margin);
+ }
}
+
+ g_list_free (widgets);
}
}
while (pango_layout_iter_next_run (run_iter));
-
+
pango_layout_iter_free (run_iter);
}
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index bf2d4b12b6..0c41e24c21 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -349,6 +349,7 @@ static GtkAdjustment* get_vadjustment (GtkTextView *text_view);
static void gtk_text_view_do_popup (GtkTextView *text_view,
GdkEventButton *event);
+static void cancel_pending_scroll (GtkTextView *text_view);
static void gtk_text_view_queue_scroll (GtkTextView *text_view,
GtkTextMark *mark,
gdouble within_margin,
@@ -1412,16 +1413,21 @@ gtk_text_view_set_buffer (GtkTextView *text_view,
g_signal_handlers_disconnect_by_func (text_view->buffer,
gtk_text_view_paste_done_handler,
text_view);
- g_object_unref (text_view->buffer);
- text_view->dnd_mark = NULL;
- text_view->first_para_mark = NULL;
if (GTK_WIDGET_REALIZED (text_view))
{
GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view),
GDK_SELECTION_PRIMARY);
gtk_text_buffer_remove_selection_clipboard (text_view->buffer, clipboard);
- }
+ }
+
+ if (text_view->layout)
+ gtk_text_layout_set_buffer (text_view->layout, NULL);
+
+ g_object_unref (text_view->buffer);
+ text_view->dnd_mark = NULL;
+ text_view->first_para_mark = NULL;
+ cancel_pending_scroll (text_view);
}
text_view->buffer = buffer;
@@ -2154,6 +2160,11 @@ gtk_text_view_scroll_to_mark (GtkTextView *text_view,
g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
+ /* We need to verify that the buffer contains the mark, otherwise this
+ * can lead to data structure corruption later on.
+ */
+ g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
+
gtk_text_view_queue_scroll (text_view, mark,
within_margin,
use_align,
@@ -2183,6 +2194,11 @@ gtk_text_view_scroll_mark_onscreen (GtkTextView *text_view,
g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+ /* We need to verify that the buffer contains the mark, otherwise this
+ * can lead to data structure corruption later on.
+ */
+ g_return_if_fail (get_buffer (text_view) == gtk_text_mark_get_buffer (mark));
+
gtk_text_view_scroll_to_mark (text_view, mark, 0.0, FALSE, 0.0, 0.0);
}
@@ -4314,7 +4330,8 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
&start, &end) &&
- gtk_text_iter_in_range (&iter, &start, &end))
+ gtk_text_iter_in_range (&iter, &start, &end) &&
+ !(event->state & GDK_SHIFT_MASK))
{
text_view->drag_start_x = event->x;
text_view->drag_start_y = event->y;
@@ -7195,6 +7212,11 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
*/
gtk_text_view_update_layout_width (text_view);
+ /* We also update the IM spot location here, since the IM context
+ * might do something that leads to validation.
+ */
+ gtk_text_view_update_im_spot_location (text_view);
+
/* note that validation of onscreen could invoke this function
* recursively, by scrolling to maintain first_para, or in response
* to updating the layout width, however there is no problem with
@@ -7229,6 +7251,9 @@ gtk_text_view_value_changed (GtkAdjustment *adj,
text_view->first_validate_idle = 0;
}
+ /* Finally we update the IM cursor location again, to ensure any
+ * changes made by the validation are pushed through.
+ */
gtk_text_view_update_im_spot_location (text_view);
DV(g_print(">End scroll offset changed handler ("G_STRLOC")\n"));
diff --git a/gtk/gtktoolbutton.c b/gtk/gtktoolbutton.c
index c9e63f6a68..6eae655931 100644
--- a/gtk/gtktoolbutton.c
+++ b/gtk/gtktoolbutton.c
@@ -963,6 +963,8 @@ gtk_tool_button_set_label (GtkToolButton *button,
const gchar *label)
{
gchar *old_label;
+ gchar *elided_label;
+ AtkObject *accessible;
g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
@@ -971,6 +973,14 @@ gtk_tool_button_set_label (GtkToolButton *button,
button->priv->label_text = g_strdup (label);
button->priv->contents_invalid = TRUE;
+ if (label)
+ {
+ elided_label = _gtk_toolbar_elide_underscores (label);
+ accessible = gtk_widget_get_accessible (GTK_WIDGET (button->priv->button));
+ atk_object_set_name (accessible, elided_label);
+ g_free (elided_label);
+ }
+
g_free (old_label);
g_object_notify (G_OBJECT (button), "label");
diff --git a/gtk/gtktoolitem.c b/gtk/gtktoolitem.c
index 411cd1ca3a..8f7406a9a9 100644
--- a/gtk/gtktoolitem.c
+++ b/gtk/gtktoolitem.c
@@ -39,6 +39,22 @@
/**
* SECTION:gtktoolitem
* @short_description: The base class of widgets that can be added to GtkToolShell
+ * @see_also: <variablelist>
+ * <varlistentry>
+ * <term>#GtkToolbar</term>
+ * <listitem><para>The toolbar widget</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkToolButton</term>
+ * <listitem><para>A subclass of #GtkToolItem that displays buttons on
+ * the toolbar</para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>#GtkSeparatorToolItem</term>
+ * <listitem><para>A subclass of #GtkToolItem that separates groups of
+ * items on a toolbar</para></listitem>
+ * </varlistentry>
+ * </variablelist>
*
* #GtkToolItem<!-- -->s are widgets that can appear on a toolbar. To
* create a toolbar item that contain something else than a button, use
diff --git a/gtk/gtktoolshell.c b/gtk/gtktoolshell.c
index f7be68a523..ec1c10b5ca 100644
--- a/gtk/gtktoolshell.c
+++ b/gtk/gtktoolshell.c
@@ -29,6 +29,7 @@
/**
* SECTION:gtktoolshell
* @short_description: Interface for containers containing GtkToolItem widgets.
+ * @Title: GtkToolShell
*
* The #GtkToolShell interface allows container widgets to provide additional
* information when embedding #GtkToolItem widgets.
diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c
index 77e47772cd..1b628776f0 100644
--- a/gtk/gtktooltip.c
+++ b/gtk/gtktooltip.c
@@ -84,7 +84,7 @@ struct _GtkTooltipClass
static void gtk_tooltip_class_init (GtkTooltipClass *klass);
static void gtk_tooltip_init (GtkTooltip *tooltip);
-static void gtk_tooltip_finalize (GObject *object);
+static void gtk_tooltip_dispose (GObject *object);
static void gtk_tooltip_window_style_set (GtkTooltip *tooltip);
static gboolean gtk_tooltip_paint_window (GtkTooltip *tooltip);
@@ -106,7 +106,7 @@ gtk_tooltip_class_init (GtkTooltipClass *klass)
object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = gtk_tooltip_finalize;
+ object_class->dispose = gtk_tooltip_dispose;
}
static void
@@ -166,7 +166,7 @@ gtk_tooltip_init (GtkTooltip *tooltip)
}
static void
-gtk_tooltip_finalize (GObject *object)
+gtk_tooltip_dispose (GObject *object)
{
GtkTooltip *tooltip = GTK_TOOLTIP (object);
@@ -194,9 +194,10 @@ gtk_tooltip_finalize (GObject *object)
gtk_tooltip_display_closed,
tooltip);
gtk_widget_destroy (tooltip->window);
+ tooltip->window = NULL;
}
- G_OBJECT_CLASS (gtk_tooltip_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gtk_tooltip_parent_class)->dispose (object);
}
/* public API */
@@ -317,9 +318,9 @@ gtk_tooltip_set_icon_from_stock (GtkTooltip *tooltip,
* Since: 2.14
*/
void
-gtk_tooltip_set_icon_from_icon_name(GtkTooltip *tooltip,
- const gchar *icon_name,
- GtkIconSize size)
+gtk_tooltip_set_icon_from_icon_name (GtkTooltip *tooltip,
+ const gchar *icon_name,
+ GtkIconSize size)
{
g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
@@ -332,6 +333,32 @@ gtk_tooltip_set_icon_from_icon_name(GtkTooltip *tooltip,
}
/**
+ * gtk_tooltip_set_from_gicon:
+ * @tooltip: a #GtkTooltip
+ * @gicon: a #GIcon representing the icon, or %NULL
+ * @size: a stock icon size
+ * Sets the icon of the tooltip (which is in front of the text) to be
+ * the icon indicated by @gicon with the size indicated
+ * by @size. If @icon_name is %NULL, the image will be hidden.
+ *
+ * Since: 2.20
+ */
+void
+gtk_tooltip_set_icon_from_gicon (GtkTooltip *tooltip,
+ GIcon *gicon,
+ GtkIconSize size)
+{
+ g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+ gtk_image_set_from_gicon (GTK_IMAGE (tooltip->image), gicon, size);
+
+ if (gicon)
+ gtk_widget_show (tooltip->image);
+ else
+ gtk_widget_hide (tooltip->image);
+}
+
+/**
* gtk_tooltip_set_custom:
* @tooltip: a #GtkTooltip
* @custom_widget: a #GtkWidget, or %NULL to unset the old custom widget.
@@ -474,6 +501,8 @@ gtk_tooltip_window_style_set (GtkTooltip *tooltip)
tooltip->window->style->ythickness,
tooltip->window->style->xthickness,
tooltip->window->style->xthickness);
+ gtk_box_set_spacing (GTK_BOX (tooltip->box),
+ tooltip->window->style->xthickness);
gtk_widget_queue_draw (tooltip->window);
}
@@ -767,6 +796,9 @@ static void
gtk_tooltip_set_last_window (GtkTooltip *tooltip,
GdkWindow *window)
{
+ if (tooltip->last_window == window)
+ return;
+
if (tooltip->last_window)
g_object_remove_weak_pointer (G_OBJECT (tooltip->last_window),
(gpointer *) &tooltip->last_window);
@@ -945,8 +977,6 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
g_object_get (tooltip_widget, "has-tooltip", &has_tooltip, NULL);
- g_assert (tooltip != NULL);
-
return_value = gtk_tooltip_run_requery (&tooltip_widget, tooltip, &x, &y);
if (!return_value)
return;
@@ -1048,11 +1078,17 @@ tooltip_popup_timeout (gpointer data)
GtkTooltip *tooltip;
display = GDK_DISPLAY_OBJECT (data);
+ tooltip = g_object_get_data (G_OBJECT (display),
+ "gdk-display-current-tooltip");
+
+ /* This usually does not happen. However, it does occur in language
+ * bindings were reference counting of objects behaves differently.
+ */
+ if (!tooltip)
+ return FALSE;
gtk_tooltip_show_tooltip (display);
- tooltip = g_object_get_data (G_OBJECT (display),
- "gdk-display-current-tooltip");
tooltip->timeout_id = 0;
return FALSE;
@@ -1068,7 +1104,7 @@ gtk_tooltip_start_delay (GdkDisplay *display)
tooltip = g_object_get_data (G_OBJECT (display),
"gdk-display-current-tooltip");
- if (tooltip && GTK_TOOLTIP_VISIBLE (tooltip))
+ if (!tooltip || GTK_TOOLTIP_VISIBLE (tooltip))
return;
if (tooltip->timeout_id)
diff --git a/gtk/gtktooltip.h b/gtk/gtktooltip.h
index 8039da6fbc..5271376798 100644
--- a/gtk/gtktooltip.h
+++ b/gtk/gtktooltip.h
@@ -48,6 +48,9 @@ void gtk_tooltip_set_icon_from_stock (GtkTooltip *tooltip,
void gtk_tooltip_set_icon_from_icon_name (GtkTooltip *tooltip,
const gchar *icon_name,
GtkIconSize size);
+void gtk_tooltip_set_icon_from_gicon (GtkTooltip *tooltip,
+ GIcon *gicon,
+ GtkIconSize size);
void gtk_tooltip_set_custom (GtkTooltip *tooltip,
GtkWidget *custom_widget);
diff --git a/gtk/gtktreemodelfilter.c b/gtk/gtktreemodelfilter.c
index cc5b86ebba..074a7a4fa1 100644
--- a/gtk/gtktreemodelfilter.c
+++ b/gtk/gtktreemodelfilter.c
@@ -73,7 +73,7 @@ struct _FilterLevel
gint ref_count;
gint visible_nodes;
- FilterElt *parent_elt;
+ gint parent_elt_index;
FilterLevel *parent_level;
};
@@ -129,6 +129,9 @@ enum
#define FILTER_ELT(filter_elt) ((FilterElt *)filter_elt)
#define FILTER_LEVEL(filter_level) ((FilterLevel *)filter_level)
+#define FILTER_LEVEL_PARENT_ELT(level) (&g_array_index (FILTER_LEVEL ((level))->parent_level->array, FilterElt, FILTER_LEVEL ((level))->parent_elt_index))
+#define FILTER_LEVEL_ELT_INDEX(level, elt) (FILTER_ELT ((elt)) - FILTER_ELT (FILTER_LEVEL ((level))->array->data))
+
/* general code (object/interface init, properties, etc) */
static void gtk_tree_model_filter_tree_model_init (GtkTreeModelIface *iface);
static void gtk_tree_model_filter_drag_source_init (GtkTreeDragSourceIface *iface);
@@ -214,7 +217,7 @@ static gboolean gtk_tree_model_filter_drag_data_delete (GtkTr
/* private functions */
static void gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
FilterLevel *parent_level,
- FilterElt *parent_elt,
+ gint parent_elt_index,
gboolean emit_inserted);
static void gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
@@ -257,6 +260,8 @@ static GtkTreePath *gtk_real_tree_model_filter_convert_child_path_to_path (GtkTr
static FilterElt *gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
FilterLevel *level,
int n);
+static gboolean gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
+ FilterElt *elt);
static FilterElt *gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
FilterLevel *level,
int n);
@@ -436,12 +441,13 @@ gtk_tree_model_filter_get_property (GObject *object,
static void
gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
FilterLevel *parent_level,
- FilterElt *parent_elt,
+ gint parent_elt_index,
gboolean emit_inserted)
{
GtkTreeIter iter;
GtkTreeIter first_node;
GtkTreeIter root;
+ FilterElt *parent_elt = NULL;
FilterLevel *new_level;
gint length = 0;
gint i;
@@ -474,6 +480,8 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
GtkTreeIter parent_iter;
GtkTreeIter child_parent_iter;
+ parent_elt = &g_array_index (parent_level->array, FilterElt, parent_elt_index);
+
parent_iter.stamp = filter->priv->stamp;
parent_iter.user_data = parent_level;
parent_iter.user_data2 = parent_elt;
@@ -499,10 +507,10 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
length);
new_level->ref_count = 0;
new_level->visible_nodes = 0;
- new_level->parent_elt = parent_elt;
+ new_level->parent_elt_index = parent_elt_index;
new_level->parent_level = parent_level;
- if (parent_elt)
+ if (parent_elt_index >= 0)
parent_elt->children = new_level;
else
filter->priv->root = new_level;
@@ -510,9 +518,9 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
/* increase the count of zero ref_counts */
while (parent_level)
{
- parent_elt->zero_ref_count++;
+ g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count++;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
if (new_level != filter->priv->root)
@@ -526,6 +534,7 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
{
if (gtk_tree_model_filter_visible (filter, &iter))
{
+ GtkTreeIter f_iter;
FilterElt filter_elt;
filter_elt.offset = i;
@@ -540,26 +549,29 @@ gtk_tree_model_filter_build_level (GtkTreeModelFilter *filter,
g_array_append_val (new_level->array, filter_elt);
new_level->visible_nodes++;
- if (new_level->parent_level || filter->priv->virtual_root)
- {
- GtkTreeIter f_iter;
-
- f_iter.stamp = filter->priv->stamp;
- f_iter.user_data = new_level;
- f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
-
- gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
+ f_iter.stamp = filter->priv->stamp;
+ f_iter.user_data = new_level;
+ f_iter.user_data2 = &(g_array_index (new_level->array, FilterElt, new_level->array->len - 1));
- if (emit_inserted)
- {
- GtkTreePath *f_path;
+ if (new_level->parent_level || filter->priv->virtual_root)
+ gtk_tree_model_filter_ref_node (GTK_TREE_MODEL (filter), &f_iter);
- f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
- &f_iter);
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter),
- f_path, &f_iter);
- gtk_tree_path_free (f_path);
- }
+ if (emit_inserted)
+ {
+ GtkTreePath *f_path;
+ GtkTreeIter children;
+
+ f_path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter),
+ &f_iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter),
+ f_path, &f_iter);
+ gtk_tree_path_free (f_path);
+
+ if (gtk_tree_model_iter_children (filter->priv->child_model,
+ &children, &iter))
+ gtk_tree_model_filter_update_children (filter,
+ new_level,
+ FILTER_ELT (f_iter.user_data2));
}
}
i++;
@@ -626,13 +638,13 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
if (filter_level->ref_count == 0)
{
FilterLevel *parent_level = filter_level->parent_level;
- FilterElt *parent_elt = filter_level->parent_elt;
+ gint parent_elt_index = filter_level->parent_elt_index;
while (parent_level)
{
- parent_elt->zero_ref_count--;
+ g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count--;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -640,8 +652,8 @@ gtk_tree_model_filter_free_level (GtkTreeModelFilter *filter,
filter->priv->zero_ref_count--;
}
- if (filter_level->parent_elt)
- filter_level->parent_elt->children = NULL;
+ if (filter_level->parent_elt_index >= 0)
+ FILTER_LEVEL_PARENT_ELT (filter_level)->children = NULL;
else
filter->priv->root = NULL;
@@ -672,7 +684,10 @@ gtk_tree_model_filter_elt_get_path (FilterLevel *level,
{
gtk_tree_path_prepend_index (path, walker2->offset);
- walker2 = walker->parent_elt;
+ if (!walker->parent_level)
+ break;
+
+ walker2 = FILTER_LEVEL_PARENT_ELT (walker);
walker = walker->parent_level;
}
@@ -804,6 +819,32 @@ gtk_tree_model_filter_get_nth (GtkTreeModelFilter *filter,
return &g_array_index (level->array, FilterElt, n);
}
+static gboolean
+gtk_tree_model_filter_elt_is_visible_in_target (FilterLevel *level,
+ FilterElt *elt)
+{
+ gint elt_index;
+
+ if (!elt->visible)
+ return FALSE;
+
+ if (level->parent_elt_index == -1)
+ return TRUE;
+
+ do
+ {
+ elt_index = level->parent_elt_index;
+ level = level->parent_level;
+
+ if (elt_index >= 0
+ && !g_array_index (level->array, FilterElt, elt_index).visible)
+ return FALSE;
+ }
+ while (level);
+
+ return TRUE;
+}
+
static FilterElt *
gtk_tree_model_filter_get_nth_visible (GtkTreeModelFilter *filter,
FilterLevel *level,
@@ -848,11 +889,11 @@ gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
FilterElt elt;
/* check if child exists and is visible */
- if (level->parent_elt)
+ if (level->parent_elt_index >= 0)
{
c_parent_path =
gtk_tree_model_filter_elt_get_path (level->parent_level,
- level->parent_elt,
+ FILTER_LEVEL_PARENT_ELT (level),
filter->priv->virtual_root);
if (!c_parent_path)
return NULL;
@@ -931,7 +972,7 @@ gtk_tree_model_filter_fetch_child (GtkTreeModelFilter *filter,
{
FilterElt *e = &(g_array_index (level->array, FilterElt, i));
if (e->children)
- e->children->parent_elt = e;
+ e->children->parent_elt_index = i;
}
c_iter.stamp = filter->priv->stamp;
@@ -950,14 +991,18 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
{
FilterElt *elt, *parent;
FilterLevel *level, *parent_level;
- gint i, length;
+ gint i, length, parent_elt_index;
gboolean emit_child_toggled = FALSE;
level = FILTER_LEVEL (iter->user_data);
elt = FILTER_ELT (iter->user_data2);
- parent = level->parent_elt;
+ parent_elt_index = level->parent_elt_index;
+ if (parent_elt_index >= 0)
+ parent = FILTER_LEVEL_PARENT_ELT (level);
+ else
+ parent = NULL;
parent_level = level->parent_level;
length = level->array->len;
@@ -972,7 +1017,10 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
* if level != root level and visible nodes == 0, emit row-has-child-toggled.
*/
- if (level != filter->priv->root && level->visible_nodes == 0)
+ if (level != filter->priv->root
+ && level->visible_nodes == 0
+ && parent
+ && parent->visible)
emit_child_toggled = TRUE;
if (length > 1)
@@ -980,9 +1028,13 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
GtkTreePath *path;
FilterElt *tmp;
- /* we emit row-deleted, and remove the node from the cache.
+ /* We emit row-deleted, and remove the node from the cache.
+ * If it has any children, these will be removed here as well.
*/
+ if (elt->children)
+ gtk_tree_model_filter_free_level (filter, elt->children);
+
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
elt->visible = FALSE;
gtk_tree_model_filter_increment_stamp (filter);
@@ -1015,7 +1067,7 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
*/
elt = &g_array_index (level->array, FilterElt, i);
if (elt->children)
- elt->children->parent_elt = elt;
+ elt->children->parent_elt_index = i;
}
}
}
@@ -1024,10 +1076,16 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
{
GtkTreePath *path;
- /* we emit row-deleted, but keep the node in the cache and
- * referenced.
+ /* We emit row-deleted, but keep the node in the cache and
+ * referenced. Its children will be removed.
*/
+ if (elt->children)
+ {
+ gtk_tree_model_filter_free_level (filter, elt->children);
+ elt->children = NULL;
+ }
+
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
elt->visible = FALSE;
gtk_tree_model_filter_increment_stamp (filter);
@@ -1038,7 +1096,7 @@ gtk_tree_model_filter_remove_node (GtkTreeModelFilter *filter,
{
GtkTreePath *path;
- /* blow level away */
+ /* Blow level away, including any child levels */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), iter);
elt->visible = FALSE;
@@ -1170,6 +1228,7 @@ gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
gboolean requested_state;
gboolean current_state;
gboolean free_c_path = FALSE;
+ gboolean signals_emitted = FALSE;
g_return_if_fail (c_path != NULL || c_iter != NULL);
@@ -1230,14 +1289,18 @@ gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
*/
gtk_tree_path_free (path);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter);
level = FILTER_LEVEL (iter.user_data);
elt = FILTER_ELT (iter.user_data2);
- /* and update the children */
- if (gtk_tree_model_iter_children (c_model, &children, &real_c_iter))
- gtk_tree_model_filter_update_children (filter, level, elt);
+ if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
+ {
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (filter), path, &iter);
+
+ /* and update the children */
+ if (gtk_tree_model_iter_children (c_model, &children, &real_c_iter))
+ gtk_tree_model_filter_update_children (filter, level, elt);
+ }
goto done;
}
@@ -1250,27 +1313,29 @@ gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
/* make sure the new item has been pulled in */
if (!filter->priv->root)
{
- gint i;
FilterLevel *root;
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, TRUE);
- root = FILTER_LEVEL (filter->priv->root);
+ /* We will only proceed below if the item is found. If the item
+ * is found, we can be sure row-inserted has just been emitted
+ * for it.
+ */
+ signals_emitted = TRUE;
- if (root)
- {
- for (i = 0; i < root->array->len; i++)
- g_array_index (root->array, FilterElt, i).visible = FALSE;
- root->visible_nodes = 0;
- }
+ root = FILTER_LEVEL (filter->priv->root);
}
gtk_tree_model_filter_increment_stamp (filter);
+ /* We need to allow to build new levels, because we are then pulling
+ * in a child in an invisible level. We only want to find path if it
+ * is in a visible level (and thus has a parent that is visible).
+ */
if (!path)
path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
c_path,
- TRUE,
+ FALSE,
TRUE);
if (!path)
@@ -1289,15 +1354,32 @@ gtk_tree_model_filter_row_changed (GtkTreeModel *c_model,
level->visible_nodes++;
}
- if ((level->parent_elt && level->parent_elt->visible) || !level->parent_elt)
+ if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
{
/* visibility changed -- reget path */
gtk_tree_path_free (path);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
+ if (!signals_emitted)
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
+
+ if (level->parent_level && level->visible_nodes == 1)
+ {
+ /* We know that this is the first visible node in this level, so
+ * we need to emit row-has-child-toggled on the parent. This
+ * does not apply to the root level.
+ */
+
+ gtk_tree_path_up (path);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (filter), &iter, path);
+
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (filter),
+ path,
+ &iter);
+ }
- if (gtk_tree_model_iter_children (c_model, &children, c_iter))
+ if (!signals_emitted
+ && gtk_tree_model_iter_children (c_model, &children, c_iter))
gtk_tree_model_filter_update_children (filter, level, elt);
}
@@ -1379,7 +1461,7 @@ gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
goto done;
/* build level will pull in the new child */
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
if (filter->priv->root
&& FILTER_LEVEL (filter->priv->root)->visible_nodes)
@@ -1506,7 +1588,7 @@ gtk_tree_model_filter_row_inserted (GtkTreeModel *c_model,
{
FilterElt *e = &g_array_index (level->array, FilterElt, i);
if (e->children)
- e->children->parent_elt = e;
+ e->children->parent_elt_index = i;
}
/* don't emit the signal if we aren't visible */
@@ -1555,6 +1637,7 @@ gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
GtkTreeIter iter;
FilterLevel *level;
FilterElt *elt;
+ gboolean requested_state;
g_return_if_fail (c_path != NULL && c_iter != NULL);
@@ -1564,12 +1647,13 @@ gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
if (filter->priv->virtual_root && !filter->priv->root
&& !gtk_tree_path_compare (c_path, filter->priv->virtual_root))
{
- gtk_tree_model_filter_build_level (filter, NULL, NULL, TRUE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, TRUE);
return;
}
- if (!gtk_tree_model_filter_visible (filter, c_iter))
- return;
+ /* For all other levels, there is a chance that the visibility state
+ * of the parent has changed now.
+ */
path = gtk_real_tree_model_filter_convert_child_path_to_path (filter,
c_path,
@@ -1580,18 +1664,60 @@ gtk_tree_model_filter_row_has_child_toggled (GtkTreeModel *c_model,
gtk_tree_model_filter_get_iter_full (GTK_TREE_MODEL (data), &iter, path);
- gtk_tree_path_free (path);
-
level = FILTER_LEVEL (iter.user_data);
elt = FILTER_ELT (iter.user_data2);
- g_assert (elt->visible);
+ gtk_tree_path_free (path);
+
+ requested_state = gtk_tree_model_filter_visible (filter, c_iter);
+
+ if (!elt->visible && !requested_state)
+ {
+ /* The parent node currently is not visible and will not become
+ * visible, so we will not pass on the row-has-child-toggled event.
+ */
+ return;
+ }
+ else if (elt->visible && !requested_state)
+ {
+ /* The node is no longer visible, so it has to be removed.
+ * _remove_node() takes care of emitting row-has-child-toggled
+ * when required.
+ */
+ level->visible_nodes--;
+
+ gtk_tree_model_filter_remove_node (filter, &iter);
+
+ return;
+ }
+ else if (!elt->visible && requested_state)
+ {
+ elt->visible = TRUE;
+ level->visible_nodes++;
+
+ /* Only insert if the parent is visible in the target */
+ if (gtk_tree_model_filter_elt_is_visible_in_target (level, elt))
+ {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (filter), &iter);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (filter), path, &iter);
+ gtk_tree_path_free (path);
+
+ /* We do not update children now, because that will happen
+ * below.
+ */
+ }
+ }
+ /* For the remaining possibility, elt->visible && requested_state
+ * no action is required.
+ */
/* If this node is referenced and has children, build the level so we
* can monitor it for changes.
*/
if (elt->ref_count > 1 && gtk_tree_model_iter_has_child (c_model, c_iter))
- gtk_tree_model_filter_build_level (filter, level, elt, TRUE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, elt),
+ TRUE);
/* get a path taking only visible nodes into account */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (data), &iter);
@@ -1607,11 +1733,12 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
GtkTreeModelFilter *filter = GTK_TREE_MODEL_FILTER (data);
GtkTreePath *path;
GtkTreeIter iter;
- FilterElt *elt, *parent = NULL;
+ FilterElt *elt;
FilterLevel *level, *parent_level = NULL;
gboolean emit_child_toggled = FALSE;
gint offset;
gint i;
+ gint parent_elt_index = -1;
g_return_if_fail (c_path != NULL);
@@ -1749,7 +1876,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
if (elt->offset > offset)
elt->offset--;
if (elt->children)
- elt->children->parent_elt = elt;
+ elt->children->parent_elt_index = i;
}
return;
@@ -1774,7 +1901,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
{
emit_child_toggled = TRUE;
parent_level = level->parent_level;
- parent = level->parent_elt;
+ parent_elt_index = level->parent_elt_index;
}
/* emit row_deleted */
@@ -1819,7 +1946,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
if (elt->offset > offset)
elt->offset--;
if (elt->children)
- elt->children->parent_elt = elt;
+ elt->children->parent_elt_index = i;
}
}
@@ -1830,7 +1957,7 @@ gtk_tree_model_filter_row_deleted (GtkTreeModel *c_model,
iter.stamp = filter->priv->stamp;
iter.user_data = parent_level;
- iter.user_data2 = parent;
+ iter.user_data2 = &g_array_index (parent_level->array, FilterElt, parent_elt_index);
/* We set in_row_deleted to TRUE to avoid a level build triggered
* by row-has-child-toggled (parent model could call iter_has_child
@@ -2013,7 +2140,7 @@ gtk_tree_model_filter_rows_reordered (GtkTreeModel *c_model,
{
FilterElt *e = &g_array_index (level->array, FilterElt, i);
if (e->children)
- e->children->parent_elt = e;
+ e->children->parent_elt_index = i;
}
/* emit rows_reordered */
@@ -2114,7 +2241,7 @@ gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
indices = gtk_tree_path_get_indices (path);
if (filter->priv->root == NULL)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
level = FILTER_LEVEL (filter->priv->root);
depth = gtk_tree_path_get_depth (path);
@@ -2134,7 +2261,9 @@ gtk_tree_model_filter_get_iter_full (GtkTreeModel *model,
elt = gtk_tree_model_filter_get_nth (filter, level, indices[i]);
if (!elt->children)
- gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, elt),
+ FALSE);
level = elt->children;
}
@@ -2169,7 +2298,7 @@ gtk_tree_model_filter_get_iter (GtkTreeModel *model,
indices = gtk_tree_path_get_indices (path);
if (filter->priv->root == NULL)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
level = FILTER_LEVEL (filter->priv->root);
depth = gtk_tree_path_get_depth (path);
@@ -2189,7 +2318,9 @@ gtk_tree_model_filter_get_iter (GtkTreeModel *model,
elt = gtk_tree_model_filter_get_nth_visible (filter, level, indices[i]);
if (!elt->children)
- gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, elt),
+ FALSE);
level = elt->children;
}
@@ -2216,6 +2347,7 @@ gtk_tree_model_filter_get_path (GtkTreeModel *model,
GtkTreePath *retval;
FilterLevel *level;
FilterElt *elt;
+ gint elt_index;
g_return_val_if_fail (GTK_IS_TREE_MODEL_FILTER (model), NULL);
g_return_val_if_fail (GTK_TREE_MODEL_FILTER (model)->priv->child_model != NULL, NULL);
@@ -2223,6 +2355,7 @@ gtk_tree_model_filter_get_path (GtkTreeModel *model,
level = iter->user_data;
elt = iter->user_data2;
+ elt_index = FILTER_LEVEL_ELT_INDEX (level, elt);
if (!elt->visible)
return NULL;
@@ -2233,7 +2366,7 @@ gtk_tree_model_filter_get_path (GtkTreeModel *model,
{
int i = 0, index = 0;
- while (&g_array_index (level->array, FilterElt, i) != elt)
+ while (i < elt_index)
{
if (g_array_index (level->array, FilterElt, i).visible)
index++;
@@ -2243,7 +2376,7 @@ gtk_tree_model_filter_get_path (GtkTreeModel *model,
}
gtk_tree_path_prepend_index (retval, index);
- elt = level->parent_elt;
+ elt_index = level->parent_elt_index;
level = level->parent_level;
}
@@ -2336,7 +2469,7 @@ gtk_tree_model_filter_iter_children (GtkTreeModel *model,
int i = 0;
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
if (!filter->priv->root)
return FALSE;
@@ -2366,20 +2499,24 @@ gtk_tree_model_filter_iter_children (GtkTreeModel *model,
else
{
int i = 0;
+ FilterElt *elt;
+
+ elt = FILTER_ELT (parent->user_data2);
- if (FILTER_ELT (parent->user_data2)->children == NULL)
+ if (elt->children == NULL)
gtk_tree_model_filter_build_level (filter,
FILTER_LEVEL (parent->user_data),
- FILTER_ELT (parent->user_data2),
+ FILTER_LEVEL_ELT_INDEX (parent->user_data, elt),
FALSE);
- if (FILTER_ELT (parent->user_data2)->children == NULL)
+
+ if (elt->children == NULL)
return FALSE;
- if (FILTER_ELT (parent->user_data2)->children->visible_nodes <= 0)
+ if (elt->children->visible_nodes <= 0)
return FALSE;
iter->stamp = filter->priv->stamp;
- iter->user_data = FILTER_ELT (parent->user_data2)->children;
+ iter->user_data = elt->children;
level = FILTER_LEVEL (iter->user_data);
@@ -2429,7 +2566,8 @@ gtk_tree_model_filter_iter_has_child (GtkTreeModel *model,
if (!elt->children
&& gtk_tree_model_iter_has_child (filter->priv->child_model, &child_iter))
gtk_tree_model_filter_build_level (filter, FILTER_LEVEL (iter->user_data),
- elt, FALSE);
+ FILTER_LEVEL_ELT_INDEX (iter->user_data, elt),
+ FALSE);
if (elt->children && elt->children->visible_nodes > 0)
return TRUE;
@@ -2453,7 +2591,7 @@ gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
if (!iter)
{
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
if (filter->priv->root)
return FILTER_LEVEL (filter->priv->root)->visible_nodes;
@@ -2472,7 +2610,8 @@ gtk_tree_model_filter_iter_n_children (GtkTreeModel *model,
gtk_tree_model_iter_has_child (filter->priv->child_model, &child_iter))
gtk_tree_model_filter_build_level (filter,
FILTER_LEVEL (iter->user_data),
- elt, FALSE);
+ FILTER_LEVEL_ELT_INDEX (iter->user_data, elt),
+ FALSE);
if (elt->children)
return elt->children->visible_nodes;
@@ -2538,7 +2677,7 @@ gtk_tree_model_filter_iter_parent (GtkTreeModel *model,
{
iter->stamp = GTK_TREE_MODEL_FILTER (model)->priv->stamp;
iter->user_data = level->parent_level;
- iter->user_data2 = level->parent_elt;
+ iter->user_data2 = FILTER_LEVEL_PARENT_ELT (level);
return TRUE;
}
@@ -2571,14 +2710,14 @@ gtk_tree_model_filter_ref_node (GtkTreeModel *model,
if (level->ref_count == 1)
{
FilterLevel *parent_level = level->parent_level;
- FilterElt *parent_elt = level->parent_elt;
+ gint parent_elt_index = level->parent_elt_index;
/* we were at zero -- time to decrease the zero_ref_count val */
while (parent_level)
{
- parent_elt->zero_ref_count--;
+ g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count--;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -2624,14 +2763,14 @@ gtk_tree_model_filter_real_unref_node (GtkTreeModel *model,
if (level->ref_count == 0)
{
FilterLevel *parent_level = level->parent_level;
- FilterElt *parent_elt = level->parent_elt;
+ gint parent_elt_index = level->parent_elt_index;
/* we are at zero -- time to increase the zero_ref_count val */
while (parent_level)
{
- parent_elt->zero_ref_count++;
+ g_array_index (parent_level->array, FilterElt, parent_elt_index).zero_ref_count++;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -3037,6 +3176,7 @@ gtk_tree_model_filter_convert_child_iter_to_iter (GtkTreeModelFilter *filter,
g_return_val_if_fail (filter->priv->child_model != NULL, FALSE);
g_return_val_if_fail (filter_iter != NULL, FALSE);
g_return_val_if_fail (child_iter != NULL, FALSE);
+ g_return_val_if_fail (filter_iter != child_iter, FALSE);
filter_iter->stamp = 0;
@@ -3076,6 +3216,7 @@ gtk_tree_model_filter_convert_iter_to_child_iter (GtkTreeModelFilter *filter,
g_return_if_fail (child_iter != NULL);
g_return_if_fail (filter_iter != NULL);
g_return_if_fail (filter_iter->stamp == filter->priv->stamp);
+ g_return_if_fail (filter_iter != child_iter);
if (GTK_TREE_MODEL_FILTER_CACHE_CHILD_ITERS (filter))
{
@@ -3124,7 +3265,7 @@ gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filte
child_indices = gtk_tree_path_get_indices (real_path);
if (filter->priv->root == NULL && build_levels)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
level = FILTER_LEVEL (filter->priv->root);
for (i = 0; i < gtk_tree_path_get_depth (real_path); i++)
@@ -3144,7 +3285,9 @@ gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filte
{
gtk_tree_path_append_index (retval, j);
if (!tmp->children && build_levels)
- gtk_tree_model_filter_build_level (filter, level, tmp, FALSE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, tmp),
+ FALSE);
level = tmp->children;
found_child = TRUE;
}
@@ -3166,7 +3309,9 @@ gtk_real_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filte
gtk_tree_path_append_index (retval, j);
if (!tmp->children && build_levels)
- gtk_tree_model_filter_build_level (filter, level, tmp, FALSE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, tmp),
+ FALSE);
level = tmp->children;
found_child = TRUE;
}
@@ -3258,7 +3403,7 @@ gtk_tree_model_filter_convert_path_to_child_path (GtkTreeModelFilter *filter,
retval = gtk_tree_path_new ();
filter_indices = gtk_tree_path_get_indices (filter_path);
if (!filter->priv->root)
- gtk_tree_model_filter_build_level (filter, NULL, NULL, FALSE);
+ gtk_tree_model_filter_build_level (filter, NULL, -1, FALSE);
level = FILTER_LEVEL (filter->priv->root);
for (i = 0; i < gtk_tree_path_get_depth (filter_path); i++)
@@ -3275,7 +3420,9 @@ gtk_tree_model_filter_convert_path_to_child_path (GtkTreeModelFilter *filter,
filter_indices[i]);
if (elt->children == NULL)
- gtk_tree_model_filter_build_level (filter, level, elt, FALSE);
+ gtk_tree_model_filter_build_level (filter, level,
+ FILTER_LEVEL_ELT_INDEX (level, elt),
+ FALSE);
if (!level || level->visible_nodes <= filter_indices[i])
{
diff --git a/gtk/gtktreemodelsort.c b/gtk/gtktreemodelsort.c
index 1dbdda41f8..f07795cc23 100644
--- a/gtk/gtktreemodelsort.c
+++ b/gtk/gtktreemodelsort.c
@@ -67,7 +67,7 @@ struct _SortLevel
{
GArray *array;
gint ref_count;
- SortElt *parent_elt;
+ gint parent_elt_index;
SortLevel *parent_level;
};
@@ -101,6 +101,10 @@ enum {
#define SORT_ELT(sort_elt) ((SortElt *)sort_elt)
#define SORT_LEVEL(sort_level) ((SortLevel *)sort_level)
+#define SORT_LEVEL_PARENT_ELT(level) (&g_array_index (SORT_LEVEL ((level))->parent_level->array, SortElt, SORT_LEVEL ((level))->parent_elt_index))
+#define SORT_LEVEL_ELT_INDEX(level, elt) (SORT_ELT ((elt)) - SORT_ELT (SORT_LEVEL ((level))->array->data))
+
+
#define GET_CHILD_ITER(tree_model_sort,ch_iter,so_iter) gtk_tree_model_sort_convert_iter_to_child_iter((GtkTreeModelSort*)(tree_model_sort), (ch_iter), (so_iter));
#define NO_SORT_FUNC ((GtkTreeIterCompareFunc) 0x1)
@@ -211,7 +215,7 @@ static gboolean gtk_tree_model_sort_has_default_sort_func (GtkTreeSortable
/* Private functions (sort funcs, level handling and other utils) */
static void gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
SortLevel *parent_level,
- SortElt *parent_elt);
+ gint parent_elt_index);
static void gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort,
SortLevel *sort_level);
static void gtk_tree_model_sort_increment_stamp (GtkTreeModelSort *tree_model_sort);
@@ -499,7 +503,7 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
for (i = 0; i < level->array->len; i++)
if (g_array_index (level->array, SortElt, i).children)
- g_array_index (level->array, SortElt, i).children->parent_elt = &g_array_index (level->array, SortElt, i);
+ g_array_index (level->array, SortElt, i).children->parent_elt_index = i;
gtk_tree_path_up (path);
gtk_tree_path_append_index (path, index);
@@ -539,11 +543,11 @@ gtk_tree_model_sort_row_changed (GtkTreeModel *s_model,
/* else? shouldn't really happen */
}
- if (level->parent_elt)
+ if (level->parent_elt_index >= 0)
{
iter.stamp = tree_model_sort->stamp;
iter.user_data = level->parent_level;
- iter.user_data2 = level->parent_elt;
+ iter.user_data2 = SORT_LEVEL_PARENT_ELT (level);
tmppath = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model_sort), &iter);
@@ -609,7 +613,7 @@ gtk_tree_model_sort_row_inserted (GtkTreeModel *s_model,
if (!tree_model_sort->root)
{
- gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL);
+ gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1);
/* the build level already put the inserted iter in the level,
so no need to handle this signal anymore */
@@ -785,7 +789,7 @@ gtk_tree_model_sort_row_deleted (GtkTreeModel *s_model,
if (elt->offset > offset)
elt->offset--;
if (elt->children)
- elt->children->parent_elt = elt;
+ elt->children->parent_elt_index = i;
}
gtk_tree_path_free (path);
@@ -934,7 +938,7 @@ gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model,
indices = gtk_tree_path_get_indices (path);
if (tree_model_sort->root == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL);
+ gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1);
level = SORT_LEVEL (tree_model_sort->root);
depth = gtk_tree_path_get_depth (path);
@@ -948,7 +952,7 @@ gtk_tree_model_sort_get_iter (GtkTreeModel *tree_model,
return FALSE;
if (g_array_index (level->array, SortElt, indices[i]).children == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, indices[i]));
+ gtk_tree_model_sort_build_level (tree_model_sort, level, indices[i]);
level = g_array_index (level->array, SortElt, indices[i]).children;
}
@@ -972,19 +976,21 @@ gtk_tree_model_sort_get_path (GtkTreeModel *tree_model,
GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model;
GtkTreePath *retval;
SortLevel *level;
- SortElt *elt;
+ gint elt_index;
g_return_val_if_fail (tree_model_sort->child_model != NULL, NULL);
g_return_val_if_fail (tree_model_sort->stamp == iter->stamp, NULL);
retval = gtk_tree_path_new ();
- level = iter->user_data;
- elt = iter->user_data2;
- while (level != NULL)
+
+ level = SORT_LEVEL (iter->user_data);
+ elt_index = SORT_LEVEL_ELT_INDEX (level, iter->user_data2);
+
+ while (level)
{
- gtk_tree_path_prepend_index (retval, elt - (SortElt *)level->array->data);
+ gtk_tree_path_prepend_index (retval, elt_index);
- elt = level->parent_elt;
+ elt_index = level->parent_elt_index;
level = level->parent_level;
}
@@ -1048,7 +1054,7 @@ gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model,
if (parent == NULL)
{
if (tree_model_sort->root == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL);
+ gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1);
if (tree_model_sort->root == NULL)
return FALSE;
@@ -1059,15 +1065,21 @@ gtk_tree_model_sort_iter_children (GtkTreeModel *tree_model,
}
else
{
- if (((SortElt *)parent->user_data2)->children == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort,
- (SortLevel *)parent->user_data,
- (SortElt *)parent->user_data2);
- if (((SortElt *)parent->user_data2)->children == NULL)
+ SortElt *elt;
+
+ level = SORT_LEVEL (parent->user_data);
+ elt = SORT_ELT (parent->user_data2);
+
+ if (elt->children == NULL)
+ gtk_tree_model_sort_build_level (tree_model_sort, level,
+ SORT_LEVEL_ELT_INDEX (level, elt));
+
+ if (elt->children == NULL)
return FALSE;
+
iter->stamp = tree_model_sort->stamp;
- iter->user_data = ((SortElt *)parent->user_data2)->children;
- iter->user_data2 = ((SortLevel *)iter->user_data)->array->data;
+ iter->user_data = elt->children;
+ iter->user_data2 = elt->children->array->data;
}
return TRUE;
@@ -1160,7 +1172,7 @@ gtk_tree_model_sort_iter_parent (GtkTreeModel *tree_model,
{
iter->stamp = tree_model_sort->stamp;
iter->user_data = level->parent_level;
- iter->user_data2 = level->parent_elt;
+ iter->user_data2 = SORT_LEVEL_PARENT_ELT (level);
return TRUE;
}
@@ -1173,9 +1185,9 @@ gtk_tree_model_sort_ref_node (GtkTreeModel *tree_model,
{
GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model;
GtkTreeIter child_iter;
- GtkTreeIter tmp_iter;
- SortLevel *level;
+ SortLevel *level, *parent_level;
SortElt *elt;
+ gint parent_elt_index;
g_return_if_fail (tree_model_sort->child_model != NULL);
g_return_if_fail (VALID_ITER (iter, tree_model_sort));
@@ -1193,28 +1205,34 @@ gtk_tree_model_sort_ref_node (GtkTreeModel *tree_model,
level->ref_count++;
/* Increase the reference count of all parent elements */
- tmp_iter.stamp = tree_model_sort->stamp;
- tmp_iter.user_data = level->parent_level;
- tmp_iter.user_data2 = level->parent_elt;;
+ parent_level = level->parent_level;
+ parent_elt_index = level->parent_elt_index;
- while (tmp_iter.user_data2)
+ while (parent_level)
{
+ GtkTreeIter tmp_iter;
+
+ tmp_iter.stamp = tree_model_sort->stamp;
+ tmp_iter.user_data = parent_level;
+ tmp_iter.user_data2 = &g_array_index (parent_level->array, SortElt, parent_elt_index);
+
gtk_tree_model_sort_ref_node (tree_model, &tmp_iter);
- tmp_iter.user_data2 = SORT_LEVEL (tmp_iter.user_data)->parent_elt;
- tmp_iter.user_data = SORT_LEVEL (tmp_iter.user_data)->parent_level;
+ parent_elt_index = parent_level->parent_elt_index;
+ parent_level = parent_level->parent_level;
}
if (level->ref_count == 1)
{
SortLevel *parent_level = level->parent_level;
- SortElt *parent_elt = level->parent_elt;
+ gint parent_elt_index = level->parent_elt_index;
+
/* We were at zero -- time to decrement the zero_ref_count val */
while (parent_level)
- {
- parent_elt->zero_ref_count--;
+ {
+ g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count--;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -1229,9 +1247,9 @@ gtk_tree_model_sort_real_unref_node (GtkTreeModel *tree_model,
gboolean propagate_unref)
{
GtkTreeModelSort *tree_model_sort = (GtkTreeModelSort *) tree_model;
- GtkTreeIter tmp_iter;
- SortLevel *level;
+ SortLevel *level, *parent_level;
SortElt *elt;
+ gint parent_elt_index;
g_return_if_fail (tree_model_sort->child_model != NULL);
g_return_if_fail (VALID_ITER (iter, tree_model_sort));
@@ -1253,29 +1271,34 @@ gtk_tree_model_sort_real_unref_node (GtkTreeModel *tree_model,
level->ref_count--;
/* Decrease the reference count of all parent elements */
- tmp_iter.stamp = tree_model_sort->stamp;
- tmp_iter.user_data = level->parent_level;
- tmp_iter.user_data2 = level->parent_elt;;
+ parent_level = level->parent_level;
+ parent_elt_index = level->parent_elt_index;
- while (tmp_iter.user_data2)
+ while (parent_level)
{
+ GtkTreeIter tmp_iter;
+
+ tmp_iter.stamp = tree_model_sort->stamp;
+ tmp_iter.user_data = parent_level;
+ tmp_iter.user_data2 = &g_array_index (parent_level->array, SortElt, parent_elt_index);
+
gtk_tree_model_sort_real_unref_node (tree_model, &tmp_iter, FALSE);
- tmp_iter.user_data2 = SORT_LEVEL (tmp_iter.user_data)->parent_elt;
- tmp_iter.user_data = SORT_LEVEL (tmp_iter.user_data)->parent_level;
+ parent_elt_index = parent_level->parent_elt_index;
+ parent_level = parent_level->parent_level;
}
if (level->ref_count == 0)
{
SortLevel *parent_level = level->parent_level;
- SortElt *parent_elt = level->parent_elt;
+ gint parent_elt_index = level->parent_elt_index;
/* We are at zero -- time to increment the zero_ref_count val */
while (parent_level)
{
- parent_elt->zero_ref_count++;
+ g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count++;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -1558,10 +1581,10 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort,
/* Set up data */
data.tree_model_sort = tree_model_sort;
- if (level->parent_elt)
+ if (level->parent_elt_index >= 0)
{
data.parent_path = gtk_tree_model_sort_elt_get_path (level->parent_level,
- level->parent_elt);
+ SORT_LEVEL_PARENT_ELT (level));
gtk_tree_path_append_index (data.parent_path, 0);
}
else
@@ -1627,9 +1650,8 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort,
new_order[i] = g_array_index (sort_array, SortTuple, i).offset;
g_array_append_val (new_array, *elt);
- elt = &g_array_index (new_array, SortElt, i);
if (elt->children)
- elt->children->parent_elt = elt;
+ elt->children->parent_elt_index = i;
}
g_array_free (level->array, TRUE);
@@ -1639,11 +1661,11 @@ gtk_tree_model_sort_sort_level (GtkTreeModelSort *tree_model_sort,
if (emit_reordered)
{
gtk_tree_model_sort_increment_stamp (tree_model_sort);
- if (level->parent_elt)
+ if (level->parent_elt_index >= 0)
{
iter.stamp = tree_model_sort->stamp;
iter.user_data = level->parent_level;
- iter.user_data2 = level->parent_elt;
+ iter.user_data2 = SORT_LEVEL_PARENT_ELT (level);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (tree_model_sort),
&iter);
@@ -1846,7 +1868,7 @@ gtk_tree_model_sort_insert_value (GtkTreeModelSort *tree_model_sort,
tmp_elt = SORT_ELT (level->array->data);
for (i = 0; i < level->array->len; i++, tmp_elt++)
if (tmp_elt->children)
- tmp_elt->children->parent_elt = tmp_elt;
+ tmp_elt->children->parent_elt_index = i;
return TRUE;
}
@@ -1869,7 +1891,10 @@ gtk_tree_model_sort_elt_get_path (SortLevel *level,
{
gtk_tree_path_prepend_index (path, walker2->offset);
- walker2 = walker->parent_elt;
+ if (!walker->parent_level)
+ break;
+
+ walker2 = SORT_LEVEL_PARENT_ELT (walker);
walker = walker->parent_level;
}
@@ -1992,7 +2017,7 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode
child_indices = gtk_tree_path_get_indices (child_path);
if (tree_model_sort->root == NULL && build_levels)
- gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL);
+ gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1);
level = SORT_LEVEL (tree_model_sort->root);
for (i = 0; i < gtk_tree_path_get_depth (child_path); i++)
@@ -2018,7 +2043,7 @@ gtk_real_tree_model_sort_convert_child_path_to_path (GtkTreeModelSort *tree_mode
gtk_tree_path_append_index (retval, j);
if (g_array_index (level->array, SortElt, j).children == NULL && build_levels)
{
- gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, j));
+ gtk_tree_model_sort_build_level (tree_model_sort, level, j);
}
level = g_array_index (level->array, SortElt, j).children;
found_child = TRUE;
@@ -2084,6 +2109,7 @@ gtk_tree_model_sort_convert_child_iter_to_iter (GtkTreeModelSort *tree_model_sor
g_return_val_if_fail (tree_model_sort->child_model != NULL, FALSE);
g_return_val_if_fail (sort_iter != NULL, FALSE);
g_return_val_if_fail (child_iter != NULL, FALSE);
+ g_return_val_if_fail (sort_iter != child_iter, FALSE);
sort_iter->stamp = 0;
@@ -2135,7 +2161,7 @@ gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sor
retval = gtk_tree_path_new ();
sorted_indices = gtk_tree_path_get_indices (sorted_path);
if (tree_model_sort->root == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort, NULL, NULL);
+ gtk_tree_model_sort_build_level (tree_model_sort, NULL, -1);
level = SORT_LEVEL (tree_model_sort->root);
for (i = 0; i < gtk_tree_path_get_depth (sorted_path); i++)
@@ -2150,7 +2176,7 @@ gtk_tree_model_sort_convert_path_to_child_path (GtkTreeModelSort *tree_model_sor
}
if (g_array_index (level->array, SortElt, count).children == NULL)
- gtk_tree_model_sort_build_level (tree_model_sort, level, &g_array_index (level->array, SortElt, count));
+ gtk_tree_model_sort_build_level (tree_model_sort, level, count);
if (level == NULL)
{
@@ -2182,6 +2208,7 @@ gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sor
g_return_if_fail (tree_model_sort->child_model != NULL);
g_return_if_fail (child_iter != NULL);
g_return_if_fail (VALID_ITER (sorted_iter, tree_model_sort));
+ g_return_if_fail (sorted_iter != child_iter);
if (GTK_TREE_MODEL_SORT_CACHE_CHILD_ITERS (tree_model_sort))
{
@@ -2201,9 +2228,10 @@ gtk_tree_model_sort_convert_iter_to_child_iter (GtkTreeModelSort *tree_model_sor
static void
gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
SortLevel *parent_level,
- SortElt *parent_elt)
+ gint parent_elt_index)
{
GtkTreeIter iter;
+ SortElt *parent_elt = NULL;
SortLevel *new_level;
gint length = 0;
gint i;
@@ -2221,6 +2249,8 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
GtkTreeIter parent_iter;
GtkTreeIter child_parent_iter;
+ parent_elt = &g_array_index (parent_level->array, SortElt, parent_elt_index);
+
parent_iter.stamp = tree_model_sort->stamp;
parent_iter.user_data = parent_level;
parent_iter.user_data2 = parent_elt;
@@ -2246,10 +2276,10 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
new_level = g_new (SortLevel, 1);
new_level->array = g_array_sized_new (FALSE, FALSE, sizeof (SortElt), length);
new_level->ref_count = 0;
- new_level->parent_elt = parent_elt;
new_level->parent_level = parent_level;
+ new_level->parent_elt_index = parent_elt_index;
- if (parent_elt)
+ if (parent_elt_index >= 0)
parent_elt->children = new_level;
else
tree_model_sort->root = new_level;
@@ -2257,11 +2287,12 @@ gtk_tree_model_sort_build_level (GtkTreeModelSort *tree_model_sort,
/* increase the count of zero ref_counts.*/
while (parent_level)
{
- parent_elt->zero_ref_count++;
+ g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count++;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
+
if (new_level != tree_model_sort->root)
tree_model_sort->zero_ref_count++;
@@ -2332,13 +2363,13 @@ gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort,
if (sort_level->ref_count == 0)
{
SortLevel *parent_level = sort_level->parent_level;
- SortElt *parent_elt = sort_level->parent_elt;
+ gint parent_elt_index = sort_level->parent_elt_index;
while (parent_level)
- {
- parent_elt->zero_ref_count--;
+ {
+ g_array_index (parent_level->array, SortElt, parent_elt_index).zero_ref_count--;
- parent_elt = parent_level->parent_elt;
+ parent_elt_index = parent_level->parent_elt_index;
parent_level = parent_level->parent_level;
}
@@ -2346,8 +2377,8 @@ gtk_tree_model_sort_free_level (GtkTreeModelSort *tree_model_sort,
tree_model_sort->zero_ref_count--;
}
- if (sort_level->parent_elt)
- sort_level->parent_elt->children = NULL;
+ if (sort_level->parent_elt_index >= 0)
+ SORT_LEVEL_PARENT_ELT (sort_level)->children = NULL;
else
tree_model_sort->root = NULL;
diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
index 44259abe35..8b672f26cc 100644
--- a/gtk/gtktreeprivate.h
+++ b/gtk/gtktreeprivate.h
@@ -285,14 +285,13 @@ struct _GtkTreeViewPrivate
{ \
g_log (G_LOG_DOMAIN, \
G_LOG_LEVEL_CRITICAL, \
- "file %s: line %d (%s): assertion `%s' failed.\n" \
+ "%s (%s): assertion `%s' failed.\n" \
"There is a disparity between the internal view of the GtkTreeView,\n" \
"and the GtkTreeModel. This generally means that the model has changed\n"\
"without letting the view know. Any display from now on is likely to\n" \
"be incorrect.\n", \
- __FILE__, \
- __LINE__, \
- __PRETTY_FUNCTION__, \
+ G_STRLOC, \
+ G_STRFUNC, \
#expr); \
return ret; \
}; }G_STMT_END
@@ -302,14 +301,13 @@ struct _GtkTreeViewPrivate
{ \
g_log (G_LOG_DOMAIN, \
G_LOG_LEVEL_CRITICAL, \
- "file %s: line %d (%s): assertion `%s' failed.\n" \
+ "%s (%s): assertion `%s' failed.\n" \
"There is a disparity between the internal view of the GtkTreeView,\n" \
"and the GtkTreeModel. This generally means that the model has changed\n"\
"without letting the view know. Any display from now on is likely to\n" \
"be incorrect.\n", \
- __FILE__, \
- __LINE__, \
- __PRETTY_FUNCTION__, \
+ G_STRLOC, \
+ G_STRFUNC, \
#expr); \
return; \
}; }G_STMT_END
diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c
index 1fb178d375..30ff14f810 100644
--- a/gtk/gtktreestore.c
+++ b/gtk/gtktreestore.c
@@ -358,30 +358,20 @@ static void
gtk_tree_store_set_n_columns (GtkTreeStore *tree_store,
gint n_columns)
{
- GType *new_columns;
+ int i;
if (tree_store->n_columns == n_columns)
return;
- new_columns = g_new0 (GType, n_columns);
- if (tree_store->column_headers)
- {
- /* copy the old header orders over */
- if (n_columns >= tree_store->n_columns)
- memcpy (new_columns, tree_store->column_headers, tree_store->n_columns * sizeof (gchar *));
- else
- memcpy (new_columns, tree_store->column_headers, n_columns * sizeof (GType));
-
- g_free (tree_store->column_headers);
- }
+ tree_store->column_headers = g_renew (GType, tree_store->column_headers, n_columns);
+ for (i = tree_store->n_columns; i < n_columns; i++)
+ tree_store->column_headers[i] = G_TYPE_INVALID;
+ tree_store->n_columns = n_columns;
if (tree_store->sort_list)
_gtk_tree_data_list_header_free (tree_store->sort_list);
tree_store->sort_list = _gtk_tree_data_list_header_new (n_columns, tree_store->column_headers);
-
- tree_store->column_headers = new_columns;
- tree_store->n_columns = n_columns;
}
/**
@@ -620,7 +610,10 @@ gtk_tree_store_iter_next (GtkTreeModel *tree_model,
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
@@ -646,7 +639,10 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model,
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
@@ -708,7 +704,10 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
static gboolean
@@ -733,7 +732,10 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
return TRUE;
}
else
- return FALSE;
+ {
+ iter->stamp = 0;
+ return FALSE;
+ }
}
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index b4d4708761..3aad46cd44 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -48,7 +48,7 @@
#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
#define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
-#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
+#define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
#define SCROLL_EDGE_SIZE 15
#define EXPANDER_EXTRA_PADDING 4
#define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
@@ -345,15 +345,6 @@ static void gtk_tree_view_build_tree (GtkTreeView
GtkTreeIter *iter,
gint depth,
gboolean recurse);
-static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
- GtkTreeIter *iter,
- gint depth,
- gint *height,
- GtkRBNode *node);
-static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth);
static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node);
@@ -2043,9 +2034,8 @@ gtk_tree_view_size_request (GtkWidget *widget,
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
GList *tmp_list;
- /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
- * sure we have some size. In practice, with a lot of static lists, this
- * should get a good width.
+ /* we validate some rows initially just to make sure we have some size.
+ * In practice, with a lot of static lists, this should get a good width.
*/
do_validate_rows (tree_view, FALSE);
gtk_tree_view_size_request_columns (tree_view);
@@ -4582,78 +4572,6 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
background_area.y + max_height);
}
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- tree_view->priv->tree_lines_enabled)
- {
- gint x = background_area.x;
- gint mult = rtl ? -1 : 1;
- gint y0 = background_area.y;
- gint y1 = background_area.y + background_area.height/2;
- gint y2 = background_area.y + background_area.height;
-
- if (rtl)
- x += background_area.width - 1;
-
- if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
- && depth > 1)
- {
- gdk_draw_line (event->window,
- tree_view->priv->tree_line_gc,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y1,
- x + tree_view->priv->expander_size * (depth - 1.1) * mult,
- y1);
- }
- else if (depth > 1)
- {
- gdk_draw_line (event->window,
- tree_view->priv->tree_line_gc,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y1,
- x + tree_view->priv->expander_size * (depth - 0.5) * mult,
- y1);
- }
-
- if (depth > 1)
- {
- gint i;
- GtkRBNode *tmp_node;
- GtkRBTree *tmp_tree;
-
- if (!_gtk_rbtree_next (tree, node))
- gdk_draw_line (event->window,
- tree_view->priv->tree_line_gc,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y0,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y1);
- else
- gdk_draw_line (event->window,
- tree_view->priv->tree_line_gc,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y0,
- x + tree_view->priv->expander_size * (depth - 1.5) * mult,
- y2);
-
- tmp_node = tree->parent_node;
- tmp_tree = tree->parent_tree;
-
- for (i = depth - 2; i > 0; i--)
- {
- if (_gtk_rbtree_next (tmp_tree, tmp_node))
- gdk_draw_line (event->window,
- tree_view->priv->tree_line_gc,
- x + tree_view->priv->expander_size * (i - 0.5) * mult,
- y0,
- x + tree_view->priv->expander_size * (i - 0.5) * mult,
- y2);
-
- tmp_node = tmp_tree->parent_node;
- tmp_tree = tmp_tree->parent_tree;
- }
- }
- }
-
if (gtk_tree_view_is_expander_column (tree_view, column))
{
if (!rtl)
@@ -4727,6 +4645,79 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
&event->area,
flags);
}
+
+ if (gtk_tree_view_is_expander_column (tree_view, column) &&
+ tree_view->priv->tree_lines_enabled)
+ {
+ gint x = background_area.x;
+ gint mult = rtl ? -1 : 1;
+ gint y0 = background_area.y;
+ gint y1 = background_area.y + background_area.height/2;
+ gint y2 = background_area.y + background_area.height;
+
+ if (rtl)
+ x += background_area.width - 1;
+
+ if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
+ && depth > 1)
+ {
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y1,
+ x + tree_view->priv->expander_size * (depth - 1.1) * mult,
+ y1);
+ }
+ else if (depth > 1)
+ {
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y1,
+ x + tree_view->priv->expander_size * (depth - 0.5) * mult,
+ y1);
+ }
+
+ if (depth > 1)
+ {
+ gint i;
+ GtkRBNode *tmp_node;
+ GtkRBTree *tmp_tree;
+
+ if (!_gtk_rbtree_next (tree, node))
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y0,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y1);
+ else
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y0,
+ x + tree_view->priv->expander_size * (depth - 1.5) * mult,
+ y2);
+
+ tmp_node = tree->parent_node;
+ tmp_tree = tree->parent_tree;
+
+ for (i = depth - 2; i > 0; i--)
+ {
+ if (_gtk_rbtree_next (tmp_tree, tmp_node))
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ x + tree_view->priv->expander_size * (i - 0.5) * mult,
+ y0,
+ x + tree_view->priv->expander_size * (i - 0.5) * mult,
+ y2);
+
+ tmp_node = tmp_tree->parent_node;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+ }
+ }
+
if (node == cursor && has_special_cell &&
((column == tree_view->priv->focus_column &&
GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
@@ -4740,6 +4731,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
&event->area,
flags);
}
+
cell_offset += column->width;
}
@@ -5483,6 +5475,12 @@ gtk_tree_view_enter_notify (GtkWidget *widget,
if (tree_view->priv->tree == NULL)
return FALSE;
+ if (event->mode == GDK_CROSSING_GRAB ||
+ event->mode == GDK_CROSSING_GTK_GRAB ||
+ event->mode == GDK_CROSSING_GTK_UNGRAB ||
+ event->mode == GDK_CROSSING_STATE_CHANGED)
+ return TRUE;
+
/* find the node internally */
new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
if (new_y < 0)
@@ -5992,16 +5990,24 @@ validate_visible_area (GtkTreeView *tree_view)
while (area_above > 0)
{
_gtk_rbtree_prev_full (tree, node, &tree, &node);
- if (! gtk_tree_path_prev (above_path) && node != NULL)
- {
- gtk_tree_path_free (above_path);
- above_path = _gtk_tree_view_find_path (tree_view, tree, node);
- }
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
+
+ /* Always find the new path in the tree. We cannot just assume
+ * a gtk_tree_path_prev() is enough here, as there might be children
+ * in between this node and the previous sibling node. If this
+ * appears to be a performance hotspot in profiles, we can look into
+ * intrigate logic for keeping path, node and iter in sync like
+ * we do for forward walks. (Which will be hard because of the lacking
+ * iter_prev).
+ */
if (node == NULL)
break;
+ gtk_tree_path_free (above_path);
+ above_path = _gtk_tree_view_find_path (tree_view, tree, node);
+
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
+
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
@@ -6118,6 +6124,7 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
gint retval = TRUE;
GtkTreePath *path = NULL;
GtkTreeIter iter;
+ GTimer *timer;
gint i = 0;
gint prev_height = -1;
@@ -6136,6 +6143,9 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
return FALSE;
}
+ timer = g_timer_new ();
+ g_timer_start (timer);
+
do
{
if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
@@ -6213,7 +6223,7 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
i++;
}
- while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
+ while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
if (!tree_view->priv->fixed_height_check)
{
@@ -6238,10 +6248,11 @@ do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
gtk_adjustment_changed (tree_view->priv->vadjustment);
if (queue_resize)
- gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
if (path) gtk_tree_path_free (path);
+ g_timer_destroy (timer);
return retval;
}
@@ -6421,6 +6432,10 @@ gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
GtkRBNode *node;
int new_dy;
+ /* Avoid recursive calls */
+ if (tree_view->priv->in_top_row_to_dy)
+ return;
+
if (tree_view->priv->top_row)
path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
else
@@ -8757,133 +8772,6 @@ gtk_tree_view_build_tree (GtkTreeView *tree_view,
gtk_tree_path_free (path);
}
-/* If height is non-NULL, then we set it to be the new height. if it's all
- * dirty, then height is -1. We know we'll remeasure dirty rows, anyways.
- */
-static gboolean
-gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
- GtkTreeIter *iter,
- gint depth,
- gint *height,
- GtkRBNode *node)
-{
- GtkTreeViewColumn *column;
- GList *list;
- gboolean retval = FALSE;
- gint tmpheight;
- gint horizontal_separator;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view),
- "horizontal-separator", &horizontal_separator,
- NULL);
-
- if (height)
- *height = -1;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- gint width;
- column = list->data;
- if (column->dirty == TRUE)
- continue;
- if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
- continue;
- if (!column->visible)
- continue;
-
- gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
- GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
- node->children?TRUE:FALSE);
-
- if (height)
- {
- gtk_tree_view_column_cell_get_size (column,
- NULL, NULL, NULL,
- &width, &tmpheight);
- *height = MAX (*height, tmpheight);
- }
- else
- {
- gtk_tree_view_column_cell_get_size (column,
- NULL, NULL, NULL,
- &width, NULL);
- }
-
- if (gtk_tree_view_is_expander_column (tree_view, column))
- {
- int tmp = 0;
-
- tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
- if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
- tmp += depth * tree_view->priv->expander_size;
-
- if (tmp > column->requested_width)
- {
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
- retval = TRUE;
- }
- }
- else
- {
- if (horizontal_separator + width > column->requested_width)
- {
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
- retval = TRUE;
- }
- }
- }
-
- return retval;
-}
-
-static void
-gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth)
-{
- GtkRBNode *temp = tree->root;
- GtkTreeViewColumn *column;
- GList *list;
- GtkTreeIter child;
- gboolean is_all_dirty;
-
- TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
-
- while (temp->left != tree->nil)
- temp = temp->left;
-
- do
- {
- TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
- is_all_dirty = TRUE;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- if (column->dirty == FALSE)
- {
- is_all_dirty = FALSE;
- break;
- }
- }
-
- if (is_all_dirty)
- return;
-
- gtk_tree_view_discover_dirty_iter (tree_view,
- iter,
- depth,
- NULL,
- temp);
- if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
- temp->children != NULL)
- gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
- temp = _gtk_rbtree_next (tree, temp);
- }
- while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
-}
-
-
/* Make sure the node is visible vertically */
static void
gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
@@ -9863,6 +9751,8 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
gtk_widget_error_bell (GTK_WIDGET (tree_view));
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
cleanup:
gtk_tree_path_free (old_cursor_path);
gtk_tree_path_free (cursor_path);
@@ -9957,6 +9847,7 @@ gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
cursor_node,
NULL);
g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
else
{
@@ -10022,6 +9913,7 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
if (gtk_tree_path_compare (old_path, path))
{
gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
else
{
@@ -10643,6 +10535,9 @@ gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
if (!tree_view->priv->in_top_row_to_dy)
gtk_tree_view_dy_to_top_row (tree_view);
}
+
+ gdk_window_process_updates (tree_view->priv->header_window, TRUE);
+ gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
}
}
@@ -12552,14 +12447,24 @@ gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
gtk_tree_row_reference_free (tree_view->priv->cursor);
tree_view->priv->cursor = NULL;
- /* One cannot set the cursor on a separator. */
- if (!row_is_separator (tree_view, NULL, path))
+ /* One cannot set the cursor on a separator. Also, if
+ * _gtk_tree_view_find_node returns TRUE, it ran out of tree
+ * before finding the tree and node belonging to path. The
+ * path maps to a non-existing path and we will silently bail out.
+ * We unset tree and node to avoid further processing.
+ */
+ if (!row_is_separator (tree_view, NULL, path)
+ && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
{
tree_view->priv->cursor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
- tree_view->priv->model,
- path);
- _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+ gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+ tree_view->priv->model,
+ path);
+ }
+ else
+ {
+ tree = NULL;
+ node = NULL;
}
if (tree != NULL)
@@ -12649,6 +12554,9 @@ gtk_tree_view_get_cursor (GtkTreeView *tree_view,
* This function is often followed by @gtk_widget_grab_focus (@tree_view)
* in order to give keyboard focus to the widget. Please note that editing
* can only happen when the widget is realized.
+ *
+ * If @path is invalid for @model, the current cursor (if any) will be unset
+ * and the function will return without failing.
**/
void
gtk_tree_view_set_cursor (GtkTreeView *tree_view,
@@ -12680,6 +12588,9 @@ gtk_tree_view_set_cursor (GtkTreeView *tree_view,
* widget. Please note that editing can only happen when the widget is
* realized.
*
+ * If @path is invalid for @model, the current cursor (if any) will be unset
+ * and the function will return without failing.
+ *
* Since: 2.2
**/
void
@@ -12690,9 +12601,12 @@ gtk_tree_view_set_cursor_on_cell (GtkTreeView *tree_view,
gboolean start_editing)
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_return_if_fail (tree_view->priv->tree != NULL);
g_return_if_fail (path != NULL);
g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
+
+ if (!tree_view->priv->model)
+ return;
+
if (focus_cell)
{
g_return_if_fail (focus_column);
@@ -12765,7 +12679,8 @@ gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
* with the column at that point. @cell_x and @cell_y return the coordinates
* relative to the cell background (i.e. the @background_area passed to
* gtk_cell_renderer_render()). This function is only meaningful if
- * @tree_view is realized.
+ * @tree_view is realized. Therefore this function will always return %FALSE
+ * if @tree_view is not realized or does not have a model.
*
* For converting widget coordinates (eg. the ones you get from
* GtkWidget::query-tooltip), please see
@@ -12787,13 +12702,15 @@ gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
gint y_offset;
g_return_val_if_fail (tree_view != NULL, FALSE);
- g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
if (path)
*path = NULL;
if (column)
*column = NULL;
+ if (tree_view->priv->bin_window == NULL)
+ return FALSE;
+
if (tree_view->priv->tree == NULL)
return FALSE;
@@ -13616,9 +13533,12 @@ gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
* @pos: Return location for the drop position, or %NULL
*
* Determines the destination row for a given position. @drag_x and
- * @drag_y are expected to be in widget coordinates.
+ * @drag_y are expected to be in widget coordinates. This function is only
+ * meaningful if @tree_view is realized. Therefore this function will always
+ * return %FALSE if @tree_view is not realized or does not have a model.
*
- * Return value: whether there is a row at the given position.
+ * Return value: whether there is a row at the given position, %TRUE if this
+ * is indeed the case.
**/
gboolean
gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
@@ -13642,12 +13562,13 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
g_return_val_if_fail (tree_view != NULL, FALSE);
g_return_val_if_fail (drag_x >= 0, FALSE);
g_return_val_if_fail (drag_y >= 0, FALSE);
- g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
-
if (path)
*path = NULL;
+ if (tree_view->priv->bin_window == NULL)
+ return FALSE;
+
if (tree_view->priv->tree == NULL)
return FALSE;
@@ -14405,7 +14326,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
retval = TRUE;
}
- if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
+ if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
&& (event->keyval == GDK_g || event->keyval == GDK_G))
{
if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
@@ -14423,7 +14344,7 @@ gtk_tree_view_search_key_press_event (GtkWidget *widget,
retval = TRUE;
}
- if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
+ if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
&& (event->keyval == GDK_g || event->keyval == GDK_G))
{
if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
@@ -14587,8 +14508,8 @@ gtk_tree_view_search_iter (GtkTreeModel *model,
{
gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
TRUE, 0.5, 0.0);
- gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
gtk_tree_selection_select_iter (selection, iter);
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
if (path)
gtk_tree_path_free (path);
@@ -14674,7 +14595,6 @@ gtk_tree_view_search_init (GtkWidget *entry,
GtkTreeView *tree_view)
{
gint ret;
- gint len;
gint count = 0;
const gchar *text;
GtkTreeIter iter;
@@ -14685,7 +14605,7 @@ gtk_tree_view_search_init (GtkWidget *entry,
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
text = gtk_entry_get_text (GTK_ENTRY (entry));
- len = strlen (text);
+
model = gtk_tree_view_get_model (tree_view);
selection = gtk_tree_view_get_selection (tree_view);
@@ -14701,7 +14621,7 @@ gtk_tree_view_search_init (GtkWidget *entry,
tree_view);
}
- if (len < 1)
+ if (*text == '\0')
return;
if (!gtk_tree_model_get_iter_first (model, &iter))
@@ -15094,6 +15014,10 @@ gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view,
tree_view->priv->row_separator_func = func;
tree_view->priv->row_separator_data = data;
tree_view->priv->row_separator_destroy = destroy;
+
+ /* Have the tree recalculate heights */
+ _gtk_rbtree_mark_invalid (tree_view->priv->tree);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index d3259d0f64..edec5deffe 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -51,7 +51,8 @@ enum
PROP_ALIGNMENT,
PROP_REORDERABLE,
PROP_SORT_INDICATOR,
- PROP_SORT_ORDER
+ PROP_SORT_ORDER,
+ PROP_SORT_COLUMN_ID
};
enum
@@ -325,7 +326,24 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
GTK_TYPE_SORT_TYPE,
GTK_SORT_ASCENDING,
GTK_PARAM_READWRITE));
-
+
+ /**
+ * GtkTreeViewColumn:sort-column-id:
+ *
+ * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
+ * clickable. Set to %-1 to make the column unsortable.
+ *
+ * Since: 2.18
+ **/
+ g_object_class_install_property (object_class,
+ PROP_SORT_COLUMN_ID,
+ g_param_spec_int ("sort-column-id",
+ P_("Sort column ID"),
+ P_("Logical sort column ID this column sorts on when selected for sorting"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
}
static void
@@ -497,6 +515,11 @@ gtk_tree_view_column_set_property (GObject *object,
g_value_get_enum (value));
break;
+ case PROP_SORT_COLUMN_ID:
+ gtk_tree_view_column_set_sort_column_id (tree_column,
+ g_value_get_int (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -595,6 +618,11 @@ gtk_tree_view_column_get_property (GObject *object,
gtk_tree_view_column_get_sort_order (tree_column));
break;
+ case PROP_SORT_COLUMN_ID:
+ g_value_set_int (value,
+ gtk_tree_view_column_get_sort_column_id (tree_column));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2381,6 +2409,7 @@ gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
gtk_tree_view_column_set_clickable (tree_column, FALSE);
+ g_object_notify (G_OBJECT (tree_column), "sort-column-id");
return;
}
@@ -2393,6 +2422,7 @@ gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
NULL);
gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
+ g_object_notify (G_OBJECT (tree_column), "sort-column-id");
}
/**
diff --git a/gtk/gtktypeutils.c b/gtk/gtktypeutils.c
index 986f9ff188..6047d6f218 100644
--- a/gtk/gtktypeutils.c
+++ b/gtk/gtktypeutils.c
@@ -125,6 +125,8 @@ gtk_type_init (GTypeDebugFlags debug_flags)
if (!initialized)
{
+ GType unused;
+
initialized = TRUE;
/* initialize GLib type system
@@ -133,7 +135,7 @@ gtk_type_init (GTypeDebugFlags debug_flags)
/* GTK_TYPE_OBJECT
*/
- gtk_object_get_type ();
+ unused = gtk_object_get_type ();
}
}
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 3e64564611..5fd9014ab4 100644
--- a/gtk/gtkviewport.c
+++ b/gtk/gtkviewport.c
@@ -556,6 +556,24 @@ gtk_viewport_get_shadow_type (GtkViewport *viewport)
return viewport->shadow_type;
}
+/**
+ * gtk_viewport_get_bin_window:
+ * @viewport: a #GtkViewport
+ *
+ * Gets the bin window of the #GtkViewport.
+ *
+ * Return value: a #GdkWindow
+ *
+ * Since: 2.20
+ **/
+GdkWindow*
+gtk_viewport_get_bin_window (GtkViewport *viewport)
+{
+ g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
+
+ return viewport->bin_window;
+}
+
static void
gtk_viewport_realize (GtkWidget *widget)
{
diff --git a/gtk/gtkviewport.h b/gtk/gtkviewport.h
index a9300da5ba..da6b97c8d5 100644
--- a/gtk/gtkviewport.h
+++ b/gtk/gtkviewport.h
@@ -83,6 +83,7 @@ void gtk_viewport_set_vadjustment (GtkViewport *viewport,
void gtk_viewport_set_shadow_type (GtkViewport *viewport,
GtkShadowType type);
GtkShadowType gtk_viewport_get_shadow_type (GtkViewport *viewport);
+GdkWindow* gtk_viewport_get_bin_window (GtkViewport *viewport);
G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index e263660eb2..5677fd73f4 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -154,7 +154,8 @@ enum {
PROP_HAS_TOOLTIP,
PROP_TOOLTIP_MARKUP,
PROP_TOOLTIP_TEXT,
- PROP_WINDOW
+ PROP_WINDOW,
+ PROP_DOUBLE_BUFFERED
};
typedef struct _GtkStateData GtkStateData;
@@ -692,6 +693,21 @@ gtk_widget_class_init (GtkWidgetClass *klass)
GDK_TYPE_WINDOW,
GTK_PARAM_READABLE));
+ /**
+ * GtkWidget:double-buffered
+ *
+ * Whether or not the widget is double buffered.
+ *
+ * Since: 2.18
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DOUBLE_BUFFERED,
+ g_param_spec_boolean ("double-buffered",
+ P_("Double Buffered"),
+ P_("Whether or not the widget is double buffered"),
+ TRUE,
+ GTK_PARAM_READWRITE));
+
widget_signals[SHOW] =
g_signal_new (I_("show"),
G_TYPE_FROM_CLASS (gobject_class),
@@ -2399,11 +2415,10 @@ gtk_widget_set_property (GObject *object,
switch (prop_id)
{
gboolean tmp;
- guint32 saved_flags;
gchar *tooltip_markup;
const gchar *tooltip_text;
GtkWindow *tooltip_window;
-
+
case PROP_NAME:
gtk_widget_set_name (widget, g_value_get_string (value));
break;
@@ -2417,10 +2432,7 @@ gtk_widget_set_property (GObject *object,
gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value));
break;
case PROP_VISIBLE:
- if (g_value_get_boolean (value))
- gtk_widget_show (widget);
- else
- gtk_widget_hide (widget);
+ gtk_widget_set_visible (widget, g_value_get_boolean (value));
break;
case PROP_SENSITIVE:
gtk_widget_set_sensitive (widget, g_value_get_boolean (value));
@@ -2429,13 +2441,7 @@ gtk_widget_set_property (GObject *object,
gtk_widget_set_app_paintable (widget, g_value_get_boolean (value));
break;
case PROP_CAN_FOCUS:
- saved_flags = GTK_WIDGET_FLAGS (widget);
- if (g_value_get_boolean (value))
- GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
- else
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
- if (saved_flags != GTK_WIDGET_FLAGS (widget))
- gtk_widget_queue_resize (widget);
+ gtk_widget_set_can_focus (widget, g_value_get_boolean (value));
break;
case PROP_HAS_FOCUS:
if (g_value_get_boolean (value))
@@ -2446,23 +2452,14 @@ gtk_widget_set_property (GObject *object,
gtk_widget_grab_focus (widget);
break;
case PROP_CAN_DEFAULT:
- saved_flags = GTK_WIDGET_FLAGS (widget);
- if (g_value_get_boolean (value))
- GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
- else
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_DEFAULT);
- if (saved_flags != GTK_WIDGET_FLAGS (widget))
- gtk_widget_queue_resize (widget);
+ gtk_widget_set_can_default (widget, g_value_get_boolean (value));
break;
case PROP_HAS_DEFAULT:
if (g_value_get_boolean (value))
gtk_widget_grab_default (widget);
break;
case PROP_RECEIVES_DEFAULT:
- if (g_value_get_boolean (value))
- GTK_WIDGET_SET_FLAGS (widget, GTK_RECEIVES_DEFAULT);
- else
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_RECEIVES_DEFAULT);
+ gtk_widget_set_receives_default (widget, g_value_get_boolean (value));
break;
case PROP_STYLE:
gtk_widget_set_style (widget, g_value_get_object (value));
@@ -2523,6 +2520,9 @@ gtk_widget_set_property (GObject *object,
if (GTK_WIDGET_VISIBLE (widget))
gtk_widget_queue_tooltip_query (widget);
break;
+ case PROP_DOUBLE_BUFFERED:
+ gtk_widget_set_double_buffered (widget, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2630,6 +2630,9 @@ gtk_widget_get_property (GObject *object,
case PROP_WINDOW:
g_value_set_object (value, gtk_widget_get_window (widget));
break;
+ case PROP_DOUBLE_BUFFERED:
+ g_value_set_boolean (value, gtk_widget_get_double_buffered (widget));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -5066,8 +5069,10 @@ _gtk_widget_grab_notify (GtkWidget *widget,
*
* Causes @widget to have the keyboard focus for the #GtkWindow it's
* inside. @widget must be a focusable widget, such as a #GtkEntry;
- * something like #GtkFrame won't work. (More precisely, it must have the
- * %GTK_CAN_FOCUS flag set.)
+ * something like #GtkFrame won't work.
+ *
+ * More precisely, it must have the %GTK_CAN_FOCUS flag set. Use
+ * gtk_widget_set_can_focus() to modify that flag.
**/
void
gtk_widget_grab_focus (GtkWidget *widget)
@@ -5259,6 +5264,74 @@ gtk_widget_real_keynav_failed (GtkWidget *widget,
}
/**
+ * gtk_widget_set_can_focus:
+ * @widget: a #GtkWidget
+ * @can_focus: whether or not @widget can own the input focus.
+ *
+ * Specifies whether @widget can own the input focus. See
+ * gtk_widget_grab_focus() for actually setting the input focus on a
+ * widget.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_widget_set_can_focus (GtkWidget *widget,
+ gboolean can_focus)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (can_focus != GTK_WIDGET_CAN_FOCUS (widget))
+ {
+ if (can_focus)
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+ else
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
+
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "can-focus");
+ }
+}
+
+/**
+ * gtk_widget_get_can_focus:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget can own the input focus. See
+ * gtk_widget_set_can_focus().
+ *
+ * Return value: %TRUE if @widget can own the input focus, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_can_focus (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_CAN_FOCUS (widget);
+}
+
+/**
+ * gtk_widget_has_focus:
+ * @widget: a #GtkWidget
+ *
+ * Determines if the widget has the global input focus. See
+ * gtk_widget_is_focus() for the difference between having the global
+ * input focus, and only having the focus within a toplevel.
+ *
+ * Return value: %TRUE if the widget has the global input focus.
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_has_focus (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_HAS_FOCUS (widget);
+}
+
+/**
* gtk_widget_is_focus:
* @widget: a #GtkWidget
*
@@ -5285,13 +5358,81 @@ gtk_widget_is_focus (GtkWidget *widget)
}
/**
+ * gtk_widget_set_can_default:
+ * @widget: a #GtkWidget
+ * @can_default: whether or not @widget can be a default widget.
+ *
+ * Specifies whether @widget can be a default widget. See
+ * gtk_widget_grab_default() for details about the meaning of
+ * "default".
+ *
+ * Since: 2.18
+ **/
+void
+gtk_widget_set_can_default (GtkWidget *widget,
+ gboolean can_default)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (can_default != GTK_WIDGET_CAN_DEFAULT (widget))
+ {
+ if (can_default)
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
+ else
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_DEFAULT);
+
+ gtk_widget_queue_resize (widget);
+ g_object_notify (G_OBJECT (widget), "can-default");
+ }
+}
+
+/**
+ * gtk_widget_get_can_default:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget can be a default widget. See
+ * gtk_widget_set_can_default().
+ *
+ * Return value: %TRUE if @widget can be a default widget, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_can_default (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_CAN_DEFAULT (widget);
+}
+
+/**
+ * gtk_widget_has_default:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget is the current default widget within its
+ * toplevel. See gtk_widget_set_can_default().
+ *
+ * Return value: %TRUE if @widget is the current default widget within
+ * its toplevel, %FALSE otherwise
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_widget_has_default (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_HAS_DEFAULT (widget);
+}
+
+/**
* gtk_widget_grab_default:
* @widget: a #GtkWidget
*
* Causes @widget to become the default widget. @widget must have the
* %GTK_CAN_DEFAULT flag set; typically you have to set this flag
- * yourself by calling <literal>GTK_WIDGET_SET_FLAGS (@widget,
- * GTK_CAN_DEFAULT)</literal>. The default widget is activated when
+ * yourself by calling <literal>gtk_widget_set_can_default (@widget,
+ * %TRUE)</literal>. The default widget is activated when
* the user presses Enter in a window. Default widgets must be
* activatable, that is, gtk_widget_activate() should affect them.
**/
@@ -5312,6 +5453,81 @@ gtk_widget_grab_default (GtkWidget *widget)
}
/**
+ * gtk_widget_set_receives_default:
+ * @widget: a #GtkWidget
+ * @receives_default: whether or not @widget can be a default widget.
+ *
+ * Specifies whether @widget will be treated as the default widget
+ * within its toplevel when it has the focus, even if another widget
+ * is the default.
+ *
+ * See gtk_widget_grab_default() for details about the meaning of
+ * "default".
+ *
+ * Since: 2.18
+ **/
+void
+gtk_widget_set_receives_default (GtkWidget *widget,
+ gboolean receives_default)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (receives_default != gtk_widget_get_receives_default (widget))
+ {
+ if (receives_default)
+ GTK_WIDGET_SET_FLAGS (widget, GTK_RECEIVES_DEFAULT);
+ else
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_RECEIVES_DEFAULT);
+
+ g_object_notify (G_OBJECT (widget), "receives-default");
+ }
+}
+
+/**
+ * gtk_widget_get_receives_default:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget is alyways treated as default widget
+ * withing its toplevel when it has the focus, even if another widget
+ * is the default.
+ *
+ * See gtk_widget_set_receives_default().
+ *
+ * Return value: %TRUE if @widget acts as default widget when focussed,
+ * %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_receives_default (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_RECEIVES_DEFAULT) != 0;
+}
+
+/**
+ * gtk_widget_has_grab:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether the widget is currently grabbing events, so it
+ * is the only widget receiving input events (keyboard and mouse).
+ *
+ * See also gtk_grab_add().
+ *
+ * Return value: %TRUE if the widget is in the grab_widgets stack
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_has_grab (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_HAS_GRAB) != 0;
+}
+
+/**
* gtk_widget_set_name:
* @widget: a #GtkWidget
* @name: name for the widget
@@ -5401,6 +5617,164 @@ gtk_widget_set_state (GtkWidget *widget,
}
}
+/**
+ * gtk_widget_get_state:
+ * @widget: a #GtkWidget
+ *
+ * Returns the widget's state. See gtk_widget_set_state().
+ *
+ * Returns: the state of @widget.
+ *
+ * Since: 2.18
+ */
+GtkStateType
+gtk_widget_get_state (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), GTK_STATE_NORMAL);
+
+ return widget->state;
+}
+
+/**
+ * gtk_widget_set_visible:
+ * @widget: a #GtkWidget
+ * @visible: whether the widget should be shown or not
+ *
+ * Sets the visibility state of @widget. Note that setting this to
+ * %TRUE doesn't mean the widget is actually viewable, see
+ * gtk_widget_get_visible().
+ *
+ * This function simply calls gtk_widget_show() or gtk_widget_hide()
+ * but is nicer to use when the visibility of the widget depends on
+ * some condition.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_widget_set_visible (GtkWidget *widget,
+ gboolean visible)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (visible != GTK_WIDGET_VISIBLE (widget))
+ {
+ if (visible)
+ gtk_widget_show (widget);
+ else
+ gtk_widget_hide (widget);
+ }
+}
+
+/**
+ * gtk_widget_get_visible:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether the widget is visible. Note that this doesn't
+ * take into account whether the widget's parent is also visible
+ * or the widget is obscured in any way.
+ *
+ * See gtk_widget_set_visible().
+ *
+ * Return value: %TRUE if the widget is visible
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_visible (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_VISIBLE) != 0;
+}
+
+/**
+ * gtk_widget_set_has_window:
+ * @widget: a #GtkWidget
+ * @has_window: whether or not @widget has a window.
+ *
+ * Specifies whether @widget has a #GdkWindow of its own. Note that
+ * all realized widgets have a non-%NULL "window" pointer
+ * (gtk_widget_get_window() never returns a %NULL window when a widget
+ * is realized), but for many of them it's actually the #GdkWindow of
+ * one of its parent widgets. Widgets that create a %window for
+ * themselves in GtkWidget::realize() however must announce this by
+ * calling this function with @has_window = %TRUE.
+ *
+ * This function should only be called by widget implementations,
+ * and they should call it in their init() function.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_widget_set_has_window (GtkWidget *widget,
+ gboolean has_window)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (has_window)
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW);
+ else
+ GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW);
+}
+
+/**
+ * gtk_widget_get_has_window:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget has a #GdkWindow of its own. See
+ * gtk_widget_set_has_window().
+ *
+ * Return value: %TRUE if @widget has a window, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_has_window (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return !GTK_WIDGET_NO_WINDOW (widget);
+}
+
+/**
+ * gtk_widget_is_toplevel:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget is a toplevel widget. Currently only
+ * #GtkWindow and #GtkInvisible are toplevel widgets. Toplevel
+ * widgets have no parent widget.
+ *
+ * Return value: %TRUE if @widget is a toplevel, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_is_toplevel (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_TOPLEVEL) != 0;
+}
+
+/**
+ * gtk_widget_is_drawable:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget can be drawn to. A widget can be drawn
+ * to if it is mapped and visible.
+ *
+ * Return value: %TRUE if @widget is drawable, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_is_drawable (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return ((GTK_WIDGET_FLAGS (widget) & GTK_VISIBLE) != 0 &&
+ (GTK_WIDGET_FLAGS (widget) & GTK_MAPPED) != 0);
+}
/**
* gtk_widget_set_app_paintable:
@@ -5449,6 +5823,27 @@ gtk_widget_set_app_paintable (GtkWidget *widget,
}
/**
+ * gtk_widget_get_app_paintable:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether the application intends to draw on the widget in
+ * an #GtkWidget::expose-event handler.
+ *
+ * See gtk_widget_set_app_paintable()
+ *
+ * Return value: %TRUE if the widget is app paintable
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_app_paintable (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_APP_PAINTABLE) != 0;
+}
+
+/**
* gtk_widget_set_double_buffered:
* @widget: a #GtkWidget
* @double_buffered: %TRUE to double-buffer a widget
@@ -5478,10 +5873,35 @@ gtk_widget_set_double_buffered (GtkWidget *widget,
{
g_return_if_fail (GTK_IS_WIDGET (widget));
- if (double_buffered)
- GTK_WIDGET_SET_FLAGS (widget, GTK_DOUBLE_BUFFERED);
- else
- GTK_WIDGET_UNSET_FLAGS (widget, GTK_DOUBLE_BUFFERED);
+ if (double_buffered != GTK_WIDGET_DOUBLE_BUFFERED (widget))
+ {
+ if (double_buffered)
+ GTK_WIDGET_SET_FLAGS (widget, GTK_DOUBLE_BUFFERED);
+ else
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_DOUBLE_BUFFERED);
+
+ g_object_notify (G_OBJECT (widget), "double-buffered");
+ }
+}
+
+/**
+ * gtk_widget_get_double_buffered:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether the widget is double buffered.
+ *
+ * See gtk_widget_set_double_buffered()
+ *
+ * Return value: %TRUE if the widget is double buffered
+ *
+ * Since: 2.18
+ **/
+gboolean
+gtk_widget_get_double_buffered (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return (GTK_WIDGET_FLAGS (widget) & GTK_DOUBLE_BUFFERED) != 0;
}
/**
@@ -5567,6 +5987,47 @@ gtk_widget_set_sensitive (GtkWidget *widget,
}
/**
+ * gtk_widget_get_sensitive:
+ * @widget: a #GtkWidget
+ *
+ * Returns the widget's sensitivity (in the sense of returning
+ * the value that has been set using gtk_widget_set_sensitive()).
+ *
+ * The effective sensitivity of a widget is however determined by both its
+ * own and its parent widget's sensitivity. See gtk_widget_is_sensitive().
+ *
+ * Returns: %TRUE if the widget is sensitive
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_widget_get_sensitive (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_SENSITIVE (widget);
+}
+
+/**
+ * gtk_widget_is_sensitive:
+ * @widget: a #GtkWidget
+ *
+ * Returns the widget's effective sensitivity, which means
+ * it is sensitive itself and also its parent widget is sensntive
+ *
+ * Returns: %TRUE if the widget is effectively sensitive
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_widget_is_sensitive (GtkWidget *widget)
+{
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ return GTK_WIDGET_IS_SENSITIVE (widget);
+}
+
+/**
* gtk_widget_set_parent:
* @widget: a #GtkWidget
* @parent: parent container
@@ -10142,6 +10603,9 @@ gtk_widget_real_set_has_tooltip (GtkWidget *widget,
* the default tooltip window. If @custom_window is %NULL, the default
* tooltip window will be used.
*
+ * If the custom window should have the default theming it needs to
+ * have the name "gtk-tooltip", see gtk_widget_set_name().
+ *
* Since: 2.12
*/
void
@@ -10371,6 +10835,76 @@ gtk_widget_get_has_tooltip (GtkWidget *widget)
}
/**
+ * gtk_widget_get_allocation:
+ * @widget: a #GtkWidget
+ * @allocation: a pointer to a #GtkAllocation to copy to
+ *
+ * Retrieves the widget's allocation.
+ *
+ * Since: 2.18
+ */
+void
+gtk_widget_get_allocation (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (allocation != NULL);
+
+ *allocation = widget->allocation;
+}
+
+/**
+ * gtk_widget_set_allocation:
+ * @widget: a #GtkWidget
+ * @allocation: a pointer to a #GtkAllocation to copy from
+ *
+ * Sets the widget's allocation. This should not be used
+ * directly, but from within a widget's size_allocate method.
+ *
+ * Since: 2.18
+ */
+void
+gtk_widget_set_allocation (GtkWidget *widget,
+ const GtkAllocation *allocation)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (allocation != NULL);
+
+ widget->allocation = *allocation;
+}
+
+/**
+ * gtk_widget_set_window:
+ * @widget: a #GtkWidget
+ * @window: a #GdkWindow
+ *
+ * Sets a widget's window. This function should only be used in a
+ * widget's GtkWidget::realize() implementation. The %window passed is
+ * usually either new window created with gdk_window_new(), or the
+ * window of its parent widget as returned by
+ * gtk_widget_get_parent_window().
+ *
+ * Widgets must indicate whether they will create their own #GdkWindow
+ * by calling gtk_widget_set_has_window(). This is usually done in the
+ * widget's init() function.
+ *
+ * Since: 2.18
+ */
+void
+gtk_widget_set_window (GtkWidget *widget,
+ GdkWindow *window)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
+
+ if (widget->window != window)
+ {
+ widget->window = window;
+ g_object_notify (G_OBJECT (widget), "window");
+ }
+}
+
+/**
* gtk_widget_get_window:
* @widget: a #GtkWidget
*
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 2d89fb0e29..ed286636d5 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -548,33 +548,80 @@ void gtk_widget_child_notify (GtkWidget *widget,
const gchar *child_property);
void gtk_widget_thaw_child_notify (GtkWidget *widget);
+void gtk_widget_set_can_focus (GtkWidget *widget,
+ gboolean can_focus);
+gboolean gtk_widget_get_can_focus (GtkWidget *widget);
+gboolean gtk_widget_has_focus (GtkWidget *widget);
gboolean gtk_widget_is_focus (GtkWidget *widget);
-void gtk_widget_grab_focus (GtkWidget *widget);
-void gtk_widget_grab_default (GtkWidget *widget);
+void gtk_widget_grab_focus (GtkWidget *widget);
+
+void gtk_widget_set_can_default (GtkWidget *widget,
+ gboolean can_default);
+gboolean gtk_widget_get_can_default (GtkWidget *widget);
+gboolean gtk_widget_has_default (GtkWidget *widget);
+void gtk_widget_grab_default (GtkWidget *widget);
+
+void gtk_widget_set_receives_default (GtkWidget *widget,
+ gboolean receives_default);
+gboolean gtk_widget_get_receives_default (GtkWidget *widget);
+
+gboolean gtk_widget_has_grab (GtkWidget *widget);
void gtk_widget_set_name (GtkWidget *widget,
const gchar *name);
G_CONST_RETURN gchar* gtk_widget_get_name (GtkWidget *widget);
+
void gtk_widget_set_state (GtkWidget *widget,
GtkStateType state);
+GtkStateType gtk_widget_get_state (GtkWidget *widget);
+
void gtk_widget_set_sensitive (GtkWidget *widget,
gboolean sensitive);
+gboolean gtk_widget_get_sensitive (GtkWidget *widget);
+gboolean gtk_widget_is_sensitive (GtkWidget *widget);
+
+void gtk_widget_set_visible (GtkWidget *widget,
+ gboolean visible);
+gboolean gtk_widget_get_visible (GtkWidget *widget);
+
+void gtk_widget_set_has_window (GtkWidget *widget,
+ gboolean has_window);
+gboolean gtk_widget_get_has_window (GtkWidget *widget);
+
+gboolean gtk_widget_is_toplevel (GtkWidget *widget);
+gboolean gtk_widget_is_drawable (GtkWidget *widget);
+
void gtk_widget_set_app_paintable (GtkWidget *widget,
gboolean app_paintable);
+gboolean gtk_widget_get_app_paintable (GtkWidget *widget);
+
void gtk_widget_set_double_buffered (GtkWidget *widget,
gboolean double_buffered);
+gboolean gtk_widget_get_double_buffered (GtkWidget *widget);
+
void gtk_widget_set_redraw_on_allocate (GtkWidget *widget,
gboolean redraw_on_allocate);
+
void gtk_widget_set_parent (GtkWidget *widget,
GtkWidget *parent);
GtkWidget * gtk_widget_get_parent (GtkWidget *widget);
+
void gtk_widget_set_parent_window (GtkWidget *widget,
GdkWindow *parent_window);
GdkWindow * gtk_widget_get_parent_window (GtkWidget *widget);
+
void gtk_widget_set_child_visible (GtkWidget *widget,
gboolean is_visible);
gboolean gtk_widget_get_child_visible (GtkWidget *widget);
-GdkWindow* gtk_widget_get_window (GtkWidget *widget);
+
+void gtk_widget_set_window (GtkWidget *widget,
+ GdkWindow *window);
+GdkWindow * gtk_widget_get_window (GtkWidget *widget);
+
+void gtk_widget_get_allocation (GtkWidget *widget,
+ GtkAllocation *allocation);
+void gtk_widget_set_allocation (GtkWidget *widget,
+ const GtkAllocation *allocation);
gboolean gtk_widget_child_focus (GtkWidget *widget,
GtkDirectionType direction);
@@ -816,8 +863,8 @@ GtkRequisition *gtk_requisition_copy (const GtkRequisition *requisition);
void gtk_requisition_free (GtkRequisition *requisition);
#if defined (GTK_TRACE_OBJECTS) && defined (__GNUC__)
-# define gtk_widget_ref gtk_object_ref
-# define gtk_widget_unref gtk_object_unref
+# define gtk_widget_ref g_object_ref
+# define gtk_widget_unref g_object_unref
#endif /* GTK_TRACE_OBJECTS && __GNUC__ */
void _gtk_widget_grab_notify (GtkWidget *widget,
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 1238c2295c..e0e6afe196 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -496,7 +496,7 @@ gtk_window_class_init (GtkWindowClass *klass)
P_("Unique identifier for the window to be used when restoring a session"),
NULL,
GTK_PARAM_READWRITE));
-
+
/**
* GtkWindow:startup-id:
*
@@ -505,9 +505,9 @@ gtk_window_class_init (GtkWindowClass *klass)
* for more details.
*
* Since: 2.12
- */
+ */
g_object_class_install_property (gobject_class,
- PROP_ROLE,
+ PROP_STARTUP_ID,
g_param_spec_string ("startup-id",
P_("Startup ID"),
P_("Unique startup identifier for the window used by startup-notification"),
@@ -4400,6 +4400,7 @@ static void
gtk_window_finalize (GObject *object)
{
GtkWindow *window = GTK_WINDOW (object);
+ GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
GtkMnemonicHash *mnemonic_hash;
g_free (window->title);
@@ -4427,11 +4428,11 @@ gtk_window_finalize (GObject *object)
}
if (window->screen)
- {
- g_signal_handlers_disconnect_by_func (window->screen,
- gtk_window_on_composited_changed, window);
- }
-
+ g_signal_handlers_disconnect_by_func (window->screen,
+ gtk_window_on_composited_changed, window);
+
+ g_free (priv->startup_id);
+
G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
}
@@ -4601,7 +4602,8 @@ gtk_window_map (GtkWidget *widget)
/* Make sure we have a "real" id */
if (!startup_id_is_fake (priv->startup_id))
gdk_notify_startup_complete_with_id (priv->startup_id);
-
+
+ g_free (priv->startup_id);
priv->startup_id = NULL;
}
else if (!sent_startup_notification)
@@ -5646,6 +5648,13 @@ gtk_window_compute_configure_request_size (GtkWindow *window,
if (info->resize_height > 0)
*height = info->resize_height;
}
+
+ /* Don't ever request zero width or height, its not supported by
+ gdk. The size allocation code will round it to 1 anyway but if
+ we do it then the value returned from this function will is
+ not comparable to the size allocation read from the GtkWindow. */
+ *width = MAX (*width, 1);
+ *height = MAX (*height, 1);
}
static GtkWindowPosition
@@ -5744,7 +5753,7 @@ clamp_window_to_rectangle (gint *x,
const GdkRectangle *rect)
{
#ifdef DEBUGGING_OUTPUT
- g_print ("%s: %+d%+d %dx%d: %+d%+d: %dx%d", __FUNCTION__, rect->x, rect->y, rect->width, rect->height, *x, *y, w, h);
+ g_print ("%s: %+d%+d %dx%d: %+d%+d: %dx%d", G_STRFUNC, rect->x, rect->y, rect->width, rect->height, *x, *y, w, h);
#endif
/* If it is too large, center it. If it fits on the monitor but is
@@ -8319,7 +8328,7 @@ _gtk_window_set_is_active (GtkWindow *window,
}
/**
- * _gtk_windwo_set_is_toplevel:
+ * _gtk_window_set_is_toplevel:
* @window: a #GtkWindow
* @is_toplevel: %TRUE if the window is still a real toplevel (nominally a
* parent of the root window); %FALSE if it is not (for example, for an
diff --git a/gtk/makefile.msc.in b/gtk/makefile.msc.in
index 0227fa7f0f..bb6ac9999e 100644
--- a/gtk/makefile.msc.in
+++ b/gtk/makefile.msc.in
@@ -572,10 +572,10 @@ gtk.def: gtk.symbols makefile.msc
-DG_GNUC_PRINTF=;G_GNUC_PRINTF gtk.symbols >> gtk.def
gtkalias.h: gtk.symbols
- cl /EP -DG_OS_WIN32 -DGTK_WINDOWING_WIN32 -DINCLUDE_INTERNAL_SYMBOLS gtk.symbols | $(PERL) makegtkalias.pl > gtkalias.h
+ $(PERL) makegtkalias.pl < gtk.symbols > gtkalias.h
gtkaliasdef.c: gtk.symbols
- perl makegtkalias.pl -def < gtk.symbols > gtkaliasdef.c
+ $(PERL) makegtkalias.pl -def < gtk.symbols > gtkaliasdef.c
# generate type identifier header (GTK_TYPE_WIDGET_FLAGS)
# use 'echo' to work around 'command line too long'
diff --git a/gtk/tests/Makefile.am b/gtk/tests/Makefile.am
index 4c8ff1f1a6..c287c258df 100644
--- a/gtk/tests/Makefile.am
+++ b/gtk/tests/Makefile.am
@@ -34,6 +34,10 @@ TEST_PROGS += treestore
treestore_SOURCES = treestore.c
treestore_LDADD = $(progs_ldadd)
+TEST_PROGS += treeview
+treeview_SOURCES = treeview.c
+treeview_LDADD = $(progs_ldadd)
+
TEST_PROGS += treeview-scrolling
treeview_scrolling_SOURCES = treeview-scrolling.c
treeview_scrolling_LDADD = $(progs_ldadd)
@@ -78,4 +82,12 @@ TEST_PROGS += textbuffer
textbuffer_SOURCES = textbuffer.c pixbuf-init.c
textbuffer_LDADD = $(progs_ldadd)
+TEST_PROGS += filtermodel
+filtermodel_SOURCES = filtermodel.c
+filtermodel_LDADD = $(progs_ldadd)
+
+TEST_PROGS += expander
+expander_SOURCES = expander.c
+expander_LDADD = $(progs_ldadd)
+
-include $(top_srcdir)/git.mk
diff --git a/gtk/tests/builder.c b/gtk/tests/builder.c
index f5a85ac4fa..2ae604d5e6 100644
--- a/gtk/tests/builder.c
+++ b/gtk/tests/builder.c
@@ -116,6 +116,13 @@ test_parser (void)
GTK_BUILDER_ERROR_INVALID_VALUE));
g_error_free (error);
+ error = NULL;
+ gtk_builder_add_from_string (builder, "<interface><object class=\"GtkButton\" id=\"a\"></object><object class=\"GtkButton\" id=\"a\"/></object></interface>", -1, &error);
+ g_assert (g_error_matches (error,
+ GTK_BUILDER_ERROR,
+ GTK_BUILDER_ERROR_DUPLICATE_ID));
+ g_error_free (error);
+
g_object_unref (builder);
}
@@ -1944,6 +1951,8 @@ test_icon_factory (void)
gtk_icon_factory_add_default (GTK_ICON_FACTORY (factory));
image = gtk_image_new_from_stock ("apple-red", GTK_ICON_SIZE_BUTTON);
g_assert (image != NULL);
+ g_object_ref_sink (image);
+ g_object_unref (image);
g_object_unref (builder);
@@ -2129,6 +2138,7 @@ test_requires (void)
GTK_BUILDER_ERROR_VERSION_MISMATCH));
g_object_unref (builder);
g_error_free (error);
+ g_free (buffer);
}
static void
@@ -2172,7 +2182,7 @@ test_add_objects (void)
" </object>"
" <object class=\"GtkWindow\" id=\"window2\">"
" <child>"
- " <object class=\"GtkLabel\" id=\"label1\">"
+ " <object class=\"GtkLabel\" id=\"label3\">"
" <property name=\"label\" translatable=\"no\">second label</property>"
" </object>"
" </child>"
diff --git a/gtk/tests/defaultvalue.c b/gtk/tests/defaultvalue.c
index 6a157e42ae..a3534b176d 100644
--- a/gtk/tests/defaultvalue.c
+++ b/gtk/tests/defaultvalue.c
@@ -173,8 +173,8 @@ test_type (gconstpointer data)
/* Default invisible char is determined at runtime */
if (g_type_is_a (type, GTK_TYPE_ENTRY) &&
- strcmp (pspec->name, "invisible-char") == 0 ||
- strcmp (pspec->name, "buffer") == 0)
+ (strcmp (pspec->name, "invisible-char") == 0 ||
+ strcmp (pspec->name, "buffer") == 0))
continue;
/* Gets set to the cwd */
@@ -239,7 +239,10 @@ test_type (gconstpointer data)
strcmp (pspec->name, "gtk-icon-theme-name") == 0 ||
strcmp (pspec->name, "gtk-im-module") == 0 ||
strcmp (pspec->name, "gtk-key-theme-name") == 0 ||
- strcmp (pspec->name, "gtk-theme-name") == 0))
+ strcmp (pspec->name, "gtk-theme-name") == 0 ||
+ strcmp (pspec->name, "gtk-sound-theme-name") == 0 ||
+ strcmp (pspec->name, "gtk-enable-input-feedback-sounds") == 0 ||
+ strcmp (pspec->name, "gtk-enable-event-sounds") == 0))
continue;
if (g_type_is_a (type, GTK_TYPE_SPIN_BUTTON) &&
diff --git a/gtk/tests/expander.c b/gtk/tests/expander.c
new file mode 100644
index 0000000000..853b20aada
--- /dev/null
+++ b/gtk/tests/expander.c
@@ -0,0 +1,94 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+#include <gtk/gtk.h>
+
+static void
+test_click_expander (void)
+{
+ GtkWidget *window = gtk_test_create_simple_window ("Test Window", "Test click on expander");
+ GtkWidget *expander = gtk_expander_new ("Test Expander");
+ GtkWidget *label = gtk_label_new ("Test Label");
+ gboolean expanded;
+ gboolean simsuccess;
+ gtk_container_add (GTK_CONTAINER (expander), label);
+ gtk_container_add (GTK_CONTAINER (GTK_BIN (window)->child), expander);
+ gtk_widget_show (expander);
+ gtk_widget_show (label);
+ gtk_widget_show_now (window);
+ /* check initial expander state */
+ expanded = gtk_expander_get_expanded (GTK_EXPANDER (expander));
+ g_assert (!expanded);
+ /* check expanding */
+ simsuccess = gtk_test_widget_click (expander, 1, 0);
+ g_assert (simsuccess == TRUE);
+ while (gtk_events_pending ()) /* let expander timeout/idle handlers update */
+ gtk_main_iteration ();
+ expanded = gtk_expander_get_expanded (GTK_EXPANDER (expander));
+ g_assert (expanded);
+ /* check collapsing */
+ simsuccess = gtk_test_widget_click (expander, 1, 0);
+ g_assert (simsuccess == TRUE);
+ while (gtk_events_pending ()) /* let expander timeout/idle handlers update */
+ gtk_main_iteration ();
+ expanded = gtk_expander_get_expanded (GTK_EXPANDER (expander));
+ g_assert (!expanded);
+}
+
+static void
+test_click_content_widget (void)
+{
+ GtkWidget *window = gtk_test_create_simple_window ("Test Window", "Test click on content widget");
+ GtkWidget *expander = gtk_expander_new ("Test Expander");
+ GtkWidget *entry = gtk_entry_new ();
+ gboolean expanded;
+ gboolean simsuccess;
+ gtk_container_add (GTK_CONTAINER (expander), entry);
+ gtk_container_add (GTK_CONTAINER (GTK_BIN (window)->child), expander);
+ gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
+ gtk_widget_show (expander);
+ gtk_widget_show (entry);
+ gtk_widget_show_now (window);
+
+ /* check click on content with expander open */
+ expanded = gtk_expander_get_expanded (GTK_EXPANDER (expander));
+ g_assert (expanded);
+ simsuccess = gtk_test_widget_click (entry, 1, 0);
+ g_assert (simsuccess == TRUE);
+ while (gtk_events_pending ()) /* let expander timeout/idle handlers update */
+ gtk_main_iteration ();
+ expanded = gtk_expander_get_expanded (GTK_EXPANDER (expander));
+ g_assert (expanded);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ gtk_test_init (&argc, &argv);
+ g_test_add_func ("/expander/click-expander", test_click_expander);
+ g_test_add_func ("/expander/click-content-widget", test_click_content_widget);
+ return g_test_run();
+}
diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c
new file mode 100644
index 0000000000..22253e0144
--- /dev/null
+++ b/gtk/tests/filtermodel.c
@@ -0,0 +1,3000 @@
+/* Extensive GtkTreeModelFilter tests.
+ * Copyright (C) 2009 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+
+/* Left to do:
+ * - Proper coverage checking to see if the unit tests cover
+ * all possible cases.
+ * - Verify if the ref counting is done properly for both the
+ * normal ref_count and the zero_ref_count. One way to test
+ * this area is by collapsing/expanding branches on the view
+ * that is connected to the filter model.
+ * - Check if the iterator stamp is incremented at the correct times.
+ */
+
+
+/*
+ * Model creation
+ */
+
+#define LEVEL_LENGTH 5
+
+static void
+create_tree_store_set_values (GtkTreeStore *store,
+ GtkTreeIter *iter,
+ gboolean visible)
+{
+ GtkTreePath *path;
+ gchar *path_string;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ path_string = gtk_tree_path_to_string (path);
+
+ gtk_tree_store_set (store, iter,
+ 0, path_string,
+ 1, visible,
+ -1);
+
+ gtk_tree_path_free (path);
+ g_free (path_string);
+}
+
+static void
+create_tree_store_recurse (int depth,
+ GtkTreeStore *store,
+ GtkTreeIter *parent,
+ gboolean visible)
+{
+ int i;
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ GtkTreeIter iter;
+
+ gtk_tree_store_insert (store, &iter, parent, i);
+ create_tree_store_set_values (store, &iter, visible);
+
+ if (depth > 0)
+ create_tree_store_recurse (depth - 1, store, &iter, visible);
+ }
+}
+
+static GtkTreeStore *
+create_tree_store (int depth,
+ gboolean visible)
+{
+ GtkTreeStore *store;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+ create_tree_store_recurse (depth, store, NULL, visible);
+
+ return store;
+}
+
+/*
+ * Signal monitor
+ */
+
+typedef enum
+{
+ ROW_INSERTED,
+ ROW_DELETED,
+ ROW_CHANGED,
+ ROW_HAS_CHILD_TOGGLED,
+ ROWS_REORDERED,
+ LAST_SIGNAL
+}
+SignalName;
+
+static const char *
+signal_name_to_string (SignalName signal)
+{
+ switch (signal)
+ {
+ case ROW_INSERTED:
+ return "row-inserted";
+
+ case ROW_DELETED:
+ return "row-deleted";
+
+ case ROW_CHANGED:
+ return "row-changed";
+
+ case ROW_HAS_CHILD_TOGGLED:
+ return "row-has-child-toggled";
+
+ case ROWS_REORDERED:
+ return "rows-reordered";
+
+ default:
+ /* Fall through */
+ break;
+ }
+
+ return "(unknown)";
+}
+
+typedef struct
+{
+ SignalName signal;
+ GtkTreePath *path;
+}
+Signal;
+
+
+static Signal *
+signal_new (SignalName signal, GtkTreePath *path)
+{
+ Signal *s;
+
+ s = g_new0 (Signal, 1);
+ s->signal = signal;
+ s->path = gtk_tree_path_copy (path);
+
+ return s;
+}
+
+static void
+signal_free (Signal *s)
+{
+ if (s->path)
+ gtk_tree_path_free (s->path);
+
+ g_free (s);
+}
+
+
+typedef struct
+{
+ GQueue *queue;
+ GtkTreeModel *client;
+ guint signal_ids[LAST_SIGNAL];
+}
+SignalMonitor;
+
+
+static void
+signal_monitor_generic_handler (SignalMonitor *m,
+ SignalName signal,
+ GtkTreeModel *model,
+ GtkTreePath *path)
+{
+ Signal *s;
+
+ if (g_queue_is_empty (m->queue))
+ {
+ g_error ("Signal queue empty\n");
+ g_assert_not_reached ();
+ }
+
+ if (m->client != model)
+ {
+ g_error ("Model mismatch; expected %p, got %p\n",
+ m->client, model);
+ g_assert_not_reached ();
+ }
+
+ s = g_queue_peek_tail (m->queue);
+
+#if 0
+ /* For debugging: output signals that are coming in. Leaks memory. */
+ g_print ("signal=%d path=%s\n", signal, gtk_tree_path_to_string (path));
+#endif
+
+ if (s->signal != signal
+ || gtk_tree_path_compare (s->path, path) != 0)
+ {
+ gchar *path_str, *s_path_str;
+
+ s_path_str = gtk_tree_path_to_string (s->path);
+ path_str = gtk_tree_path_to_string (path);
+
+ g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
+ signal_name_to_string (s->signal), s_path_str,
+ signal_name_to_string (signal), path_str);
+
+ g_free (s_path_str);
+ g_free (path_str);
+
+ g_assert_not_reached ();
+ }
+
+ s = g_queue_pop_tail (m->queue);
+
+ signal_free (s);
+}
+
+static void
+signal_monitor_row_inserted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_INSERTED,
+ model, path);
+}
+
+static void
+signal_monitor_row_deleted (GtkTreeModel *model,
+ GtkTreePath *path,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_DELETED,
+ model, path);
+}
+
+static void
+signal_monitor_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_CHANGED,
+ model, path);
+}
+
+static void
+signal_monitor_row_has_child_toggled (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
+ model, path);
+}
+
+static void
+signal_monitor_rows_reordered (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gint *new_order,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROWS_REORDERED,
+ model, path);
+}
+
+static SignalMonitor *
+signal_monitor_new (GtkTreeModel *client)
+{
+ SignalMonitor *m;
+
+ m = g_new0 (SignalMonitor, 1);
+ m->client = g_object_ref (client);
+ m->queue = g_queue_new ();
+
+ m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
+ "row-inserted",
+ G_CALLBACK (signal_monitor_row_inserted),
+ m);
+ m->signal_ids[ROW_DELETED] = g_signal_connect (client,
+ "row-deleted",
+ G_CALLBACK (signal_monitor_row_deleted),
+ m);
+ m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
+ "row-changed",
+ G_CALLBACK (signal_monitor_row_changed),
+ m);
+ m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
+ "row-has-child-toggled",
+ G_CALLBACK (signal_monitor_row_has_child_toggled),
+ m);
+ m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
+ "rows-reordered",
+ G_CALLBACK (signal_monitor_rows_reordered),
+ m);
+
+ return m;
+}
+
+static void
+signal_monitor_free (SignalMonitor *m)
+{
+ int i;
+
+ for (i = 0; i < LAST_SIGNAL; i++)
+ g_signal_handler_disconnect (m->client, m->signal_ids[i]);
+
+ g_object_unref (m->client);
+
+ if (m->queue)
+ g_queue_free (m->queue);
+
+ g_free (m);
+}
+
+static void
+signal_monitor_assert_is_empty (SignalMonitor *m)
+{
+ g_assert (g_queue_is_empty (m->queue));
+}
+
+static void
+signal_monitor_append_signal_path (SignalMonitor *m,
+ SignalName signal,
+ GtkTreePath *path)
+{
+ Signal *s;
+
+ s = signal_new (signal, path);
+ g_queue_push_head (m->queue, s);
+}
+
+static void
+signal_monitor_append_signal (SignalMonitor *m,
+ SignalName signal,
+ const gchar *path_string)
+{
+ Signal *s;
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_string (path_string);
+
+ s = signal_new (signal, path);
+ g_queue_push_head (m->queue, s);
+
+ gtk_tree_path_free (path);
+}
+
+/*
+ * Fixture
+ */
+
+typedef struct
+{
+ GtkWidget *tree_view;
+
+ GtkTreeStore *store;
+ GtkTreeModelFilter *filter;
+
+ SignalMonitor *monitor;
+
+ guint block_signals : 1;
+} FilterTest;
+
+
+static void
+filter_test_store_signal (FilterTest *fixture)
+{
+ if (fixture->block_signals)
+ g_signal_stop_emission_by_name (fixture->store, "row-changed");
+}
+
+
+static void
+filter_test_setup_generic (FilterTest *fixture,
+ gconstpointer test_data,
+ int depth,
+ gboolean empty,
+ gboolean unfiltered)
+{
+ const GtkTreePath *vroot = test_data;
+ GtkTreeModel *filter;
+
+ fixture->store = create_tree_store (depth, !empty);
+
+ g_signal_connect_swapped (fixture->store, "row-changed",
+ G_CALLBACK (filter_test_store_signal), fixture);
+
+ /* Please forgive me for casting const away. */
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
+ (GtkTreePath *)vroot);
+ fixture->filter = GTK_TREE_MODEL_FILTER (filter);
+
+ if (!unfiltered)
+ gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
+
+ /* We need a tree view that's listening to get ref counting from that
+ * side.
+ */
+ fixture->tree_view = gtk_tree_view_new_with_model (filter);
+
+ fixture->monitor = signal_monitor_new (filter);
+}
+
+static void
+filter_test_setup (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
+}
+
+static void
+filter_test_setup_empty (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
+}
+
+static void
+filter_test_setup_unfiltered (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
+}
+
+static void
+filter_test_setup_empty_unfiltered (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
+}
+
+static GtkTreePath *
+strip_virtual_root (GtkTreePath *path,
+ GtkTreePath *root_path)
+{
+ GtkTreePath *real_path;
+
+ if (root_path)
+ {
+ int j;
+ int depth = gtk_tree_path_get_depth (path);
+ int root_depth = gtk_tree_path_get_depth (root_path);
+
+ real_path = gtk_tree_path_new ();
+
+ for (j = 0; j < depth - root_depth; j++)
+ gtk_tree_path_append_index (real_path,
+ gtk_tree_path_get_indices (path)[root_depth + j]);
+ }
+ else
+ real_path = gtk_tree_path_copy (path);
+
+ return real_path;
+}
+
+static void
+filter_test_append_refilter_signals_recurse (FilterTest *fixture,
+ GtkTreePath *store_path,
+ GtkTreePath *filter_path,
+ int depth,
+ GtkTreePath *root_path)
+{
+ int i;
+ int rows_deleted = 0;
+ GtkTreeIter iter;
+
+ gtk_tree_path_down (store_path);
+ gtk_tree_path_down (filter_path);
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, store_path);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ gboolean visible;
+ GtkTreePath *real_path;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
+ 1, &visible,
+ -1);
+
+ if (root_path &&
+ (!gtk_tree_path_is_descendant (store_path, root_path)
+ || !gtk_tree_path_compare (store_path, root_path)))
+ {
+ if (!gtk_tree_path_compare (store_path, root_path))
+ {
+ if (depth > 1
+ && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
+ &iter))
+ {
+ GtkTreePath *store_copy;
+ GtkTreePath *filter_copy;
+
+ store_copy = gtk_tree_path_copy (store_path);
+ filter_copy = gtk_tree_path_copy (filter_path);
+ filter_test_append_refilter_signals_recurse (fixture,
+ store_copy,
+ filter_copy,
+ depth - 1,
+ root_path);
+ gtk_tree_path_free (store_copy);
+ gtk_tree_path_free (filter_copy);
+ }
+ }
+
+ gtk_tree_path_next (store_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+
+ if (visible)
+ gtk_tree_path_next (filter_path);
+
+ continue;
+ }
+
+ real_path = strip_virtual_root (filter_path, root_path);
+
+ if (visible)
+ {
+ /* This row will be inserted */
+ signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
+ real_path);
+ signal_monitor_append_signal_path (fixture->monitor,
+ ROW_HAS_CHILD_TOGGLED,
+ real_path);
+
+ if (depth > 1
+ && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
+ &iter))
+ {
+ GtkTreePath *store_copy;
+ GtkTreePath *filter_copy;
+
+ store_copy = gtk_tree_path_copy (store_path);
+ filter_copy = gtk_tree_path_copy (filter_path);
+ filter_test_append_refilter_signals_recurse (fixture,
+ store_copy,
+ filter_copy,
+ depth - 1,
+ root_path);
+ gtk_tree_path_free (store_copy);
+ gtk_tree_path_free (filter_copy);
+ }
+
+ gtk_tree_path_next (filter_path);
+ }
+ else
+ {
+ /* This row will be deleted */
+ rows_deleted++;
+ signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
+ real_path);
+ }
+
+ gtk_tree_path_free (real_path);
+
+ gtk_tree_path_next (store_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ }
+
+ if (rows_deleted == LEVEL_LENGTH
+ && gtk_tree_path_get_depth (filter_path) > 1)
+ {
+ GtkTreePath *real_path;
+
+ gtk_tree_path_up (store_path);
+ gtk_tree_path_up (filter_path);
+
+ /* A row-has-child-toggled will be emitted on the parent */
+ if (!root_path
+ || (root_path
+ && gtk_tree_path_is_descendant (store_path, root_path)
+ && gtk_tree_path_compare (store_path, root_path)))
+ {
+ real_path = strip_virtual_root (filter_path, root_path);
+ signal_monitor_append_signal_path (fixture->monitor,
+ ROW_HAS_CHILD_TOGGLED,
+ real_path);
+
+ gtk_tree_path_free (real_path);
+ }
+ }
+}
+
+static void
+filter_test_append_refilter_signals (FilterTest *fixture,
+ int depth)
+{
+ /* A special function that walks the tree store like the
+ * model validation functions below.
+ */
+ GtkTreePath *path;
+ GtkTreePath *filter_path;
+
+ path = gtk_tree_path_new ();
+ filter_path = gtk_tree_path_new ();
+ filter_test_append_refilter_signals_recurse (fixture,
+ path,
+ filter_path,
+ depth,
+ NULL);
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (filter_path);
+}
+
+static void
+filter_test_append_refilter_signals_with_vroot (FilterTest *fixture,
+ int depth,
+ GtkTreePath *root_path)
+{
+ /* A special function that walks the tree store like the
+ * model validation functions below.
+ */
+ GtkTreePath *path;
+ GtkTreePath *filter_path;
+
+ path = gtk_tree_path_new ();
+ filter_path = gtk_tree_path_new ();
+ filter_test_append_refilter_signals_recurse (fixture,
+ path,
+ filter_path,
+ depth,
+ root_path);
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (filter_path);
+}
+
+static void
+filter_test_enable_filter (FilterTest *fixture)
+{
+ gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
+ gtk_tree_model_filter_refilter (fixture->filter);
+}
+
+static void
+filter_test_block_signals (FilterTest *fixture)
+{
+ fixture->block_signals = TRUE;
+}
+
+static void
+filter_test_unblock_signals (FilterTest *fixture)
+{
+ fixture->block_signals = FALSE;
+}
+
+static void
+filter_test_teardown (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ signal_monitor_free (fixture->monitor);
+
+ g_object_unref (fixture->filter);
+ g_object_unref (fixture->store);
+}
+
+/*
+ * Model structure validation
+ */
+
+static void
+check_filter_model_recurse (FilterTest *fixture,
+ GtkTreePath *store_parent_path,
+ GtkTreePath *filter_parent_path)
+{
+ int i;
+ GtkTreeIter store_iter;
+ GtkTreeIter filter_iter;
+ gboolean store_has_next, filter_has_next;
+
+ gtk_tree_path_down (store_parent_path);
+ gtk_tree_path_down (filter_parent_path);
+
+ store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &store_iter, store_parent_path);
+ filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
+ &filter_iter, filter_parent_path);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ gboolean visible;
+
+ g_return_if_fail (store_has_next == TRUE);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
+ &store_iter,
+ 1, &visible,
+ -1);
+
+ if (visible)
+ {
+ GtkTreePath *tmp;
+ gchar *filter_str, *store_str;
+
+ g_return_if_fail (filter_has_next == TRUE);
+
+ /* Verify path */
+ tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
+ &filter_iter);
+ g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
+
+ /* Verify model content */
+ gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
+ &store_iter,
+ 0, &store_str,
+ -1);
+ gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
+ &filter_iter,
+ 0, &filter_str,
+ -1);
+
+ g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
+
+ g_free (store_str);
+ g_free (filter_str);
+
+ if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
+ &filter_iter))
+ {
+ g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
+
+ check_filter_model_recurse (fixture,
+ gtk_tree_path_copy (store_parent_path),
+ tmp);
+ }
+
+ gtk_tree_path_next (filter_parent_path);
+ filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
+ }
+
+ gtk_tree_path_next (store_parent_path);
+ store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
+ }
+
+ /* Both models should have no more content! */
+ g_return_if_fail (store_has_next == FALSE);
+ g_return_if_fail (filter_has_next == FALSE);
+
+ gtk_tree_path_free (store_parent_path);
+ gtk_tree_path_free (filter_parent_path);
+}
+
+static void
+check_filter_model (FilterTest *fixture)
+{
+ GtkTreePath *path;
+
+ if (fixture->monitor)
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ path = gtk_tree_path_new ();
+
+ check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
+}
+
+static void
+check_filter_model_with_root (FilterTest *fixture,
+ GtkTreePath *path)
+{
+ if (fixture->monitor)
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ check_filter_model_recurse (fixture,
+ gtk_tree_path_copy (path),
+ gtk_tree_path_new ());
+}
+
+/* Helpers */
+
+static void
+check_level_length (GtkTreeModelFilter *filter,
+ const gchar *level,
+ const int length)
+{
+ if (!level)
+ {
+ int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
+ g_return_if_fail (l == length);
+ }
+ else
+ {
+ int l;
+ gboolean retrieved_iter = FALSE;
+ GtkTreeIter iter;
+
+ retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
+ &iter, level);
+ g_return_if_fail (retrieved_iter);
+ l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
+ g_return_if_fail (l == length);
+ }
+}
+
+static void
+set_path_visibility (FilterTest *fixture,
+ const gchar *path,
+ gboolean visible)
+{
+ GtkTreeIter store_iter;
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &store_iter, path);
+ gtk_tree_store_set (fixture->store, &store_iter,
+ 1, visible,
+ -1);
+}
+
+#if 0
+static void
+insert_path_with_visibility (FilterTest *fixture,
+ const gchar *path_string,
+ gboolean visible)
+{
+ int position;
+ GtkTreePath *path;
+ GtkTreeIter parent, iter;
+
+ path = gtk_tree_path_new_from_string (path_string);
+ position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
+ gtk_tree_path_up (path);
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
+ {
+ gtk_tree_store_insert (fixture->store, &iter, &parent, position);
+ create_tree_store_set_values (fixture->store, &iter, visible);
+ }
+ gtk_tree_path_free (path);
+}
+#endif
+
+/*
+ * The actual tests.
+ */
+
+static void
+verify_test_suite (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ check_filter_model (fixture);
+}
+
+static void
+verify_test_suite_vroot (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
+}
+
+
+static void
+filled_hide_root_level (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
+ set_path_visibility (fixture, "2", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "0", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
+ set_path_visibility (fixture, "4", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
+
+
+ /* Hide remaining */
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+
+ set_path_visibility (fixture, "1", FALSE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
+
+ set_path_visibility (fixture, "3", FALSE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
+
+ check_filter_model (fixture);
+
+ /* Show some */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ set_path_visibility (fixture, "1", TRUE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
+
+ set_path_visibility (fixture, "3", TRUE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
+
+ check_filter_model (fixture);
+}
+
+static void
+filled_hide_child_levels (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
+ set_path_visibility (fixture, "0:2", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
+ set_path_visibility (fixture, "0:4", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "0:4:3", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "0:4:0", FALSE);
+ set_path_visibility (fixture, "0:4:1", FALSE);
+ set_path_visibility (fixture, "0:4:2", FALSE);
+ set_path_visibility (fixture, "0:4:4", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
+ /* FIXME: Actually, the filter model should not be emitted the
+ * row-has-child-toggled signal here. *However* an extraneous emission
+ * of this signal does not hurt and is allowed.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
+ set_path_visibility (fixture, "0:4", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, "0:3", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
+ set_path_visibility (fixture, "0:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:4", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
+ /* Once 0:4:0 got inserted, 0:4 became a parent */
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
+
+ set_path_visibility (fixture, "0:4:2", TRUE);
+ set_path_visibility (fixture, "0:4:4", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, "0:4", 2);
+}
+
+
+static void
+filled_vroot_hide_root_level (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ /* These changes do not affect the filter's root level */
+ set_path_visibility (fixture, "0", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ set_path_visibility (fixture, "4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ /* Even though we set the virtual root parent node to FALSE,
+ * the virtual root contents remain.
+ */
+ set_path_visibility (fixture, "2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ /* No change */
+ set_path_visibility (fixture, "1", FALSE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ set_path_visibility (fixture, "3", FALSE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ check_filter_model_with_root (fixture, path);
+
+ /* Show some */
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ set_path_visibility (fixture, "1", TRUE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ set_path_visibility (fixture, "3", TRUE);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH);
+
+ check_filter_model_with_root (fixture, path);
+
+ /* Now test changes in the virtual root level */
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
+ set_path_visibility (fixture, "2:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
+ set_path_visibility (fixture, "2:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "1:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
+ set_path_visibility (fixture, "2:4", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+
+ set_path_visibility (fixture, "2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "2:0", FALSE);
+ set_path_visibility (fixture, "2:1", FALSE);
+ set_path_visibility (fixture, "2:2", FALSE);
+ set_path_visibility (fixture, "2:3", FALSE);
+ set_path_visibility (fixture, "2:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "1:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:4", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "2:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2:0", TRUE);
+ set_path_visibility (fixture, "2:1", TRUE);
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
+}
+
+static void
+filled_vroot_hide_child_levels (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
+ set_path_visibility (fixture, "2:0:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
+ set_path_visibility (fixture, "2:0:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "2:0:4:3", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "2:0:4:0", FALSE);
+ set_path_visibility (fixture, "2:0:4:1", FALSE);
+ set_path_visibility (fixture, "2:0:4:2", FALSE);
+ set_path_visibility (fixture, "2:0:4:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
+ /* FIXME: Actually, the filter model should not be emitted the
+ * row-has-child-toggled signal here. *However* an extraneous emission
+ * of this signal does not hurt and is allowed.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
+ set_path_visibility (fixture, "2:0:4", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, "0:3", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
+ set_path_visibility (fixture, "2:0:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:4", 0);
+
+ /* FIXME: Inconsistency! For the non-vroot case we also receive two
+ * row-has-child-toggled signals here.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
+ /* Once 0:4:0 got inserted, 0:4 became a parent */
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
+ set_path_visibility (fixture, "2:0:4:2", TRUE);
+ set_path_visibility (fixture, "2:0:4:4", TRUE);
+ check_level_length (fixture->filter, "0:4", 2);
+}
+
+
+static void
+empty_show_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 0);
+
+ set_path_visibility (fixture, "3:2:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
+ set_path_visibility (fixture, "3:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+ check_level_length (fixture->filter, "0:0:0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "3", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3:2:1", TRUE);
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 2);
+ check_level_length (fixture->filter, "0:0:0", 0);
+}
+
+static void
+empty_show_multiple_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter;
+ GtkTreePath *changed_path;
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ /* We simulate a change in visible func condition with this. The
+ * visibility state of multiple nodes changes at once, we emit row-changed
+ * for these nodes (and others) after that.
+ */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "3", TRUE);
+ set_path_visibility (fixture, "4", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (changed_path, 2);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, changed_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 0);
+
+ set_path_visibility (fixture, "3:2:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
+ set_path_visibility (fixture, "3:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+ check_level_length (fixture->filter, "0:0:0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "3", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3:2:1", TRUE);
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 2);
+ check_level_length (fixture->filter, "0:0:0", 0);
+}
+
+static void
+empty_vroot_show_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2:2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 0);
+
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "2:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2:1", TRUE);
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 2);
+ check_level_length (fixture->filter, "0:1", 0);
+}
+
+static void
+empty_vroot_show_multiple_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter;
+ GtkTreePath *changed_path;
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* We simulate a change in visible func condition with this. The
+ * visibility state of multiple nodes changes at once, we emit row-changed
+ * for these nodes (and others) after that.
+ */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "2", TRUE);
+ set_path_visibility (fixture, "3", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (changed_path, 1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, changed_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2:2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ /* Again, we simulate a call to refilter */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "2:2", TRUE);
+ set_path_visibility (fixture, "2:3", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (changed_path, 2);
+ gtk_tree_path_append_index (changed_path, 1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, changed_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 0);
+
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "2:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2:1", TRUE);
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 2);
+ check_level_length (fixture->filter, "0:1", 0);
+}
+
+
+static void
+unfiltered_hide_single (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 2);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_hide_single_child (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 2);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_hide_single_multi_level (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 2);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
+}
+
+
+static void
+unfiltered_vroot_hide_single (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached. (We add an additional level to
+ * take the virtual root into account).
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_vroot_hide_single_child (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached. (We add an additional level to take
+ * the virtual root into account).
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_vroot_hide_single_multi_level (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2:2:2", FALSE);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
+}
+
+
+
+static void
+unfiltered_show_single (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 2);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+}
+
+static void
+unfiltered_show_single_child (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 3);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+}
+
+static void
+unfiltered_show_single_multi_level (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ /* The view is not showing this row (collapsed state), so it is not
+ * referenced. The signal should not go through.
+ */
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals (fixture, 3);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+}
+
+
+static void
+unfiltered_vroot_show_single (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+}
+
+static void
+unfiltered_vroot_show_single_child (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+}
+
+static void
+unfiltered_vroot_show_single_multi_level (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ /* The view is not showing this row (collapsed state), so it is not
+ * referenced. The signal should not go through.
+ */
+ set_path_visibility (fixture, "2:2:2:2", TRUE);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so the filter model only has
+ * the first two levels cached.
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+}
+
+
+static gboolean
+specific_path_dependent_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, iter);
+ if (gtk_tree_path_get_indices (path)[0] < 4)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+specific_path_dependent_filter (void)
+{
+ int i;
+ GtkTreeIter iter;
+ GtkListStore *list;
+ GtkTreeModel *sort;
+ GtkTreeModel *filter;
+
+ list = gtk_list_store_new (1, G_TYPE_INT);
+ gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
+ gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
+ gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
+ gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
+ gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
+ gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
+ gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
+ gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_path_dependent_filter_func,
+ NULL, NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
+ GTK_SORT_DESCENDING);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
+ NULL, 1))
+ gtk_list_store_remove (list, &iter);
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
+ NULL, 2))
+ gtk_list_store_remove (list, &iter);
+ }
+}
+
+
+static gboolean
+specific_append_after_collapse_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gint number;
+ gboolean hide_negative_numbers;
+
+ gtk_tree_model_get (model, iter, 1, &number, -1);
+ hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
+
+ return (number >= 0 || !hide_negative_numbers);
+}
+
+static void
+specific_append_after_collapse (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ *
+ * General idea:
+ * - Construct tree.
+ * - Show tree, expand, collapse.
+ * - Add a row.
+ */
+
+ GtkTreeIter iter;
+ GtkTreeIter child_iter;
+ GtkTreeIter child_iter2;
+ GtkTreePath *append_path;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkTreeModel *sort;
+
+ GtkWidget *window;
+ GtkWidget *tree_view;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
+ GINT_TO_POINTER (FALSE));
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_append_after_collapse_visible_func,
+ filter, NULL);
+
+ sort = gtk_tree_model_sort_new_with_model (filter);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ tree_view = gtk_tree_view_new_with_model (sort);
+ gtk_container_add (GTK_CONTAINER (window), tree_view);
+ gtk_widget_realize (tree_view);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ gtk_tree_store_prepend (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ 0, "hallo", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "toemaar", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter2, &child_iter);
+ gtk_tree_store_set (store, &child_iter2,
+ 0, "very deep", 1, 1, -1);
+
+ append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "sja", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "some word", 1, -1, -1);
+
+ /* Expand and collapse the tree */
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Add another it */
+ g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
+ GINT_TO_POINTER (TRUE));
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
+ {
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "new new new !!", 1, 1, -1);
+ }
+ gtk_tree_path_free (append_path);
+
+ /* Expand */
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+
+static gint
+specific_sort_filter_remove_node_compare_func (GtkTreeModel *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2,
+ gpointer data)
+{
+ return -1;
+}
+
+static gboolean
+specific_sort_filter_remove_node_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ char *item = NULL;
+
+ /* Do reference the model */
+ gtk_tree_model_get (model, iter, 0, &item, -1);
+ g_free (item);
+
+ return FALSE;
+}
+
+static void
+specific_sort_filter_remove_node (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ *
+ * General idea:
+ * - Create tree store, sort, filter models. The sort model has
+ * a default sort func that is enabled, filter model a visible func
+ * that defaults to returning FALSE.
+ * - Remove a node from the tree store.
+ */
+
+ GtkTreeIter iter;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkTreeModel *sort;
+
+ GtkWidget *window;
+ GtkWidget *tree_view;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
+ specific_sort_filter_remove_node_compare_func, NULL, NULL);
+
+ filter = gtk_tree_model_filter_new (sort, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_sort_filter_remove_node_visible_func,
+ filter, NULL);
+
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ tree_view = gtk_tree_view_new_with_model (filter);
+ gtk_container_add (GTK_CONTAINER (window), tree_view);
+ gtk_widget_realize (tree_view);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Remove a node */
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ gtk_tree_store_remove (store, &iter);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+
+static void
+specific_sort_filter_remove_root (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ */
+
+ GtkTreeModel *model, *sort, *filter;
+ GtkTreeIter root, mid, leaf;
+ GtkTreePath *path;
+
+ model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
+ gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
+
+ path = gtk_tree_model_get_path (model, &mid);
+
+ sort = gtk_tree_model_sort_new_with_model (model);
+ filter = gtk_tree_model_filter_new (sort, path);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
+
+ g_object_unref (filter);
+ g_object_unref (sort);
+ g_object_unref (model);
+}
+
+
+static void
+specific_root_mixed_visibility (void)
+{
+ int i;
+ GtkTreeModel *filter;
+ /* A bit nasty, apologies */
+ FilterTest fixture;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ GtkTreeIter iter;
+
+ gtk_tree_store_insert (fixture.store, &iter, NULL, i);
+ if (i % 2 == 0)
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ else
+ create_tree_store_set_values (fixture.store, &iter, FALSE);
+ }
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = NULL;
+
+ gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
+
+ /* In order to trigger the potential bug, we should not access
+ * the filter model here (so don't call the check functions).
+ */
+
+ /* Change visibility of an odd row to TRUE */
+ set_path_visibility (&fixture, "3", TRUE);
+ check_filter_model (&fixture);
+ check_level_length (fixture.filter, NULL, 4);
+}
+
+
+
+static gboolean
+specific_has_child_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ return gtk_tree_model_iter_has_child (model, iter);
+}
+
+static void
+specific_has_child_filter (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeIter iter, root;
+ /* A bit nasty, apologies */
+ FilterTest fixture;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = NULL;
+
+ /* We will filter on parent state using a filter function. We will
+ * manually keep the boolean column in sync, so that we can use
+ * check_filter_model() to check the consistency of the model.
+ */
+ /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
+ * to be able to check the structure here. We keep the calls to
+ * check_filter_model() commented out until then.
+ */
+ gtk_tree_model_filter_set_visible_func (fixture.filter,
+ specific_has_child_filter_filter_func,
+ NULL, NULL);
+
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ create_tree_store_set_values (fixture.store, &root, FALSE);
+
+ /* check_filter_model (&fixture); */
+ check_level_length (fixture.filter, NULL, 0);
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* Parent must now be visible. Do the level length check first,
+ * to avoid modifying the child model triggering a row-changed to
+ * the filter model.
+ */
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+
+ set_path_visibility (&fixture, "0", TRUE);
+ /* check_filter_model (&fixture); */
+
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ check_level_length (fixture.filter, NULL, 1);
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "1", 0);
+
+ create_tree_store_set_values (fixture.store, &root, TRUE);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* check_filter_model (&fixture); */
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "0", 0);
+ check_level_length (fixture.filter, "1", 0);
+
+ /* Now remove one of the remaining child rows */
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
+ &iter, "0:0");
+ gtk_tree_store_remove (fixture.store, &iter);
+
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+
+ set_path_visibility (&fixture, "0", FALSE);
+ /* check_filter_model (&fixture); */
+}
+
+
+static gboolean
+specific_root_has_child_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int depth;
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, iter);
+ depth = gtk_tree_path_get_depth (path);
+ gtk_tree_path_free (path);
+
+ if (depth > 1)
+ return TRUE;
+ /* else */
+ return gtk_tree_model_iter_has_child (model, iter);
+}
+
+static void
+specific_root_has_child_filter (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeIter iter, root;
+ /* A bit nasty, apologies */
+ FilterTest fixture;
+
+ /* This is a variation on the above test case wherein the has-child
+ * check for visibility only applies to root level nodes.
+ */
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = NULL;
+
+ /* We will filter on parent state using a filter function. We will
+ * manually keep the boolean column in sync, so that we can use
+ * check_filter_model() to check the consistency of the model.
+ */
+ /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
+ * to be able to check the structure here. We keep the calls to
+ * check_filter_model() commented out until then.
+ */
+ gtk_tree_model_filter_set_visible_func (fixture.filter,
+ specific_root_has_child_filter_filter_func,
+ NULL, NULL);
+
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ create_tree_store_set_values (fixture.store, &root, FALSE);
+
+ /* check_filter_model (&fixture); */
+ check_level_length (fixture.filter, NULL, 0);
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* Parent must now be visible. Do the level length check first,
+ * to avoid modifying the child model triggering a row-changed to
+ * the filter model.
+ */
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 1);
+
+ set_path_visibility (&fixture, "0", TRUE);
+ /* check_filter_model (&fixture); */
+
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ check_level_length (fixture.filter, NULL, 1);
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "1", 1);
+
+ create_tree_store_set_values (fixture.store, &root, TRUE);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* check_filter_model (&fixture); */
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "0", 1);
+ check_level_length (fixture.filter, "1", 2);
+
+ /* Now remove one of the remaining child rows */
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
+ &iter, "0:0");
+ gtk_tree_store_remove (fixture.store, &iter);
+
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 2);
+
+ set_path_visibility (&fixture, "0", FALSE);
+ /* check_filter_model (&fixture); */
+}
+
+
+static void
+specific_filter_add_child (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ */
+
+ GtkTreeIter iter;
+ GtkTreeIter iter_first;
+ GtkTreeIter child;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+ gtk_tree_store_append (store, &iter_first, NULL);
+ gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello", -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello", -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello", -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+
+ gtk_tree_store_set (store, &iter, 0, "Hello", -1);
+ gtk_tree_store_append (store, &child, &iter_first);
+ gtk_tree_store_set (store, &child, 0, "Hello", -1);
+}
+
+static void
+specific_list_store_clear (void)
+{
+ GtkTreeIter iter;
+ GtkListStore *list;
+ GtkTreeModel *filter;
+ GtkWidget *view;
+
+ list = gtk_list_store_new (1, G_TYPE_INT);
+ gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
+ gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
+ gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
+ gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
+ gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
+ gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
+ gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
+ gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
+ view = gtk_tree_view_new_with_model (filter);
+
+ gtk_list_store_clear (list);
+}
+
+static void
+specific_bug_300089 (void)
+{
+ /* Test case for GNOME Bugzilla bug 300089. Written by
+ * Matthias Clasen.
+ */
+ GtkTreeModel *sort_model, *child_model;
+ GtkTreePath *path;
+ GtkTreeIter iter, iter2, sort_iter;
+
+ child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
+
+
+ sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+
+ path = gtk_tree_path_new_from_indices (1, 1, -1);
+
+ /* make sure a level is constructed */
+ gtk_tree_model_get_iter (sort_model, &sort_iter, path);
+
+ /* change the "E" row in a way that causes it to change position */
+ gtk_tree_model_get_iter (child_model, &iter, path);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
+}
+
+
+static int
+specific_bug_301558_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer data)
+{
+ int i, j;
+
+ gtk_tree_model_get (model, a, 0, &i, -1);
+ gtk_tree_model_get (model, b, 0, &j, -1);
+
+ return j - i;
+}
+
+static void
+specific_bug_301558 (void)
+{
+ /* Test case for GNOME Bugzilla bug 301558 provided by
+ * Markku Vire.
+ */
+ GtkTreeStore *tree;
+ GtkTreeModel *filter;
+ GtkTreeModel *sort;
+ GtkTreeIter root, iter, iter2;
+ GtkWidget *view;
+ int i;
+ gboolean add;
+
+ tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
+ gtk_tree_store_append (tree, &iter, NULL);
+ gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
+ gtk_tree_store_append (tree, &iter2, &iter);
+ gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
+ specific_bug_301558_sort_func,
+ NULL, NULL);
+
+ filter = gtk_tree_model_filter_new (sort, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
+
+ view = gtk_tree_view_new_with_model (filter);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ add = TRUE;
+
+ for (i = 0; i < 10; i++)
+ {
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
+ g_assert_not_reached ();
+
+ if (add)
+ {
+ gtk_tree_store_append (tree, &iter, &root);
+ gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
+ }
+ else
+ {
+ int n;
+ n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
+ gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
+ &root, n - 1);
+ gtk_tree_store_remove (tree, &iter);
+ }
+
+ add = !add;
+ }
+}
+
+
+static gboolean
+specific_bug_311955_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int value;
+
+ gtk_tree_model_get (model, iter, 0, &value, -1);
+
+ return (value != 0);
+}
+
+static void
+specific_bug_311955 (void)
+{
+ /* This is a test case for GNOME Bugzilla bug 311955. It was written
+ * by Markku Vire.
+ */
+ GtkTreeIter iter, child, root;
+ GtkTreeStore *store;
+ GtkTreeModel *sort;
+ GtkTreeModel *filter;
+
+ GtkWidget *window;
+ GtkWidget *tree_view;
+ int i;
+ int n;
+
+ store = gtk_tree_store_new (1, G_TYPE_INT);
+
+ gtk_tree_store_append (store, &root, NULL);
+ gtk_tree_store_set (store, &root, 0, 33, -1);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 50, -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, 22, -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ filter = gtk_tree_model_filter_new (sort, NULL);
+
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_311955_filter_func,
+ NULL, NULL);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ tree_view = gtk_tree_view_new_with_model (filter);
+ g_object_unref (store);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Fill model */
+ for (i = 0; i < 4; i++)
+ {
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
+
+ gtk_tree_store_append (store, &iter, &root);
+
+ if (i < 3)
+ gtk_tree_store_set (store, &iter, 0, i, -1);
+
+ if (i % 2 == 0)
+ {
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 10, -1);
+ }
+ }
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Remove bottommost child from the tree. */
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
+ n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
+ {
+ if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
+ gtk_tree_store_remove (store, &child);
+ }
+ else
+ g_assert_not_reached ();
+}
+
+static void
+specific_bug_346800 (void)
+{
+ /* This is a test case for GNOME Bugzilla bug 346800. It was written
+ * by Jonathan Matthew.
+ */
+
+ GtkTreeIter node_iters[50];
+ GtkTreeIter child_iters[50];
+ GtkTreeModel *model;
+ GtkTreeModelFilter *filter;
+ GtkTreeStore *store;
+ GType *columns;
+ int i;
+ int items = 50;
+ columns = g_new (GType, 2);
+ columns[0] = G_TYPE_STRING;
+ columns[1] = G_TYPE_BOOLEAN;
+ store = gtk_tree_store_newv (2, columns);
+ model = GTK_TREE_MODEL (store);
+
+ filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
+ gtk_tree_model_filter_set_visible_column (filter, 1);
+
+ for (i=0; i<items; i++)
+ {
+ /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
+
+ g_malloc (138);
+ gtk_tree_store_append (store, &node_iters[i], NULL);
+ gtk_tree_store_set (store, &node_iters[i],
+ 0, "something",
+ 1, ((i%6) == 0) ? FALSE : TRUE,
+ -1);
+
+ g_malloc (47);
+ gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
+ gtk_tree_store_set (store, &child_iters[i],
+ 0, "something else",
+ 1, FALSE,
+ -1);
+ gtk_tree_model_filter_refilter (filter);
+
+ if (i > 6)
+ {
+ gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
+ (i & 1) ? TRUE : FALSE, -1);
+ gtk_tree_model_filter_refilter (filter);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
+ (i & 1) ? FALSE: TRUE, -1);
+ gtk_tree_model_filter_refilter (filter);
+ }
+ }
+}
+
+
+static void
+specific_bug_364946 (void)
+{
+ /* This is a test case for GNOME Bugzilla bug 364946. It was written
+ * by Andreas Koehler.
+ */
+ GtkTreeStore *store;
+ GtkTreeIter a, aa, aaa, aab, iter;
+ GtkTreeModel *s_model;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+ gtk_tree_store_append (store, &a, NULL);
+ gtk_tree_store_set (store, &a, 0, "0", -1);
+
+ gtk_tree_store_append (store, &aa, &a);
+ gtk_tree_store_set (store, &aa, 0, "0:0", -1);
+
+ gtk_tree_store_append (store, &aaa, &aa);
+ gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
+
+ gtk_tree_store_append (store, &aab, &aa);
+ gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
+
+ s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
+
+ gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
+ gtk_tree_store_remove (store, &aaa);
+ gtk_tree_store_remove (store, &aab);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
+}
+
+
+static gboolean
+specific_bug_464173_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean *visible = (gboolean *)data;
+
+ return *visible;
+}
+
+static void
+specific_bug_464173 (void)
+{
+ /* Test case for GNOME Bugzilla bug 464173, test case written
+ * by Andreas Koehler.
+ */
+ GtkTreeStore *model;
+ GtkTreeModelFilter *f_model;
+ GtkTreeIter iter1, iter2;
+ GtkWidget *view;
+ gboolean visible = TRUE;
+
+ model = gtk_tree_store_new (1, G_TYPE_STRING);
+ gtk_tree_store_append (model, &iter1, NULL);
+ gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
+ gtk_tree_store_append (model, &iter2, &iter1);
+ gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
+
+ f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
+ gtk_tree_model_filter_set_visible_func (f_model,
+ specific_bug_464173_visible_func,
+ &visible, NULL);
+
+ view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
+
+ visible = FALSE;
+ gtk_tree_model_filter_refilter (f_model);
+}
+
+
+static gboolean
+specific_bug_540201_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean has_children;
+
+ has_children = gtk_tree_model_iter_has_child (model, iter);
+
+ return has_children;
+}
+
+static void
+specific_bug_540201 (void)
+{
+ /* Test case for GNOME Bugzilla bug 540201, steps provided by
+ * Charles Day.
+ */
+ GtkTreeIter iter, root;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+
+ GtkWidget *tree_view;
+
+ store = gtk_tree_store_new (1, G_TYPE_INT);
+
+ gtk_tree_store_append (store, &root, NULL);
+ gtk_tree_store_set (store, &root, 0, 33, -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ tree_view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_540201_filter_func,
+ NULL, NULL);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 50, -1);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 22, -1);
+
+
+ gtk_tree_store_append (store, &root, NULL);
+ gtk_tree_store_set (store, &root, 0, 33, -1);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 22, -1);
+}
+
+
+static gboolean
+specific_bug_549287_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean result = FALSE;
+
+ result = gtk_tree_model_iter_has_child (model, iter);
+
+ return result;
+}
+
+static void
+specific_bug_549287 (void)
+{
+ /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
+
+ int i;
+ GtkTreeStore *store;
+ GtkTreeModel *filtered;
+ GtkWidget *view;
+ GtkTreeIter iter;
+ GtkTreeIter *swap, *parent, *child;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+ filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
+ specific_bug_549287_visible_func,
+ NULL, NULL);
+
+ view = gtk_tree_view_new_with_model (filtered);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
+ {
+ parent = gtk_tree_iter_copy (&iter);
+ child = gtk_tree_iter_copy (&iter);
+
+ while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
+ child, parent, 0))
+ {
+
+ swap = parent;
+ parent = child;
+ child = swap;
+ }
+
+ gtk_tree_store_append (store, child, parent);
+ gtk_tree_store_set (store, child,
+ 0, "Something",
+ -1);
+
+ gtk_tree_iter_free (parent);
+ gtk_tree_iter_free (child);
+ }
+ else
+ {
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ 0, "Something",
+ -1);
+ }
+
+ /* since we inserted something, we changed the visibility conditions: */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
+ }
+}
+
+/* main */
+
+int
+main (int argc,
+ char **argv)
+{
+ gtk_test_init (&argc, &argv, NULL);
+
+ g_test_add ("/FilterModel/self/verify-test-suite",
+ FilterTest, NULL,
+ filter_test_setup,
+ verify_test_suite,
+ filter_test_teardown);
+
+ g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-1",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup,
+ verify_test_suite_vroot,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-2",
+ FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
+ filter_test_setup,
+ verify_test_suite_vroot,
+ filter_test_teardown);
+
+
+ g_test_add ("/FilterModel/filled/hide-root-level",
+ FilterTest, NULL,
+ filter_test_setup,
+ filled_hide_root_level,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/filled/hide-child-levels",
+ FilterTest, NULL,
+ filter_test_setup,
+ filled_hide_child_levels,
+ filter_test_teardown);
+
+ g_test_add ("/FilterModel/filled/hide-root-level/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup,
+ filled_vroot_hide_root_level,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/filled/hide-child-levels/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup,
+ filled_vroot_hide_child_levels,
+ filter_test_teardown);
+
+
+ g_test_add ("/FilterModel/empty/show-nodes",
+ FilterTest, NULL,
+ filter_test_setup_empty,
+ empty_show_nodes,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/empty/show-multiple-nodes",
+ FilterTest, NULL,
+ filter_test_setup_empty,
+ empty_show_multiple_nodes,
+ filter_test_teardown);
+
+ g_test_add ("/FilterModel/empty/show-nodes/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty,
+ empty_vroot_show_nodes,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/empty/show-multiple-nodes/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty,
+ empty_vroot_show_multiple_nodes,
+ filter_test_teardown);
+
+
+ g_test_add ("/FilterModel/unfiltered/hide-single",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered,
+ unfiltered_hide_single,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/hide-single-child",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered,
+ unfiltered_hide_single_child,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/hide-single-multi-level",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered,
+ unfiltered_hide_single_multi_level,
+ filter_test_teardown);
+
+ g_test_add ("/FilterModel/unfiltered/hide-single/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_unfiltered,
+ unfiltered_vroot_hide_single,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/hide-single-child/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_unfiltered,
+ unfiltered_vroot_hide_single_child,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/hide-single-multi-level/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_unfiltered,
+ unfiltered_vroot_hide_single_multi_level,
+ filter_test_teardown);
+
+
+
+ g_test_add ("/FilterModel/unfiltered/show-single",
+ FilterTest, NULL,
+ filter_test_setup_empty_unfiltered,
+ unfiltered_show_single,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/show-single-child",
+ FilterTest, NULL,
+ filter_test_setup_empty_unfiltered,
+ unfiltered_show_single_child,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/show-single-multi-level",
+ FilterTest, NULL,
+ filter_test_setup_empty_unfiltered,
+ unfiltered_show_single_multi_level,
+ filter_test_teardown);
+
+ g_test_add ("/FilterModel/unfiltered/show-single/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty_unfiltered,
+ unfiltered_vroot_show_single,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/show-single-child/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty_unfiltered,
+ unfiltered_vroot_show_single_child,
+ filter_test_teardown);
+ g_test_add ("/FilterModel/unfiltered/show-single-multi-level/vroot",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty_unfiltered,
+ unfiltered_vroot_show_single_multi_level,
+ filter_test_teardown);
+
+
+ g_test_add_func ("/FilterModel/specific/path-dependent-filter",
+ specific_path_dependent_filter);
+ g_test_add_func ("/FilterModel/specific/append-after-collapse",
+ specific_append_after_collapse);
+ g_test_add_func ("/FilterModel/specific/sort-filter-remove-node",
+ specific_sort_filter_remove_node);
+ g_test_add_func ("/FilterModel/specific/sort-filter-remove-root",
+ specific_sort_filter_remove_root);
+ g_test_add_func ("/FilterModel/specific/root-mixed-visibility",
+ specific_root_mixed_visibility);
+ g_test_add_func ("/FilterModel/specific/has-child-filter",
+ specific_has_child_filter);
+ g_test_add_func ("/FilterModel/specific/root-has-child-filter",
+ specific_root_has_child_filter);
+ g_test_add_func ("/FilterModel/specific/filter-add-child",
+ specific_filter_add_child);
+ g_test_add_func ("/FilterModel/specific/list-store-clear",
+ specific_list_store_clear);
+
+ g_test_add_func ("/FilterModel/specific/bug-300089",
+ specific_bug_300089);
+ g_test_add_func ("/FilterModel/specific/bug-301558",
+ specific_bug_301558);
+ g_test_add_func ("/FilterModel/specific/bug-311955",
+ specific_bug_311955);
+ g_test_add_func ("/FilterModel/specific/bug-346800",
+ specific_bug_346800);
+ g_test_add_func ("/FilterModel/specific/bug-364946",
+ specific_bug_364946);
+ g_test_add_func ("/FilterModel/specific/bug-464173",
+ specific_bug_464173);
+ g_test_add_func ("/FilterModel/specific/bug-540201",
+ specific_bug_540201);
+ g_test_add_func ("/FilterModel/specific/bug-549287",
+ specific_bug_549287);
+
+ return g_test_run ();
+}
diff --git a/gtk/tests/liststore.c b/gtk/tests/liststore.c
index 588f725f3d..6452fc2903 100644
--- a/gtk/tests/liststore.c
+++ b/gtk/tests/liststore.c
@@ -850,6 +850,72 @@ list_store_test_move_before_single (void)
g_object_unref (store);
}
+
+/* iter invalidation */
+
+static void
+list_store_test_iter_next_invalid (ListStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_indices (4, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path);
+ gtk_tree_path_free (path);
+
+ g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store),
+ &iter) == FALSE);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE);
+ g_assert (iter.stamp == 0);
+}
+
+static void
+list_store_test_iter_children_invalid (ListStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE);
+
+ g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store),
+ &child, &iter) == FALSE);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE);
+ g_assert (child.stamp == 0);
+}
+
+static void
+list_store_test_iter_nth_child_invalid (ListStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE);
+
+ g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store),
+ &child, &iter, 0) == FALSE);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE);
+ g_assert (child.stamp == 0);
+}
+
+static void
+list_store_test_iter_parent_invalid (ListStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == TRUE);
+
+ g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store),
+ &iter, &child) == FALSE);
+ g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE);
+ g_assert (iter.stamp == 0);
+}
+
+
/* main */
int
@@ -958,5 +1024,19 @@ main (int argc,
g_test_add_func ("/list-store/move-before-single",
list_store_test_move_before_single);
+ /* iter invalidation */
+ g_test_add ("/list-store/iter-next-invalid", ListStore, NULL,
+ list_store_setup, list_store_test_iter_next_invalid,
+ list_store_teardown);
+ g_test_add ("/list-store/iter-children-invalid", ListStore, NULL,
+ list_store_setup, list_store_test_iter_children_invalid,
+ list_store_teardown);
+ g_test_add ("/list-store/iter-nth-child-invalid", ListStore, NULL,
+ list_store_setup, list_store_test_iter_nth_child_invalid,
+ list_store_teardown);
+ g_test_add ("/list-store/iter-parent-invalid", ListStore, NULL,
+ list_store_setup, list_store_test_iter_parent_invalid,
+ list_store_teardown);
+
return g_test_run ();
}
diff --git a/gtk/tests/textbuffer.c b/gtk/tests/textbuffer.c
index 822b04c752..010776d478 100644
--- a/gtk/tests/textbuffer.c
+++ b/gtk/tests/textbuffer.c
@@ -879,6 +879,8 @@ split_r_n_separators_test (void)
gtk_text_buffer_get_iter_at_offset (buffer, &iter, 3);
g_assert (gtk_text_iter_ends_line (&iter));
+
+ g_object_unref (buffer);
}
static void
@@ -913,6 +915,40 @@ test_line_separator (void)
}
static void
+test_backspace (void)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ gboolean ret;
+
+ buffer = gtk_text_buffer_new (NULL);
+
+ gtk_text_buffer_set_text (buffer, "foo", -1);
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, 2);
+ ret = gtk_text_buffer_backspace (buffer, &iter, TRUE, TRUE);
+ g_assert (ret);
+ g_assert_cmpint (1, ==, gtk_text_iter_get_offset (&iter));
+ g_assert_cmpint (2, ==, gtk_text_buffer_get_char_count (buffer));
+
+ gtk_text_buffer_set_text (buffer, "foo", -1);
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+ ret = gtk_text_buffer_backspace (buffer, &iter, TRUE, TRUE);
+ g_assert (!ret);
+ g_assert_cmpint (0, ==, gtk_text_iter_get_offset (&iter));
+ g_assert_cmpint (3, ==, gtk_text_buffer_get_char_count (buffer));
+
+ /* test bug #544724 */
+ gtk_text_buffer_set_text (buffer, "foo\r\n\r\nbar", -1);
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, 5);
+ ret = gtk_text_buffer_backspace (buffer, &iter, TRUE, TRUE);
+ g_assert (ret);
+ g_assert_cmpint (0, ==, gtk_text_iter_get_line (&iter));
+ g_assert_cmpint (8, ==, gtk_text_buffer_get_char_count (buffer));
+
+ g_object_unref (buffer);
+}
+
+static void
test_logical_motion (void)
{
char *str;
@@ -1297,6 +1333,7 @@ main (int argc, char** argv)
g_test_add_func ("/TextBuffer/UTF8 unknown char", test_utf8);
g_test_add_func ("/TextBuffer/Line separator", test_line_separator);
+ g_test_add_func ("/TextBuffer/Backspace", test_backspace);
g_test_add_func ("/TextBuffer/Logical motion", test_logical_motion);
g_test_add_func ("/TextBuffer/Marks", test_marks);
g_test_add_func ("/TextBuffer/Empty buffer", test_empty_buffer);
diff --git a/gtk/tests/treestore.c b/gtk/tests/treestore.c
index e3a85c92fe..c9dbcffba8 100644
--- a/gtk/tests/treestore.c
+++ b/gtk/tests/treestore.c
@@ -853,6 +853,72 @@ tree_store_test_move_before_single (void)
g_object_unref (store);
}
+
+/* iter invalidation */
+
+static void
+tree_store_test_iter_next_invalid (TreeStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = gtk_tree_path_new_from_indices (4, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path);
+ gtk_tree_path_free (path);
+
+ g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store),
+ &iter) == FALSE);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE);
+ g_assert (iter.stamp == 0);
+}
+
+static void
+tree_store_test_iter_children_invalid (TreeStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE);
+
+ g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store),
+ &child, &iter) == FALSE);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE);
+ g_assert (child.stamp == 0);
+}
+
+static void
+tree_store_test_iter_nth_child_invalid (TreeStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE);
+
+ g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store),
+ &child, &iter, 0) == FALSE);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE);
+ g_assert (child.stamp == 0);
+}
+
+static void
+tree_store_test_iter_parent_invalid (TreeStore *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter, child;
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == TRUE);
+
+ g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store),
+ &iter, &child) == FALSE);
+ g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE);
+ g_assert (iter.stamp == 0);
+}
+
+
/* main */
int
@@ -961,5 +1027,19 @@ main (int argc,
g_test_add_func ("/tree-store/move-before-single",
tree_store_test_move_before_single);
+ /* iter invalidation */
+ g_test_add ("/tree-store/iter-next-invalid", TreeStore, NULL,
+ tree_store_setup, tree_store_test_iter_next_invalid,
+ tree_store_teardown);
+ g_test_add ("/tree-store/iter-children-invalid", TreeStore, NULL,
+ tree_store_setup, tree_store_test_iter_children_invalid,
+ tree_store_teardown);
+ g_test_add ("/tree-store/iter-nth-child-invalid", TreeStore, NULL,
+ tree_store_setup, tree_store_test_iter_nth_child_invalid,
+ tree_store_teardown);
+ g_test_add ("/tree-store/iter-parent-invalid", TreeStore, NULL,
+ tree_store_setup, tree_store_test_iter_parent_invalid,
+ tree_store_teardown);
+
return g_test_run ();
}
diff --git a/gtk/tests/treeview-scrolling.c b/gtk/tests/treeview-scrolling.c
index 0207dbcff2..81dfd8d752 100644
--- a/gtk/tests/treeview-scrolling.c
+++ b/gtk/tests/treeview-scrolling.c
@@ -1,6 +1,7 @@
/* Scrolling test suite for GtkTreeView
* Copyright (C) 2006 Kristian Rietveld <kris@gtk.org>
* Copyright (C) 2007 Imendio AB, Kristian Rietveld
+ * Copyright (C) 2009 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -37,6 +38,8 @@
* - Test that nothing happens if the row is fully visible.
* - The tests are dependent on the theme/font (size measurements,
* chosen paths).
+ * - Convert to proper GTK+ coding style.
+ * - Briefly test scrolling in tree stores as well.
*/
@@ -175,6 +178,34 @@ scroll_fixture_single_setup (ScrollFixture *fixture,
scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
}
+/* sets up a fixture with a tree store */
+static void
+scroll_fixture_tree_setup (ScrollFixture *fixture,
+ gconstpointer test_data)
+{
+ GtkTreeStore *store;
+ GtkTreeIter iter, child;
+ int i;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Root node", -1);
+
+ for (i = 0; i < 5; i++) {
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, "Child node", -1);
+ }
+
+ for (i = 0; i < 5; i++) {
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Other node", -1);
+ }
+
+ /* The teardown will also destroy the model */
+ scroll_fixture_setup (fixture, GTK_TREE_MODEL (store), test_data);
+}
+
static void
scroll_fixture_teardown (ScrollFixture *fixture,
gconstpointer test_data)
@@ -752,6 +783,56 @@ scroll_new_row (ScrollFixture *fixture,
gtk_tree_path_free (scroll_path);
}
+static void
+scroll_new_row_tree (ScrollFixture *fixture,
+ gconstpointer test_data)
+{
+ GtkTreeModel *model;
+ GtkAdjustment *vadjustment;
+ int i;
+
+ /* The goal of this test is to append new rows at the end of a tree
+ * store and immediately scroll to them. If there is a parent
+ * node with a couple of childs in the "area above" to explore,
+ * this used to lead to unexpected results due to a bug.
+ *
+ * This issue has been reported by Miroslav Rajcic on
+ * gtk-app-devel-list:
+ * http://mail.gnome.org/archives/gtk-app-devel-list/2008-December/msg00068.html
+ */
+
+ gtk_widget_show_all (fixture->window);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (fixture->tree_view));
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (fixture->tree_view));
+ vadjustment = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (fixture->tree_view));
+
+ for (i = 0; i < 5; i++) {
+ GtkTreeIter scroll_iter;
+ GtkTreePath *scroll_path;
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &scroll_iter,
+ NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &scroll_iter,
+ 0, "New node", -1);
+
+ scroll_path = gtk_tree_model_get_path (model, &scroll_iter);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (fixture->tree_view),
+ scroll_path, NULL, FALSE, 0.0, 0.0);
+ gtk_tree_path_free (scroll_path);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Test position, the scroll bar must be at the end */
+ g_assert (vadjustment->value == vadjustment->upper - vadjustment->page_size);
+ }
+}
+
/* Test for GNOME bugzilla bug 359231; tests "recovery when removing a bunch of
* rows at the bottom.
*/
@@ -874,10 +955,10 @@ test_type_string (int test_type)
{
switch (test_type) {
case BEFORE:
- return "before";
+ return "before-realize";
case AFTER:
- return "after";
+ return "after-realize";
case BOTH:
return "both";
@@ -913,7 +994,7 @@ add_test (const char *path,
align = align_string (use_align, row_align);
- test_path = g_strdup_printf ("/treeview/scrolling/%s-%s-path-%s-%s",
+ test_path = g_strdup_printf ("/TreeView/scrolling/%s/%s-height/path-%s-%s",
test_type_string (test_type),
mixed ? "mixed" : "constant",
path, align);
@@ -1013,42 +1094,46 @@ main (int argc, char **argv)
}
/* Test different alignments in view with single row */
- g_test_add ("/treeview/scrolling/single-no-align", ScrollFixture, "0",
+ g_test_add ("/TreeView/scrolling/single-row/no-align",
+ ScrollFixture, "0",
scroll_fixture_single_setup,
scroll_no_align,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/single-align-0.0", ScrollFixture, "0",
+ g_test_add ("/TreeView/scrolling/single-row/align-0.0",
+ ScrollFixture, "0",
scroll_fixture_single_setup,
scroll_align_0_0,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/single-align-0.5", ScrollFixture, "0",
+ g_test_add ("/TreeView/scrolling/single-row/align-0.5",
+ ScrollFixture, "0",
scroll_fixture_single_setup,
scroll_align_0_5,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/single-align-1.0", ScrollFixture, "0",
+ g_test_add ("/TreeView/scrolling/single-row/align-1.0",
+ ScrollFixture, "0",
scroll_fixture_single_setup,
scroll_align_1_0,
scroll_fixture_teardown);
/* Test scrolling in a very large model; also very slow */
if (g_test_slow ()) {
- g_test_add ("/treeview/scrolling/constant-big-middle-no-align",
+ g_test_add ("/TreeView/scrolling/large-model/constant-height/middle-no-align",
ScrollFixture, "50000",
scroll_fixture_constant_big_setup,
scroll_no_align,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/constant-big-end-no-align",
+ g_test_add ("/TreeView/scrolling/large-model/constant-height/end-no-align",
ScrollFixture, "99999",
scroll_fixture_constant_big_setup,
scroll_no_align,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/mixed-big-middle-no-align",
+ g_test_add ("/TreeView/scrolling/large-model/mixed-height/middle-no-align",
ScrollFixture, "50000",
scroll_fixture_mixed_big_setup,
scroll_no_align,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/mixed-big-end-no-align",
+ g_test_add ("/TreeView/scrolling/large-model/mixed-height/end-no-align",
ScrollFixture, "99999",
scroll_fixture_mixed_big_setup,
scroll_no_align,
@@ -1056,12 +1141,12 @@ main (int argc, char **argv)
}
/* Test scrolling to a newly created row */
- g_test_add ("/treeview/scrolling/new-row-path-0", ScrollFixture,
+ g_test_add ("/TreeView/scrolling/new-row/path-0", ScrollFixture,
GINT_TO_POINTER (0),
scroll_fixture_constant_setup,
scroll_new_row,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/new-row-path-4", ScrollFixture,
+ g_test_add ("/TreeView/scrolling/new-row/path-4", ScrollFixture,
GINT_TO_POINTER (4),
scroll_fixture_constant_setup,
scroll_new_row,
@@ -1070,27 +1155,35 @@ main (int argc, char **argv)
* based on my font setting of "Vera Sans 11" and
* the separators set to 0. (This should be made dynamic; FIXME).
*/
- g_test_add ("/treeview/scrolling/new-row-path-8", ScrollFixture,
+ g_test_add ("/TreeView/scrolling/new-row/path-8", ScrollFixture,
GINT_TO_POINTER (8),
scroll_fixture_constant_setup,
scroll_new_row,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/new-row-path-500", ScrollFixture,
+ g_test_add ("/TreeView/scrolling/new-row/path-500", ScrollFixture,
GINT_TO_POINTER (500),
scroll_fixture_constant_setup,
scroll_new_row,
scroll_fixture_teardown);
- g_test_add ("/treeview/scrolling/new-row-path-999", ScrollFixture,
+ g_test_add ("/TreeView/scrolling/new-row/path-999", ScrollFixture,
GINT_TO_POINTER (999),
scroll_fixture_constant_setup,
scroll_new_row,
scroll_fixture_teardown);
+ g_test_add ("/TreeView/scrolling/new-row/tree", ScrollFixture,
+ NULL,
+ scroll_fixture_tree_setup,
+ scroll_new_row_tree,
+ scroll_fixture_teardown);
+
/* Misc. tests */
- g_test_add ("/treeview/scrolling/bug-316689", ScrollFixture, NULL,
+ g_test_add ("/TreeView/scrolling/specific/bug-316689",
+ ScrollFixture, NULL,
scroll_fixture_constant_setup, test_bug316689,
scroll_fixture_teardown);
- g_test_add_func ("/treeview/scrolling/bug-359231", test_bug359231);
+ g_test_add_func ("/TreeView/scrolling/specific/bug-359231",
+ test_bug359231);
return g_test_run ();
}
diff --git a/gtk/tests/treeview.c b/gtk/tests/treeview.c
new file mode 100644
index 0000000000..3dcc44287f
--- /dev/null
+++ b/gtk/tests/treeview.c
@@ -0,0 +1,165 @@
+/* Basic GtkTreeView unit tests.
+ * Copyright (C) 2009 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+static void
+test_bug_546005 (void)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreePath *cursor_path;
+ GtkListStore *list_store;
+ GtkWidget *view;
+
+ /* Tests provided by Bjorn Lindqvist, Paul Pogonyshev */
+ view = gtk_tree_view_new ();
+
+ /* Invalid path on tree view without model */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path,
+ NULL, FALSE);
+ gtk_tree_path_free (path);
+
+ list_store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view),
+ GTK_TREE_MODEL (list_store));
+
+ /* Invalid path on tree view with empty model */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path,
+ NULL, FALSE);
+ gtk_tree_path_free (path);
+
+ /* Valid path */
+ gtk_list_store_insert_with_values (list_store, &iter, 0,
+ 0, "hi",
+ -1);
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path,
+ NULL, FALSE);
+
+ gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &cursor_path, NULL);
+ g_assert (gtk_tree_path_compare (cursor_path, path) == 0);
+
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (cursor_path);
+
+ /* Invalid path on tree view with model */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path,
+ NULL, FALSE);
+ gtk_tree_path_free (path);
+}
+
+static void
+test_bug_539377 (void)
+{
+ GtkWidget *view;
+ GtkTreePath *path;
+ GtkListStore *list_store;
+
+ /* Test provided by Bjorn Lindqvist */
+
+ /* Non-realized view, no model */
+ view = gtk_tree_view_new ();
+ g_assert (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), 10, 10, &path,
+ NULL, NULL, NULL) == FALSE);
+ g_assert (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), 10, 10,
+ &path, NULL) == FALSE);
+
+ /* Non-realized view, with model */
+ list_store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (view),
+ GTK_TREE_MODEL (list_store));
+
+ g_assert (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), 10, 10, &path,
+ NULL, NULL, NULL) == FALSE);
+ g_assert (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view), 10, 10,
+ &path, NULL) == FALSE);
+}
+
+static void
+test_select_collapsed_row (void)
+{
+ GtkTreeIter child, parent;
+ GtkTreePath *path;
+ GtkTreeStore *tree_store;
+ GtkTreeSelection *selection;
+ GtkWidget *view;
+
+ /* Reported by Michael Natterer */
+ tree_store = gtk_tree_store_new (1, G_TYPE_STRING);
+ view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store));
+
+ gtk_tree_store_insert_with_values (tree_store, &parent, NULL, 0,
+ 0, "Parent",
+ -1);
+
+ gtk_tree_store_insert_with_values (tree_store, &child, &parent, 0,
+ 0, "Child",
+ -1);
+ gtk_tree_store_insert_with_values (tree_store, &child, &parent, 0,
+ 0, "Child",
+ -1);
+
+
+ /* Try to select a child path. */
+ path = gtk_tree_path_new_from_indices (0, 1, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+
+ /* Check that the parent is not selected. */
+ gtk_tree_path_up (path);
+ g_return_if_fail (gtk_tree_selection_path_is_selected (selection, path) == FALSE);
+
+ /* Nothing should be selected at this point. */
+ g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 0);
+
+ /* Check that selection really still works. */
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
+ g_return_if_fail (gtk_tree_selection_path_is_selected (selection, path) == TRUE);
+ g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1);
+
+ /* Expand and select child node now. */
+ gtk_tree_path_append_index (path, 1);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
+ g_return_if_fail (gtk_tree_selection_path_is_selected (selection, path) == TRUE);
+ g_return_if_fail (gtk_tree_selection_count_selected_rows (selection) == 1);
+
+ gtk_tree_path_free (path);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ gtk_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/TreeView/cursor/bug-546005", test_bug_546005);
+ g_test_add_func ("/TreeView/cursor/bug-539377", test_bug_539377);
+ g_test_add_func ("/TreeView/cursor/select-collapsed_row",
+ test_select_collapsed_row);
+
+ return g_test_run ();
+}
diff --git a/gtk/updateiconcache.c b/gtk/updateiconcache.c
index 627f49eb80..3b927011cc 100644
--- a/gtk/updateiconcache.c
+++ b/gtk/updateiconcache.c
@@ -1516,9 +1516,11 @@ opentmp:
g_unlink (bak_cache_path);
if (g_rename (cache_path, bak_cache_path) == -1)
{
+ int errsv = errno;
+
g_printerr (_("Could not rename %s to %s: %s, removing %s then.\n"),
cache_path, bak_cache_path,
- g_strerror (errno),
+ g_strerror (errsv),
cache_path);
g_unlink (cache_path);
bak_cache_path = NULL;
@@ -1528,16 +1530,22 @@ opentmp:
if (g_rename (tmp_cache_path, cache_path) == -1)
{
+ int errsv = errno;
+
g_printerr (_("Could not rename %s to %s: %s\n"),
tmp_cache_path, cache_path,
- g_strerror (errno));
+ g_strerror (errsv));
g_unlink (tmp_cache_path);
#ifdef G_OS_WIN32
if (bak_cache_path != NULL)
if (g_rename (bak_cache_path, cache_path) == -1)
- g_printerr (_("Could not rename %s back to %s: %s.\n"),
- bak_cache_path, cache_path,
- g_strerror (errno));
+ {
+ errsv = errno;
+
+ g_printerr (_("Could not rename %s back to %s: %s.\n"),
+ bak_cache_path, cache_path,
+ g_strerror (errsv));
+ }
#endif
exit (1);
}
@@ -1648,8 +1656,12 @@ main (int argc, char **argv)
setlocale (LC_ALL, "");
+#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+#endif
context = g_option_context_new ("ICONPATH");
g_option_context_add_main_entries (context, args, GETTEXT_PACKAGE);