Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c85905dfcd | |||
| e2eba253cb | |||
| 09d1129f4f | |||
| affa829ac2 | |||
| da397664b4 | |||
| d3b32e9f42 | |||
| e2d92863b2 | |||
| f9e1e7bd1a | |||
| 641c068744 | |||
| 7c8cd23c5f | |||
| 6aafb81702 | |||
| 0578422612 | |||
| ad04da84c9 | |||
| 333b013f7f | |||
| b3dc517565 | |||
| 70e4dabe89 | |||
| d3443d6f2a | |||
| a508f68044 | |||
| f191b64bbc | |||
| e9efe77839 | |||
| d98c0d32f2 | |||
| dfa2dcceb8 | |||
| d441e7106b | |||
| 4cd92f979c | |||
| d1a068e5b1 | |||
| 4d90846182 | |||
| 986f721938 | |||
| 7903246355 | |||
| 0252ae2be3 | |||
| fa90e42a38 | |||
| 2d36109565 | |||
| de8258171a | |||
| 2ed6224778 | |||
| e1a0171094 | |||
| 395521f3d3 | |||
| 8c95a84ea4 | |||
| 75db19c789 | |||
| f00d2b30bb | |||
| c0c5ce2f9b | |||
| ee9f9ae05e | |||
| 387649ded4 | |||
| be12131d74 | |||
| 896ebdc9d7 | |||
| bc58bd0b83 | |||
| 8d4c87876b | |||
| cebc99ddc7 | |||
| 1b62203f18 | |||
| 06dd8c2cfd | |||
| 5da21ca4dc | |||
| 3e16ef33b0 | |||
| 2746a2d929 | |||
| e31bacf7be | |||
| 911ae64931 | |||
| 99a0b35705 | |||
| 89bf8af878 | |||
| f3744c991a | |||
| dcee15c0f1 | |||
| 2321e9de05 | |||
| 73dcda460f | |||
| 0f8bc67a98 | |||
| 379d830123 | |||
| bc8bc68b80 | |||
| 8c4df51a14 | |||
| 06d67d2384 | |||
| cc8bb5fc54 | |||
| 8fb1e33d0f | |||
| 0dc946da63 | |||
| 26a23d3e56 | |||
| 766f4bc8fe | |||
| 3d008d5929 | |||
| 0546e26434 | |||
| e6d8eedc00 | |||
| 13b37b0ba4 | |||
| 779c71b66d | |||
| 8e73d007f5 | |||
| e376d638fb | |||
| 52982a88aa | |||
| 422c1d9c0d | |||
| ccc8ad8700 | |||
| 6b0eb970d8 | |||
| 775e35865c | |||
| 49ce680d53 | |||
| 463f3d3a52 | |||
| f6347f18b0 | |||
| 2e959fe300 | |||
| 56f771ba29 | |||
| 32e96215b4 | |||
| 86f800e11d | |||
| 4d371b2b16 | |||
| 7e97c2513f | |||
| 2bf5a150e6 | |||
| 18c87faaa5 | |||
| fdeda388bf | |||
| ea2c27c640 | |||
| dfc04a590d | |||
| fe5b364675 | |||
| 9b73c55559 | |||
| 0b38a0663d | |||
| e5c0716293 | |||
| 54a3293cad | |||
| 818287a7ce | |||
| 59119cd898 | |||
| 817da34f7e | |||
| 8fa44fc3e6 | |||
| c7e94151b2 | |||
| 729ba44297 | |||
| 2a2a6879c5 | |||
| e7b773b031 | |||
| 57a225681c | |||
| ea07a92366 | |||
| 76290e8ddb | |||
| 26d83b1ab7 | |||
| 2bba856206 | |||
| bf3382a89e | |||
| 3162e25671 | |||
| 3d931b4fe2 | |||
| fc770a383a | |||
| 62c385a9dd | |||
| 7c4ad1a5c4 | |||
| ac524bb13a | |||
| 66fa9380b5 | |||
| b64eb6ca13 | |||
| 9b2d8ac362 | |||
| 2a90bc1a9b | |||
| d4b868d9bc | |||
| b54f6710a7 | |||
| 6bb7caf155 | |||
| 202348f9d0 | |||
| 1a613de2f6 | |||
| 665df37703 | |||
| acad5e4e3d | |||
| 6267c8469b | |||
| 5a2f791bdd | |||
| 286a00a1db | |||
| 11dd602b28 | |||
| 35988d659d | |||
| be3449b3ce | |||
| 2d8fddc1e9 | |||
| 644d522d19 | |||
| a8b0125da1 | |||
| acccac516e | |||
| d65214fa4e | |||
| 1d96fc8237 | |||
| 882a87ca19 | |||
| 1dbb8df95f | |||
| f6c2c2edbd | |||
| c4e4de36f6 | |||
| 67cbb2a7d3 | |||
| a979daa8ea | |||
| fb14f50ec1 | |||
| 6099fbafc1 | |||
| 6f2f828bce | |||
| 795d3122cc | |||
| 5080730728 | |||
| f75a3a0e95 | |||
| b75db7d1c6 | |||
| b03069bdf6 | |||
| 1c71e56e75 | |||
| 9332d0dcc8 | |||
| 9ad37583e6 | |||
| 69975627e9 | |||
| b74a489aba | |||
| 599b807726 | |||
| 6510ca8bdd | |||
| be20a04e04 | |||
| 92e5536335 | |||
| c2da2f7ecd | |||
| 54bfd380a8 | |||
| f01d695e6c | |||
| 619b2465c1 | |||
| cc18191a8e | |||
| 1f8e7c8aab | |||
| 671daea262 | |||
| 76533513c2 | |||
| 0d3988365b | |||
| 0966636803 | |||
| 7c3b30036e | |||
| 988901294d | |||
| 43b9fc6981 | |||
| 25f670faae | |||
| d0068a036f | |||
| fae014eb45 | |||
| f0ea0be15d | |||
| 9650236b23 | |||
| c0e2d7c62f | |||
| cc072eb7cd | |||
| 613213f597 | |||
| e25c25fcb5 | |||
| 52666d6fe5 | |||
| 56b3669411 | |||
| e3b5b76cdd | |||
| bbb28196e5 | |||
| 72d3a9042c | |||
| f2853ffa8e | |||
| fca2ba963d | |||
| 806779769e | |||
| 82aa0d1f7c | |||
| 72f1d34eca | |||
| c267a75eef | |||
| 2fb755e0c9 | |||
| cd096819d8 | |||
| 83543423e2 | |||
| d0bb72a2aa | |||
| 8cc2a44268 | |||
| 4800dd3f95 | |||
| 2534310ce9 | |||
| 3a4fbc5e50 | |||
| 89a67ac719 | |||
| 21b84b1890 | |||
| 20935f678b | |||
| c41b4130c6 | |||
| f1b010af66 | |||
| ec1133d6e1 | |||
| 8fcf1b78a4 | |||
| 21f9148155 | |||
| d4f0593b37 |
+18
-2
@@ -19,8 +19,8 @@ variables:
|
||||
COMMON_MESON_FLAGS: "--fatal-meson-warnings --werror"
|
||||
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true -Dvulkan=yes"
|
||||
FEATURE_FLAGS: "-Dcloudproviders=true"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 2
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v17"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 3
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v20"
|
||||
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
|
||||
DOCS_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora-docs:v19"
|
||||
|
||||
@@ -180,6 +180,22 @@ static-scan:
|
||||
- _scan_build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
# Run tests with the address sanitizer. We need to turn off introspection,
|
||||
# since it is incompatible with asan
|
||||
asan-build:
|
||||
image: $FEDORA_IMAGE
|
||||
tags: [ privileged ]
|
||||
stage: analysis
|
||||
variables:
|
||||
script:
|
||||
- CC=clang meson --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=false _build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
artifacts:
|
||||
paths:
|
||||
- _build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
reference:
|
||||
image: $DOCS_IMAGE
|
||||
stage: docs
|
||||
|
||||
@@ -35,4 +35,13 @@ branch, as well as their available versions.
|
||||
- [ ] Add the new job to `.gitlab-ci.yml` referencing the image
|
||||
- [ ] Open a merge request with your changes and let it run
|
||||
|
||||
### Checklist for Adding a new dependency to a CI image
|
||||
|
||||
Our images are layered, and the base (called fedora-base) contains
|
||||
all the rpm payload. Therefore, adding a new dependency is a 2-step
|
||||
process:
|
||||
|
||||
1. [ ] Build and upload fedora-base:$version+1
|
||||
1. [ ] Build and upload fedora:$version+1 based on fedora-base:version+1
|
||||
|
||||
[registry]: https://gitlab.gnome.org/GNOME/gtk/container_registry
|
||||
|
||||
@@ -41,12 +41,14 @@ RUN dnf -y install \
|
||||
itstool \
|
||||
json-glib-devel \
|
||||
lcov \
|
||||
libasan \
|
||||
libattr-devel \
|
||||
libepoxy-devel \
|
||||
libffi-devel \
|
||||
libmount-devel \
|
||||
librsvg2 \
|
||||
libselinux-devel \
|
||||
libubsan \
|
||||
libXcomposite-devel \
|
||||
libXcursor-devel \
|
||||
libXcursor-devel \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
|
||||
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v20
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
|
||||
@@ -7,10 +7,14 @@ srcdir=$( pwd )
|
||||
builddir=$1
|
||||
backend=$2
|
||||
|
||||
# Ignore memory leaks lower in dependencies
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp
|
||||
|
||||
case "${backend}" in
|
||||
x11)
|
||||
xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
@@ -30,6 +34,7 @@ case "${backend}" in
|
||||
export WAYLAND_DISPLAY=wayland-5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
@@ -48,6 +53,7 @@ case "${backend}" in
|
||||
export BROADWAY_DISPLAY=:5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
|
||||
@@ -1,3 +1,74 @@
|
||||
Overview of Changes in GTK 3.99.0
|
||||
=================================
|
||||
|
||||
* Add GtkEditableLabel
|
||||
|
||||
* Add GtkBookmarkList, a list model for bookmarks
|
||||
|
||||
* Add GtkStringList, a list model for strings
|
||||
|
||||
* Add GtkBitset, and use it for representing selections
|
||||
|
||||
* GtkTreeView:
|
||||
- Make cell editing work again
|
||||
|
||||
* GtkSpinButton:
|
||||
- Make autosizing work again
|
||||
|
||||
* Printing:
|
||||
- Use GtkDropDown in the print dialog
|
||||
|
||||
* GtkApplication
|
||||
- Support opening files on OS X
|
||||
|
||||
* GtkFileChooser:
|
||||
- Fix libcloudproviders support
|
||||
- Turn GtkFileFilter into a GtkFilter
|
||||
- Simplify the api
|
||||
|
||||
* GtkGridView, GtkListView:
|
||||
- Improve scrolling behavior
|
||||
- Autoscroll and autoexpand during DND
|
||||
|
||||
* GtkFilterListModel:
|
||||
- Add incremental filtering
|
||||
|
||||
* GtkEntry:
|
||||
- Make entry completion work again
|
||||
- Drop action support from GtkEntryCompletion
|
||||
|
||||
* Inspector:
|
||||
- Improve list model support
|
||||
- Add direct navigation between objects
|
||||
|
||||
* GDK:
|
||||
- Compress scroll events
|
||||
- Keep a scroll history
|
||||
- Clean up GdkDevice api
|
||||
- Improve frame clock accuracy
|
||||
|
||||
* GSK:
|
||||
- Use gL_ARB_framebuffer_object
|
||||
|
||||
* gtk-demo:
|
||||
- Add incremental refill to the color grid
|
||||
- Improve performance of the color grid
|
||||
- Add an incrementally filtering word list
|
||||
|
||||
* Translation updates
|
||||
Basque
|
||||
Catalan
|
||||
Chinese
|
||||
Japanese
|
||||
Kazakh
|
||||
Lithuanian
|
||||
Polish
|
||||
Romanian
|
||||
Spanish
|
||||
Turkish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in GTK 3.98.5
|
||||
=================================
|
||||
|
||||
|
||||
@@ -15,7 +15,13 @@ if 'DESTDIR' not in os.environ:
|
||||
gtk_immodule_dir = os.path.join(gtk_moduledir, 'immodules')
|
||||
|
||||
print('Compiling GSettings schemas...')
|
||||
subprocess.call(['glib-compile-schemas',
|
||||
glib_compile_schemas = subprocess.check_output(['pkg-config',
|
||||
'--variable=glib_compile_schemas',
|
||||
'gio-2.0']).strip()
|
||||
if not os.path.exists(glib_compile_schemas):
|
||||
# pkg-config variables only available since GLib 2.62.0.
|
||||
glib_compile_schemas = 'glib-compile-schemas'
|
||||
subprocess.call([glib_compile_schemas,
|
||||
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
|
||||
|
||||
print('Updating icon cache...')
|
||||
@@ -24,8 +30,14 @@ if 'DESTDIR' not in os.environ:
|
||||
|
||||
print('Updating module cache for print backends...')
|
||||
os.makedirs(gtk_printmodule_dir, exist_ok=True)
|
||||
subprocess.call(['gio-querymodules', gtk_printmodule_dir])
|
||||
gio_querymodules = subprocess.check_output(['pkg-config',
|
||||
'--variable=gio_querymodules',
|
||||
'gio-2.0']).strip()
|
||||
if not os.path.exists(gio_querymodules):
|
||||
# pkg-config variables only available since GLib 2.62.0.
|
||||
gio_querymodules = 'gio-querymodules'
|
||||
subprocess.call([gio_querymodules, gtk_printmodule_dir])
|
||||
|
||||
print('Updating module cache for input methods...')
|
||||
os.makedirs(gtk_immodule_dir, exist_ok=True)
|
||||
subprocess.call(['gio-querymodules', gtk_immodule_dir])
|
||||
subprocess.call([gio_querymodules, gtk_immodule_dir])
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
|
||||
@@ -188,7 +188,7 @@ constraint_view_init (ConstraintView *self)
|
||||
g_list_store_append (list, children);
|
||||
g_list_store_append (list, guides);
|
||||
g_list_store_append (list, constraints);
|
||||
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
|
||||
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
|
||||
g_object_unref (children);
|
||||
g_object_unref (guides);
|
||||
g_object_unref (constraints);
|
||||
|
||||
@@ -140,6 +140,7 @@
|
||||
</gresource>
|
||||
<gresource prefix="/listview_colors">
|
||||
<file compressed="true">color.names.txt</file>
|
||||
<file>listview_colors.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/shortcuts">
|
||||
<file>shortcuts.ui</file>
|
||||
@@ -225,6 +226,7 @@
|
||||
<file>listview_minesweeper.c</file>
|
||||
<file>listview_settings.c</file>
|
||||
<file>listview_weather.c</file>
|
||||
<file>listview_words.c</file>
|
||||
<file>list_store.c</file>
|
||||
<file>markup.c</file>
|
||||
<file>modelbutton.c</file>
|
||||
|
||||
+179
-29
@@ -1,13 +1,15 @@
|
||||
/* Drop Downs
|
||||
/* Lists/Selections
|
||||
*
|
||||
* The GtkDropDown widget is a modern alternative to GtkComboBox.
|
||||
* It uses list models instead of tree models, and the content is
|
||||
* displayed using widgets instead of cell renderers.
|
||||
* The GtkDropDown and GtkSuggestionEntry widgets are modern
|
||||
* alternatives to GtkComboBox and GtkEntryCompletion.
|
||||
*
|
||||
* They use list models instead of tree models, and the content
|
||||
* is displayed using widgets instead of cell renderers.
|
||||
*
|
||||
* The examples here demonstrate how to use different kinds of
|
||||
* list models with GtkDropDown, how to use search and how to
|
||||
* display the selected item differently from the presentation
|
||||
* in the popup.
|
||||
* list models with GtkDropDown and GtkSuggestionEntry, how to
|
||||
* use search and how to display the selected item differently
|
||||
* from the presentation in the popup.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -92,7 +94,7 @@ strings_setup_item_full (GtkSignalListItemFactory *factory,
|
||||
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
|
||||
description = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (description), 0.0);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (description), "dim-label");
|
||||
gtk_widget_add_css_class (description, "dim-label");
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||
@@ -218,13 +220,50 @@ get_title (gpointer item)
|
||||
return g_strdup (STRING_HOLDER (item)->title);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_file_name (gpointer item)
|
||||
{
|
||||
return g_strdup (g_file_info_get_display_name (G_FILE_INFO (item)));
|
||||
}
|
||||
|
||||
static void
|
||||
setup_item (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *item)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *icon;
|
||||
GtkWidget *label;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
icon = gtk_image_new ();
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_box_append (GTK_BOX (box), icon);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
gtk_list_item_set_child (item, box);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_item (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *item)
|
||||
{
|
||||
GFileInfo *info = G_FILE_INFO (gtk_list_item_get_item (item));
|
||||
GtkWidget *box = gtk_list_item_get_child (item);
|
||||
GtkWidget *icon = gtk_widget_get_first_child (box);
|
||||
GtkWidget *label = gtk_widget_get_last_child (box);
|
||||
|
||||
gtk_image_set_from_gicon (GTK_IMAGE (icon), g_file_info_get_icon (info));
|
||||
gtk_label_set_label (GTK_LABEL (label), g_file_info_get_display_name (info));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_dropdown (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
GtkWidget *button, *box, *spin, *check;
|
||||
GtkWidget *button, *box, *spin, *check, *hbox, *label, *entry;
|
||||
GListModel *model;
|
||||
GtkExpression *expression;
|
||||
GtkListItemFactory *factory;
|
||||
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL };
|
||||
const char * const many_times[] = {
|
||||
"1 minute", "2 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes",
|
||||
@@ -237,23 +276,78 @@ do_dropdown (GtkWidget *do_widget)
|
||||
const char * const device_descriptions[] = {
|
||||
"Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio", "Thinkpad Tunderbolt 3 Dock USB Audio", NULL
|
||||
};
|
||||
const char *words[] = {
|
||||
"GNOME",
|
||||
"gnominious",
|
||||
"Gnomonic projection",
|
||||
"total",
|
||||
"totally",
|
||||
"toto",
|
||||
"tottery",
|
||||
"totterer",
|
||||
"Totten trust",
|
||||
"totipotent",
|
||||
"totipotency",
|
||||
"totemism",
|
||||
"totem pole",
|
||||
"Totara",
|
||||
"totalizer",
|
||||
"totalizator",
|
||||
"totalitarianism",
|
||||
"total parenteral nutrition",
|
||||
"total hysterectomy",
|
||||
"total eclipse",
|
||||
"Totipresence",
|
||||
"Totipalmi",
|
||||
"Tomboy",
|
||||
"zombie",
|
||||
NULL
|
||||
};
|
||||
|
||||
char *cwd;
|
||||
GFile *file;
|
||||
GListModel *dir;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Drop Downs");
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Selections");
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_widget_set_margin_start (box, 10);
|
||||
gtk_widget_set_margin_end (box, 10);
|
||||
gtk_widget_set_margin_top (box, 10);
|
||||
gtk_widget_set_margin_bottom (box, 10);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
|
||||
|
||||
gtk_widget_set_margin_start (hbox, 20);
|
||||
gtk_widget_set_margin_end (hbox, 20);
|
||||
gtk_widget_set_margin_top (hbox, 20);
|
||||
gtk_widget_set_margin_bottom (hbox, 20);
|
||||
gtk_window_set_child (GTK_WINDOW (window), hbox);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_box_append (GTK_BOX (hbox), box);
|
||||
|
||||
label = gtk_label_new ("Dropdowns");
|
||||
gtk_widget_add_css_class (label, "title-4");
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
/* A basic dropdown */
|
||||
button = drop_down_new_from_strings (times, NULL, NULL);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
/* A dropdown using an expression to obtain strings */
|
||||
button = drop_down_new_from_strings (many_times, NULL, NULL);
|
||||
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
|
||||
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)get_title,
|
||||
NULL, NULL);
|
||||
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
|
||||
gtk_expression_unref (expression);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
/* A dropdown using a non-trivial model, and search */
|
||||
button = gtk_drop_down_new ();
|
||||
|
||||
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
|
||||
@@ -270,30 +364,86 @@ do_dropdown (GtkWidget *do_widget)
|
||||
|
||||
spin = gtk_spin_button_new_with_range (-1, g_list_model_get_n_items (G_LIST_MODEL (model)), 1);
|
||||
gtk_widget_set_halign (spin, GTK_ALIGN_START);
|
||||
gtk_widget_set_margin_start (spin, 20);
|
||||
g_object_bind_property (button, "selected", spin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (box), spin);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Enable search");
|
||||
gtk_widget_set_margin_start (check, 20);
|
||||
g_object_bind_property (button, "enable-search", check, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
|
||||
g_object_unref (model);
|
||||
|
||||
button = drop_down_new_from_strings (times, NULL, NULL);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
button = drop_down_new_from_strings (many_times, NULL, NULL);
|
||||
gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
|
||||
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)get_title,
|
||||
NULL, NULL);
|
||||
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
|
||||
gtk_expression_unref (expression);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
/* A dropdown with a separate list factory */
|
||||
button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
|
||||
gtk_box_append (GTK_BOX (hbox), gtk_separator_new (GTK_ORIENTATION_VERTICAL));
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
|
||||
gtk_box_append (GTK_BOX (hbox), box);
|
||||
|
||||
label = gtk_label_new ("Suggestions");
|
||||
gtk_widget_add_css_class (label, "title-4");
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
/* A basic suggestion entry */
|
||||
entry = gtk_suggestion_entry_new ();
|
||||
g_object_set (entry, "placeholder-text", "Words with T or G…", NULL);
|
||||
gtk_suggestion_entry_set_from_strings (GTK_SUGGESTION_ENTRY (entry), words);
|
||||
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
gtk_widget_set_halign (hbox, GTK_ALIGN_START);
|
||||
gtk_widget_set_margin_start (hbox, 20);
|
||||
spin = gtk_spin_button_new_with_range (0, 10, 1);
|
||||
g_object_bind_property (entry, "minimum-length", spin, "value", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (hbox), gtk_label_new ("Min. length"));
|
||||
gtk_box_append (GTK_BOX (hbox), spin);
|
||||
gtk_box_append (GTK_BOX (box), hbox);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Auto-Insert");
|
||||
gtk_widget_set_margin_start (check, 20);
|
||||
g_object_bind_property (entry, "insert-prefix", check, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Auto-Select");
|
||||
gtk_widget_set_margin_start (check, 20);
|
||||
g_object_bind_property (entry, "insert-selection", check, "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
|
||||
/* A suggestion entry using a custom model, and no filtering */
|
||||
entry = gtk_suggestion_entry_new ();
|
||||
|
||||
cwd = g_get_current_dir ();
|
||||
file = g_file_new_for_path (cwd);
|
||||
dir = G_LIST_MODEL (gtk_directory_list_new ("standard::display-name,standard::content-type,standard::icon,standard::size", file));
|
||||
gtk_suggestion_entry_set_model (GTK_SUGGESTION_ENTRY (entry), dir);
|
||||
g_object_unref (dir);
|
||||
g_object_unref (file);
|
||||
g_free (cwd);
|
||||
|
||||
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)get_file_name,
|
||||
NULL, NULL);
|
||||
gtk_suggestion_entry_set_expression (GTK_SUGGESTION_ENTRY (entry), expression);
|
||||
gtk_expression_unref (expression);
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
|
||||
|
||||
gtk_suggestion_entry_set_factory (GTK_SUGGESTION_ENTRY (entry), factory);
|
||||
g_object_unref (factory);
|
||||
|
||||
gtk_suggestion_entry_set_use_filter (GTK_SUGGESTION_ENTRY (entry), FALSE);
|
||||
gtk_suggestion_entry_set_show_button (GTK_SUGGESTION_ENTRY (entry), TRUE);
|
||||
gtk_suggestion_entry_set_insert_selection (GTK_SUGGESTION_ENTRY (entry), TRUE);
|
||||
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<style>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<property name="title">Font Explorer</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="reset">
|
||||
<property name="receives-default">1</property>
|
||||
|
||||
@@ -30,7 +30,6 @@ do_headerbar (GtkWidget *do_widget)
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
|
||||
button = gtk_button_new ();
|
||||
icon = g_themed_icon_new ("mail-send-receive-symbolic");
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">500</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<style>
|
||||
|
||||
@@ -627,6 +627,23 @@ setup_listitem_cb (GtkListItemFactory *factory,
|
||||
gtk_expression_unref (color_expression);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_selection_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *picture;
|
||||
GtkExpression *color_expression, *expression;
|
||||
|
||||
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
|
||||
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
|
||||
|
||||
picture = gtk_picture_new ();
|
||||
gtk_widget_set_size_request (picture, 8, 8);
|
||||
gtk_expression_bind (color_expression, picture, "paintable", NULL);
|
||||
|
||||
gtk_list_item_set_child (list_item, picture);
|
||||
}
|
||||
|
||||
static void
|
||||
set_title (gpointer item,
|
||||
const char *title)
|
||||
@@ -777,6 +794,47 @@ bind_number_item (GtkSignalListItemFactory *factory,
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
static void
|
||||
update_selection_count (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
gpointer data)
|
||||
{
|
||||
char *text;
|
||||
text = g_strdup_printf ("%u", g_list_model_get_n_items (model));
|
||||
gtk_label_set_label (GTK_LABEL (data), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
update_selection_average (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
gpointer data)
|
||||
{
|
||||
guint n = g_list_model_get_n_items (model);
|
||||
GdkRGBA c = { 0, 0, 0, 1 };
|
||||
guint i;
|
||||
GtkColor *color;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
color = g_list_model_get_item (model, i);
|
||||
|
||||
c.red += color->color.red;
|
||||
c.green += color->color.green;
|
||||
c.blue += color->color.blue;
|
||||
|
||||
g_object_unref (color);
|
||||
}
|
||||
|
||||
color = gtk_color_new ("", c.red / n, c.green / n, c.blue / n);
|
||||
gtk_picture_set_paintable (GTK_PICTURE (data), GDK_PAINTABLE (color));
|
||||
g_object_unref (color);
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
@@ -797,11 +855,26 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
PangoAttrList *attrs;
|
||||
char *string;
|
||||
guint len;
|
||||
GtkWidget *selection_view;
|
||||
GListModel *selection_filter;
|
||||
GListModel *no_selection;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *selection_size_label;
|
||||
GtkWidget *selection_average_picture;
|
||||
GtkWidget *selection_info_toggle;
|
||||
GtkWidget *selection_info_revealer;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/listview_colors/listview_colors.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
800);
|
||||
g_object_unref (provider);
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
@@ -809,14 +882,85 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
selection_info_revealer = gtk_revealer_new ();
|
||||
gtk_box_append (GTK_BOX (box), selection_info_revealer);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_revealer_set_child (GTK_REVEALER (selection_info_revealer), grid);
|
||||
gtk_widget_set_margin_start (grid, 10);
|
||||
gtk_widget_set_margin_end (grid, 10);
|
||||
gtk_widget_set_margin_top (grid, 10);
|
||||
gtk_widget_set_margin_bottom (grid, 10);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
|
||||
|
||||
label = gtk_label_new ("Selection");
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_widget_add_css_class (label, "title-3");
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 5, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Size:"), 0, 2, 1, 1);
|
||||
|
||||
selection_size_label = gtk_label_new ("0");
|
||||
gtk_grid_attach (GTK_GRID (grid), selection_size_label, 1, 2, 1, 1);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Average:"), 2, 2, 1, 1);
|
||||
|
||||
selection_average_picture = gtk_picture_new ();
|
||||
gtk_widget_set_size_request (selection_average_picture, 32, 32);
|
||||
gtk_grid_attach (GTK_GRID (grid), selection_average_picture, 3, 2, 1, 1);
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), label, 4, 2, 1, 1);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
gtk_widget_set_hexpand (sw, TRUE);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), sw, 0, 1, 5, 1);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_selection_listitem_cb), NULL);
|
||||
selection_view = gtk_grid_view_new_with_factory (factory);
|
||||
gtk_widget_add_css_class (selection_view, "compact");
|
||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (selection_view), 200);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), selection_view);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_box_append (GTK_BOX (box), sw);
|
||||
|
||||
gridview = create_color_grid ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
|
||||
gtk_widget_set_hexpand (sw, TRUE);
|
||||
gtk_widget_set_vexpand (sw, TRUE);
|
||||
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
|
||||
|
||||
selection_filter = G_LIST_MODEL (gtk_selection_filter_model_new (GTK_SELECTION_MODEL (model)));
|
||||
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_count), selection_size_label);
|
||||
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_average), selection_average_picture);
|
||||
|
||||
no_selection = G_LIST_MODEL (gtk_no_selection_new (selection_filter));
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (selection_view), no_selection);
|
||||
g_object_unref (selection_filter);
|
||||
g_object_unref (no_selection);
|
||||
|
||||
g_object_get (model, "model", &model, NULL);
|
||||
|
||||
selection_info_toggle = gtk_toggle_button_new ();
|
||||
gtk_button_set_icon_name (GTK_BUTTON (selection_info_toggle), "emblem-important-symbolic");
|
||||
gtk_widget_set_tooltip_text (selection_info_toggle, "Show selection info");
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), selection_info_toggle);
|
||||
|
||||
g_object_bind_property (selection_info_toggle, "active",
|
||||
selection_info_revealer, "reveal-child",
|
||||
G_BINDING_DEFAULT);
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Refill");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (refill),
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.view.compact > child {
|
||||
padding: 1px;
|
||||
}
|
||||
@@ -174,7 +174,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">go-up-symbolic</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="title" translatable="yes">Minesweeper</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">New Game</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">480</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="search_button">
|
||||
<property name="icon-name">system-search-symbolic</property>
|
||||
|
||||
@@ -194,8 +194,8 @@ create_weather_model (void)
|
||||
}
|
||||
|
||||
static void
|
||||
setup_widget (GtkListItem *list_item,
|
||||
gpointer unused)
|
||||
setup_widget (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *box, *child;
|
||||
|
||||
@@ -218,8 +218,8 @@ setup_widget (GtkListItem *list_item,
|
||||
}
|
||||
|
||||
static void
|
||||
bind_widget (GtkListItem *list_item,
|
||||
gpointer unused)
|
||||
bind_widget (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *box, *child;
|
||||
GtkWeatherInfo *info;
|
||||
@@ -282,11 +282,12 @@ create_weather_view (void)
|
||||
{
|
||||
GtkWidget *listview;
|
||||
GListModel *model, *selection;
|
||||
GtkListItemFactory *factory;
|
||||
|
||||
listview = gtk_list_view_new_with_factory (
|
||||
gtk_functions_list_item_factory_new (setup_widget,
|
||||
bind_widget,
|
||||
NULL, NULL));
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_widget), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_widget), NULL);
|
||||
listview = gtk_list_view_new_with_factory (factory);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
|
||||
model = create_weather_model ();
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/* Lists/Words
|
||||
*
|
||||
* This demo shows filtering a long list - of words.
|
||||
*
|
||||
* You should have the file `/usr/share/dict/words` installed for
|
||||
* this demo to work.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *progress;
|
||||
|
||||
const char *factory_text =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkLabel'>\n"
|
||||
" <property name='ellipsize'>end</property>\n"
|
||||
" <property name='xalign'>0</property>\n"
|
||||
" <binding name='label'>\n"
|
||||
" <lookup name='string' type='GtkStringObject'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
static void
|
||||
update_title_cb (GtkFilterListModel *model)
|
||||
{
|
||||
guint total;
|
||||
char *title;
|
||||
guint pending;
|
||||
|
||||
total = g_list_model_get_n_items (gtk_filter_list_model_get_model (model));
|
||||
pending = gtk_filter_list_model_get_pending (model);
|
||||
|
||||
title = g_strdup_printf ("%u lines", g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
|
||||
gtk_widget_set_visible (progress, pending != 0);
|
||||
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (total - pending) / (double) total);
|
||||
gtk_window_set_title (GTK_WINDOW (window), title);
|
||||
g_free (title);
|
||||
}
|
||||
|
||||
static void
|
||||
read_lines_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (object);
|
||||
GtkStringList *stringlist = data;
|
||||
GError *error = NULL;
|
||||
gsize size;
|
||||
GPtrArray *lines;
|
||||
gssize n_filled;
|
||||
const char *buffer, *newline;
|
||||
|
||||
n_filled = g_buffered_input_stream_fill_finish (stream, result, &error);
|
||||
if (n_filled < 0)
|
||||
{
|
||||
g_print ("Could not read data: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||
|
||||
if (n_filled == 0)
|
||||
{
|
||||
if (size)
|
||||
gtk_string_list_take (stringlist, g_utf8_make_valid (buffer, size));
|
||||
return;
|
||||
}
|
||||
|
||||
lines = NULL;
|
||||
while ((newline = memchr (buffer, '\n', size)))
|
||||
{
|
||||
if (newline > buffer)
|
||||
{
|
||||
if (lines == NULL)
|
||||
lines = g_ptr_array_new_with_free_func (g_free);
|
||||
g_ptr_array_add (lines, g_utf8_make_valid (buffer, newline - buffer));
|
||||
}
|
||||
if (g_input_stream_skip (G_INPUT_STREAM (stream), newline - buffer + 1, NULL, &error) < 0)
|
||||
{
|
||||
g_clear_error (&error);
|
||||
break;
|
||||
}
|
||||
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||
}
|
||||
if (lines == NULL)
|
||||
{
|
||||
g_buffered_input_stream_set_buffer_size (stream, g_buffered_input_stream_get_buffer_size (stream) + 4096);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (lines, NULL);
|
||||
gtk_string_list_splice (stringlist, g_list_model_get_n_items (G_LIST_MODEL (stringlist)), 0, (const char **) lines->pdata);
|
||||
g_ptr_array_free (lines, TRUE);
|
||||
}
|
||||
|
||||
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||
}
|
||||
|
||||
static void
|
||||
file_is_open_cb (GObject *file,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GFileInputStream *file_stream;
|
||||
GBufferedInputStream *stream;
|
||||
|
||||
file_stream = g_file_read_finish (G_FILE (file), result, &error);
|
||||
if (file_stream == NULL)
|
||||
{
|
||||
g_print ("Could not open file: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = G_BUFFERED_INPUT_STREAM (g_buffered_input_stream_new (G_INPUT_STREAM (file_stream)));
|
||||
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
load_file (GtkStringList *list,
|
||||
GFile *file)
|
||||
{
|
||||
gtk_string_list_splice (list, 0, g_list_model_get_n_items (G_LIST_MODEL (list)), NULL);
|
||||
g_file_read_async (file, G_PRIORITY_HIGH_IDLE, NULL, file_is_open_cb, list);
|
||||
}
|
||||
|
||||
static void
|
||||
file_selected_cb (GtkWidget *button,
|
||||
GtkStringList *stringlist)
|
||||
{
|
||||
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (button));
|
||||
|
||||
if (file)
|
||||
{
|
||||
load_file (stringlist, file);
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_listview_words (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *header, *listview, *sw, *vbox, *search_entry, *open_button, *overlay;
|
||||
GtkFilterListModel *filter_model;
|
||||
GtkNoSelection *selection;
|
||||
GtkStringList *stringlist;
|
||||
GtkFilter *filter;
|
||||
GtkExpression *expression;
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_path ("/usr/share/dict/words");
|
||||
if (g_file_query_exists (file, NULL))
|
||||
{
|
||||
stringlist = gtk_string_list_new (NULL);
|
||||
load_file (stringlist, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char **words;
|
||||
words = g_strsplit ("lorem ipsum dolor sit amet consectetur adipisci elit sed eiusmod tempor incidunt labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat", " ", -1);
|
||||
stringlist = gtk_string_list_new ((const char **) words);
|
||||
g_strfreev (words);
|
||||
}
|
||||
|
||||
filter = gtk_string_filter_new ();
|
||||
expression = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string");
|
||||
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
|
||||
gtk_expression_unref (expression);
|
||||
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (stringlist), filter);
|
||||
gtk_filter_list_model_set_incremental (filter_model, TRUE);
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
open_button = gtk_file_chooser_button_new ("_Open", GTK_FILE_CHOOSER_ACTION_OPEN);
|
||||
g_signal_connect (open_button, "file-set", G_CALLBACK (file_selected_cb), stringlist);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), open_button);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
|
||||
search_entry = gtk_search_entry_new ();
|
||||
g_object_bind_property (search_entry, "text", filter, "search", 0);
|
||||
gtk_box_append (GTK_BOX (vbox), search_entry);
|
||||
|
||||
overlay = gtk_overlay_new ();
|
||||
gtk_box_append (GTK_BOX (vbox), overlay);
|
||||
|
||||
progress = gtk_progress_bar_new ();
|
||||
gtk_widget_set_halign (progress, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_valign (progress, GTK_ALIGN_START);
|
||||
gtk_widget_set_hexpand (progress, TRUE);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), progress);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_overlay_set_child (GTK_OVERLAY (overlay), sw);
|
||||
|
||||
listview = gtk_list_view_new_with_factory (
|
||||
gtk_builder_list_item_factory_new_from_bytes (NULL,
|
||||
g_bytes_new_static (factory_text, strlen (factory_text))));
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
selection = gtk_no_selection_new (G_LIST_MODEL (filter_model));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
|
||||
g_object_unref (selection);
|
||||
|
||||
g_signal_connect (filter_model, "items-changed", G_CALLBACK (update_title_cb), progress);
|
||||
g_signal_connect (filter_model, "notify::pending", G_CALLBACK (update_title_cb), progress);
|
||||
update_title_cb (filter_model);
|
||||
|
||||
g_object_unref (filter_model);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
<property name="default-height">600</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="headerbar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="valign">center</property>
|
||||
|
||||
@@ -69,7 +69,6 @@ do_markup (GtkWidget *do_widget)
|
||||
g_signal_connect (show_source, "toggled", G_CALLBACK (source_toggled), stack);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), show_source);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ demos = files([
|
||||
'cursors.c',
|
||||
'dialog.c',
|
||||
'drawingarea.c',
|
||||
'dropdown.c',
|
||||
'dnd.c',
|
||||
'editable_cells.c',
|
||||
'entry_completion.c',
|
||||
@@ -47,8 +46,10 @@ demos = files([
|
||||
'listview_colors.c',
|
||||
'listview_filebrowser.c',
|
||||
'listview_minesweeper.c',
|
||||
'dropdown.c',
|
||||
'listview_settings.c',
|
||||
'listview_weather.c',
|
||||
'listview_words.c',
|
||||
'markup.c',
|
||||
'modelbutton.c',
|
||||
'overlay.c',
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
<property name="title" translatable="yes">Model Button</property>
|
||||
<property name="resizable">0</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
</object>
|
||||
<object class="GtkHeaderBar"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
|
||||
@@ -392,7 +392,6 @@ do_paint (GtkWidget *toplevel)
|
||||
gtk_window_set_child (GTK_WINDOW (window), draw_area);
|
||||
|
||||
headerbar = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (headerbar), TRUE);
|
||||
|
||||
colorbutton = gtk_color_button_new ();
|
||||
g_signal_connect (colorbutton, "color-set",
|
||||
|
||||
@@ -276,7 +276,6 @@ do_peg_solitaire (GtkWidget *do_widget)
|
||||
g_signal_connect (restart, "clicked", G_CALLBACK (restart), NULL);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
|
||||
@@ -40,7 +40,6 @@ do_sidebar (GtkWidget *do_widget)
|
||||
gtk_widget_set_size_request (window, 500, 350);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR(header), TRUE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW(window), header);
|
||||
gtk_window_set_title (GTK_WINDOW(window), "Stack Sidebar");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
@@ -470,7 +470,6 @@ do_sliding_puzzle (GtkWidget *do_widget)
|
||||
g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
|
||||
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
|
||||
window = gtk_window_new ();
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<property name="resizable">0</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="start">
|
||||
<object class="GtkToggleButton" id="toggle">
|
||||
<property name="label">Cycle</property>
|
||||
|
||||
@@ -73,7 +73,6 @@ do_video_player (GtkWidget *do_widget)
|
||||
gtk_window_set_child (GTK_WINDOW (window), video);
|
||||
|
||||
title = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (title), TRUE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), title);
|
||||
|
||||
open_button = gtk_button_new_with_mnemonic ("_Open");
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkBox">
|
||||
<style>
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
<property name="focus-widget">text_view</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="start">
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">document-open-symbolic</property>
|
||||
|
||||
@@ -436,7 +436,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
|
||||
<property name="title">GTK Widget Factory</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="headerbar1">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="stack">toplevel_stack</property>
|
||||
|
||||
@@ -1423,7 +1423,6 @@ the search bar below the header bar.
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
@@ -1537,7 +1536,6 @@ GtkMenuButton, GtkRevealer and GtkListBox.
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
<section>
|
||||
<xi:include href="xml/gtkfilter.xml" />
|
||||
<xi:include href="xml/gtkcustomfilter.xml" />
|
||||
<xi:include href="xml/gtkstringfilter.xml" />
|
||||
<xi:include href="xml/gtkmultifilter.xml" />
|
||||
<xi:include href="xml/gtkstringfilter.xml" />
|
||||
<xi:include href="xml/gtkfilefilter.xml" />
|
||||
</section>
|
||||
<xi:include href="xml/gtkflattenlistmodel.xml" />
|
||||
<xi:include href="xml/gtkmaplistmodel.xml" />
|
||||
@@ -74,6 +75,7 @@
|
||||
<xi:include href="xml/gtksingleselection.xml" />
|
||||
<xi:include href="xml/gtkmultiselection.xml" />
|
||||
</section>
|
||||
<xi:include href="xml/gtkselectionfiltermodel.xml" />
|
||||
<xi:include href="xml/gtkbookmarklist.xml" />
|
||||
<xi:include href="xml/gtkdirectorylist.xml" />
|
||||
<xi:include href="xml/gtkstringlist.xml" />
|
||||
@@ -219,6 +221,7 @@
|
||||
<xi:include href="xml/gtksearchentry.xml" />
|
||||
<xi:include href="xml/gtksearchbar.xml" />
|
||||
<xi:include href="xml/gtkeditablelabel.xml" />
|
||||
<xi:include href="xml/gtksuggestionentry.xml" />
|
||||
</chapter>
|
||||
|
||||
<chapter id="TextWidgetObjects">
|
||||
@@ -284,7 +287,6 @@
|
||||
<xi:include href="xml/gtkfilechoosernative.xml" />
|
||||
<xi:include href="xml/gtkfilechooserdialog.xml" />
|
||||
<xi:include href="xml/gtkfilechooserwidget.xml" />
|
||||
<xi:include href="xml/gtkfilefilter.xml" />
|
||||
<xi:include href="xml/gtkfontchooser.xml" />
|
||||
<xi:include href="xml/gtkfontbutton.xml" />
|
||||
<xi:include href="xml/gtkfontchooserwidget.xml" />
|
||||
|
||||
@@ -348,6 +348,7 @@ GtkBitset
|
||||
gtk_bitset_ref
|
||||
gtk_bitset_unref
|
||||
gtk_bitset_new_empty
|
||||
gtk_bitset_new_range
|
||||
gtk_bitset_copy
|
||||
<SUBSECTION>
|
||||
gtk_bitset_contains
|
||||
@@ -355,6 +356,9 @@ gtk_bitset_is_empty
|
||||
gtk_bitset_equals
|
||||
gtk_bitset_get_minimum
|
||||
gtk_bitset_get_maximum
|
||||
gtk_bitset_get_size
|
||||
gtk_bitset_get_size_in_range
|
||||
gtk_bitset_get_nth
|
||||
<SUBSECTION>
|
||||
gtk_bitset_remove_all
|
||||
gtk_bitset_add
|
||||
@@ -371,7 +375,7 @@ gtk_bitset_subtract
|
||||
gtk_bitset_difference
|
||||
gtk_bitset_shift_left
|
||||
gtk_bitset_shift_right
|
||||
gtk_bitset_slice
|
||||
gtk_bitset_splice
|
||||
<SUBSECTION>
|
||||
GtkBitsetIter
|
||||
gtk_bitset_iter_init_first
|
||||
@@ -419,6 +423,7 @@ gtk_selection_model_get_type
|
||||
GtkNoSelection
|
||||
gtk_no_selection_new
|
||||
gtk_no_selection_get_model
|
||||
gtk_no_selection_set_model
|
||||
<SUBSECTION Private>
|
||||
gtk_no_selection_get_type
|
||||
</SECTION>
|
||||
@@ -430,6 +435,7 @@ GtkSingleSelection
|
||||
GTK_INVALID_LIST_POSITION
|
||||
gtk_single_selection_new
|
||||
gtk_single_selection_get_model
|
||||
gtk_single_selection_set_model
|
||||
gtk_single_selection_get_selected
|
||||
gtk_single_selection_set_selected
|
||||
gtk_single_selection_get_selected_item
|
||||
@@ -446,6 +452,8 @@ gtk_single_selection_get_type
|
||||
<TITLE>GtkMultiSeledction</TITLE>
|
||||
GtkMultiSelection
|
||||
gtk_multi_selection_new
|
||||
gtk_multi_selection_get_model
|
||||
gtk_multi_selection_set_model
|
||||
<SUBSECTION Private>
|
||||
gtk_multi_selection_get_type
|
||||
</SECTION>
|
||||
@@ -1292,23 +1300,19 @@ gtk_file_chooser_get_current_name
|
||||
<SUBSECTION>
|
||||
gtk_file_chooser_get_file
|
||||
gtk_file_chooser_set_file
|
||||
gtk_file_chooser_select_file
|
||||
gtk_file_chooser_unselect_file
|
||||
gtk_file_chooser_select_all
|
||||
gtk_file_chooser_unselect_all
|
||||
gtk_file_chooser_get_files
|
||||
gtk_file_chooser_set_current_folder
|
||||
gtk_file_chooser_get_current_folder
|
||||
<SUBSECTION>
|
||||
gtk_file_chooser_add_filter
|
||||
gtk_file_chooser_remove_filter
|
||||
gtk_file_chooser_list_filters
|
||||
gtk_file_chooser_get_filters
|
||||
gtk_file_chooser_set_filter
|
||||
gtk_file_chooser_get_filter
|
||||
<SUBSECTION>
|
||||
gtk_file_chooser_add_shortcut_folder
|
||||
gtk_file_chooser_remove_shortcut_folder
|
||||
gtk_file_chooser_list_shortcut_folders
|
||||
gtk_file_chooser_get_shortcut_folders
|
||||
<SUBSECTION>
|
||||
gtk_file_chooser_add_choice
|
||||
gtk_file_chooser_remove_choice
|
||||
@@ -1405,18 +1409,13 @@ GtkFileChooserButtonPrivate
|
||||
<SECTION>
|
||||
<FILE>gtkfilefilter</FILE>
|
||||
GtkFileFilter
|
||||
GtkFileFilterInfo
|
||||
GtkFileFilterFlags
|
||||
GtkFileFilterFunc
|
||||
gtk_file_filter_new
|
||||
gtk_file_filter_set_name
|
||||
gtk_file_filter_get_name
|
||||
gtk_file_filter_add_mime_type
|
||||
gtk_file_filter_add_pattern
|
||||
gtk_file_filter_add_pixbuf_formats
|
||||
gtk_file_filter_add_custom
|
||||
gtk_file_filter_get_needed
|
||||
gtk_file_filter_filter
|
||||
gtk_file_filter_get_attributes
|
||||
|
||||
<SUBSECTION Serialization>
|
||||
gtk_file_filter_new_from_gvariant
|
||||
@@ -1441,6 +1440,8 @@ gtk_directory_list_get_file
|
||||
gtk_directory_list_set_file
|
||||
gtk_directory_list_get_io_priority
|
||||
gtk_directory_list_set_io_priority
|
||||
gtk_directory_list_get_monitored
|
||||
gtk_directory_list_set_monitored
|
||||
gtk_directory_list_is_loading
|
||||
gtk_directory_list_get_error
|
||||
<SUBSECTION Standard>
|
||||
@@ -1535,11 +1536,13 @@ gtk_custom_filter_get_type
|
||||
<TITLE>GtkFilterListModel</TITLE>
|
||||
GtkFilterListModel
|
||||
gtk_filter_list_model_new
|
||||
gtk_filter_list_model_new_for_type
|
||||
gtk_filter_list_model_set_model
|
||||
gtk_filter_list_model_get_model
|
||||
gtk_filter_list_model_set_filter
|
||||
gtk_filter_list_model_get_filter
|
||||
gtk_filter_list_model_set_incremental
|
||||
gtk_filter_list_model_get_incremental
|
||||
gtk_filter_list_model_get_pending
|
||||
<SUBSECTION Standard>
|
||||
GTK_FILTER_LIST_MODEL
|
||||
GTK_IS_FILTER_LIST_MODEL
|
||||
@@ -2694,7 +2697,6 @@ gtk_size_group_get_type
|
||||
<TITLE>GtkSliceListModel</TITLE>
|
||||
GtkSliceListModel
|
||||
gtk_slice_list_model_new
|
||||
gtk_slice_list_model_new_for_type
|
||||
gtk_slice_list_model_set_model
|
||||
gtk_slice_list_model_get_model
|
||||
gtk_slice_list_model_set_offset
|
||||
@@ -2826,7 +2828,6 @@ gtk_tree_list_row_sorter_get_type
|
||||
<TITLE>GtkSortListModel</TITLE>
|
||||
GtkSortListModel
|
||||
gtk_sort_list_model_new
|
||||
gtk_sort_list_model_new_for_type
|
||||
gtk_sort_list_model_set_sorter
|
||||
gtk_sort_list_model_get_sorter
|
||||
gtk_sort_list_model_set_model
|
||||
@@ -7606,6 +7607,42 @@ gtk_string_list_take
|
||||
gtk_string_list_remove
|
||||
gtk_string_list_splice
|
||||
gtk_string_list_get_string
|
||||
<SUBSECTION>
|
||||
GtkStringObject
|
||||
gtk_string_object_new
|
||||
gtk_string_object_get_string
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkselectionfiltermodel</FILE>
|
||||
<TITLE>GtkSelectionFilterModel</TITLE>
|
||||
GtkSelectionFilterModel
|
||||
gtk_selection_filter_model_new
|
||||
gtk_selection_filter_model_new_for_type
|
||||
gtk_selection_filter_model_set_model
|
||||
gtk_selection_filter_model_get_model
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtksuggestionentry</FILE>
|
||||
<TITLE>GtkSuggestionEntry</TITLE>
|
||||
GtkSuggestionEntry
|
||||
gtk_suggestion_entry_new
|
||||
gtk_suggestion_entry_set_model
|
||||
gtk_suggestion_entry_get_model
|
||||
gtk_suggestion_entry_set_from_strings
|
||||
gtk_suggestion_entry_set_factory
|
||||
gtk_suggestion_entry_get_factory
|
||||
gtk_suggestion_entry_set_expression
|
||||
gtk_suggestion_entry_get_expression
|
||||
gtk_suggestion_entry_set_use_filter
|
||||
gtk_suggestion_entry_get_use_filter
|
||||
gtk_suggestion_entry_set_insert_selection
|
||||
gtk_suggestion_entry_get_insert_selection
|
||||
gtk_suggestion_entry_set_insert_prefix
|
||||
gtk_suggestion_entry_get_insert_prefix
|
||||
gtk_suggestion_entry_set_show_button
|
||||
gtk_suggestion_entry_get_show_button
|
||||
gtk_suggestion_entry_set_minimum_length
|
||||
gtk_suggestion_entry_get_minimum_length
|
||||
</SECTION>
|
||||
|
||||
@@ -184,6 +184,7 @@ gtk_scrollbar_get_type
|
||||
gtk_scrolled_window_get_type
|
||||
gtk_search_bar_get_type
|
||||
gtk_search_entry_get_type
|
||||
gtk_selection_filter_model_get_type
|
||||
gtk_selection_model_get_type
|
||||
gtk_separator_get_type
|
||||
gtk_settings_get_type
|
||||
@@ -213,6 +214,7 @@ gtk_string_filter_get_type
|
||||
gtk_string_list_get_type
|
||||
gtk_string_object_get_type
|
||||
gtk_string_sorter_get_type
|
||||
gtk_suggestion_entry_get_type
|
||||
gtk_switch_get_type
|
||||
gtk_level_bar_get_type
|
||||
gtk_style_context_get_type
|
||||
|
||||
@@ -411,6 +411,7 @@ and gtk_box_append(). You can also reorder box children as necessary.
|
||||
The gtk_header_bar_set_show_close_button() function has been renamed to
|
||||
the more accurate name gtk_header_bar_set_show_title_buttons(). The
|
||||
corresponding getter and the property itself have also been renamed.
|
||||
The default value of the property is now %TRUE instead of %FALSE.
|
||||
|
||||
The gtk_header_bar_set_custom_title() function has been renamed to
|
||||
the more accurate name gtk_header_bar_set_title_widget(). The
|
||||
|
||||
@@ -198,4 +198,6 @@ transitioning code for easy lookup:
|
||||
| #GtkCellLayout | #GtkListItemFactory |
|
||||
| #GtkCellArea | #GtkWidget |
|
||||
| #GtkCellRenderer | #GtkWidget |
|
||||
| #GtkComboBoxText | #GtkSuggestionEntry |
|
||||
| #GtkEntryCompletion | #GtkSuggestionEntry |
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="lines_label">
|
||||
<property name="visible">0</property>
|
||||
|
||||
@@ -15,7 +15,6 @@ new_window (GApplication *app,
|
||||
gtk_window_set_icon_name (GTK_WINDOW (window), "sunny");
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
overlay = gtk_overlay_new ();
|
||||
|
||||
@@ -1648,6 +1648,38 @@ create_zxdg_toplevel_v6_resources (GdkSurface *surface)
|
||||
surface);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_surface_set_application_id (GdkSurface *surface, const char* application_id)
|
||||
{
|
||||
GdkWaylandSurface *impl;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
|
||||
g_return_if_fail (application_id != NULL);
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (surface))
|
||||
return;
|
||||
|
||||
if (!is_realized_toplevel (surface))
|
||||
return;
|
||||
|
||||
display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
switch (display_wayland->shell_variant)
|
||||
{
|
||||
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
|
||||
xdg_toplevel_set_app_id (impl->display_server.xdg_toplevel,
|
||||
application_id);
|
||||
break;
|
||||
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
|
||||
zxdg_toplevel_v6_set_app_id (impl->display_server.zxdg_toplevel_v6,
|
||||
application_id);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface)
|
||||
{
|
||||
@@ -1702,19 +1734,7 @@ gdk_wayland_surface_create_xdg_toplevel (GdkSurface *surface)
|
||||
if (app_id == NULL)
|
||||
app_id = "GTK+ Application";
|
||||
|
||||
switch (display_wayland->shell_variant)
|
||||
{
|
||||
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
|
||||
xdg_toplevel_set_app_id (impl->display_server.xdg_toplevel,
|
||||
app_id);
|
||||
break;
|
||||
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
|
||||
zxdg_toplevel_v6_set_app_id (impl->display_server.zxdg_toplevel_v6,
|
||||
app_id);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
gdk_wayland_surface_set_application_id (surface, app_id);
|
||||
|
||||
maybe_set_gtk_surface_dbus_properties (surface);
|
||||
maybe_set_gtk_surface_modal (surface);
|
||||
|
||||
@@ -74,6 +74,10 @@ GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_wayland_surface_set_transient_for_exported (GdkSurface *surface,
|
||||
char *parent_handle_str);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_wayland_surface_set_application_id (GdkSurface *surface,
|
||||
const char *application_id);
|
||||
|
||||
void gdk_wayland_surface_announce_csd (GdkSurface *surface);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -653,6 +653,8 @@ gdk_x11_clipboard_store_async (GdkClipboard *clipboard,
|
||||
GDK_DISPLAY_NOTE (display, CLIPBOARD,
|
||||
g_printerr ("%s: X error during ConvertSelection() while storing selection: %d\n", cb->selection, error));
|
||||
}
|
||||
|
||||
g_free (atoms);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -1874,6 +1874,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
case XI_Leave:
|
||||
{
|
||||
XIEnterEvent *xev = (XIEnterEvent *) ev;
|
||||
GdkModifierType state;
|
||||
|
||||
GDK_DISPLAY_NOTE (display, EVENTS,
|
||||
g_message ("%s notify:\twindow %ld\n\tsubwindow:%ld\n"
|
||||
@@ -1890,6 +1891,18 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
|
||||
state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
/* Ignore normal crossing events while there is an implicit grab.
|
||||
* We will receive a crossing event with one of the other details if
|
||||
* the implicit grab were finished (eg. releasing the button outside
|
||||
* the window triggers a XINotifyUngrab leave).
|
||||
*/
|
||||
if (xev->mode == XINotifyNormal &&
|
||||
(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
|
||||
GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)))
|
||||
break;
|
||||
|
||||
if (ev->evtype == XI_Enter &&
|
||||
xev->detail != XINotifyInferior && xev->mode != XINotifyPassiveUngrab &&
|
||||
GDK_IS_TOPLEVEL (surface))
|
||||
@@ -1916,12 +1929,11 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
device,
|
||||
source_device,
|
||||
xev->time,
|
||||
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
|
||||
state,
|
||||
(double) xev->event_x / scale,
|
||||
(double) xev->event_y / scale,
|
||||
translate_crossing_mode (xev->mode),
|
||||
translate_notify_type (xev->detail));
|
||||
|
||||
}
|
||||
break;
|
||||
case XI_FocusIn:
|
||||
|
||||
@@ -1184,7 +1184,7 @@ _gdk_wm_protocols_filter (const XEvent *xevent,
|
||||
if (timings)
|
||||
timings->drawn_time = frame_drawn_time;
|
||||
|
||||
if (surface_impl->toplevel->frame_pending)
|
||||
if (!surface_impl->toplevel->frame_still_painting && surface_impl->toplevel->frame_pending)
|
||||
{
|
||||
surface_impl->toplevel->frame_pending = FALSE;
|
||||
gdk_surface_thaw_updates (win);
|
||||
|
||||
+49
-10
@@ -582,6 +582,23 @@ create_legacy_context (GdkDisplay *display,
|
||||
}
|
||||
|
||||
#ifdef HAVE_XDAMAGE
|
||||
static void
|
||||
finish_frame (GdkGLContext *context)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
|
||||
if (context_x11->xdamage == 0)
|
||||
return;
|
||||
|
||||
if (context_x11->frame_fence == 0)
|
||||
return;
|
||||
|
||||
glDeleteSync (context_x11->frame_fence);
|
||||
context_x11->frame_fence = 0;
|
||||
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_context_for_frame_fence (GdkGLContext *context)
|
||||
{
|
||||
@@ -628,7 +645,6 @@ on_gl_surface_xevent (GdkGLContext *context,
|
||||
GdkX11Display *display_x11)
|
||||
{
|
||||
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
XDamageNotifyEvent *damage_xevent;
|
||||
|
||||
if (!context_x11->is_attached)
|
||||
@@ -675,9 +691,7 @@ on_gl_surface_xevent (GdkGLContext *context,
|
||||
case GL_WAIT_FAILED:
|
||||
if (wait_result == GL_WAIT_FAILED)
|
||||
g_warning ("failed to wait on GL fence associated with last swap buffers call");
|
||||
glDeleteSync (context_x11->frame_fence);
|
||||
context_x11->frame_fence = 0;
|
||||
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
|
||||
finish_frame (context);
|
||||
break;
|
||||
|
||||
/* We assume that if the fence hasn't been signaled, that this
|
||||
@@ -696,6 +710,21 @@ on_gl_surface_xevent (GdkGLContext *context,
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_surface_state_changed (GdkGLContext *context)
|
||||
{
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
|
||||
if ((surface->state & GDK_SURFACE_STATE_WITHDRAWN) == 0)
|
||||
return;
|
||||
|
||||
/* If we're about to withdraw the surface, then we don't care if the frame is
|
||||
* still getting rendered by the GPU. The compositor is going to remove the surface
|
||||
* from the scene anyway, so wrap up the frame.
|
||||
*/
|
||||
finish_frame (context);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
@@ -878,13 +907,23 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
|
||||
gdk_x11_surface_get_xid (surface),
|
||||
XDamageReportRawRectangles);
|
||||
if (gdk_x11_display_error_trap_pop (display))
|
||||
context_x11->xdamage = 0;
|
||||
{
|
||||
context_x11->xdamage = 0;
|
||||
}
|
||||
else
|
||||
g_signal_connect_object (G_OBJECT (display),
|
||||
"xevent",
|
||||
G_CALLBACK (on_gl_surface_xevent),
|
||||
context,
|
||||
G_CONNECT_SWAPPED);
|
||||
{
|
||||
g_signal_connect_object (G_OBJECT (display),
|
||||
"xevent",
|
||||
G_CALLBACK (on_gl_surface_xevent),
|
||||
context,
|
||||
G_CONNECT_SWAPPED);
|
||||
g_signal_connect_object (G_OBJECT (surface),
|
||||
"notify::state",
|
||||
G_CALLBACK (on_surface_state_changed),
|
||||
context,
|
||||
G_CONNECT_SWAPPED);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+16
-6
@@ -2241,12 +2241,23 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
{
|
||||
GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
|
||||
GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node);
|
||||
float progress = gsk_cross_fade_node_get_progress (node);
|
||||
const float progress = gsk_cross_fade_node_get_progress (node);
|
||||
TextureRegion start_region;
|
||||
TextureRegion end_region;
|
||||
gboolean is_offscreen1, is_offscreen2;
|
||||
OpCrossFade *op;
|
||||
|
||||
if (progress <= 0)
|
||||
{
|
||||
gsk_gl_renderer_add_render_ops (self, start_node, builder);
|
||||
return;
|
||||
}
|
||||
else if (progress >= 1)
|
||||
{
|
||||
gsk_gl_renderer_add_render_ops (self, end_node, builder);
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
|
||||
@@ -2266,11 +2277,10 @@ render_cross_fade_node (GskGLRenderer *self,
|
||||
&end_region, &is_offscreen2,
|
||||
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY))
|
||||
{
|
||||
load_vertex_data_with_region (ops_draw (builder, NULL),
|
||||
node,
|
||||
builder,
|
||||
&start_region,
|
||||
TRUE);
|
||||
const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress);
|
||||
gsk_gl_renderer_add_render_ops (self, start_node, builder);
|
||||
ops_set_opacity (builder, prev_opacity);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+19
-19
@@ -104,7 +104,7 @@ gsk_color_node_peek_color (GskRenderNode *node)
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_color_node_new:
|
||||
* gsk_color_node_new:
|
||||
* @rgba: a #GdkRGBA specifying a color
|
||||
* @bounds: the rectangle to render the color into
|
||||
*
|
||||
@@ -216,7 +216,7 @@ gsk_linear_gradient_node_diff (GskRenderNode *node1,
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
}
|
||||
|
||||
@@ -1163,7 +1163,7 @@ gsk_inset_shadow_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_inset_shadow_node_new:
|
||||
* gsk_inset_shadow_node_new:
|
||||
* @outline: outline of the region containing the shadow
|
||||
* @color: color of the shadow
|
||||
* @dx: horizontal offset of shadow
|
||||
@@ -1465,7 +1465,7 @@ gsk_outset_shadow_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_outset_shadow_node_new:
|
||||
* gsk_outset_shadow_node_new:
|
||||
* @outline: outline of the region surrounded by shadow
|
||||
* @color: color of the shadow
|
||||
* @dx: horizontal offset of shadow
|
||||
@@ -1672,7 +1672,7 @@ gsk_cairo_node_peek_surface (GskRenderNode *node)
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_cairo_node_new:
|
||||
* gsk_cairo_node_new:
|
||||
* @bounds: the rectangle to render to
|
||||
*
|
||||
* Creates a #GskRenderNode that will render a cairo surface
|
||||
@@ -1982,7 +1982,7 @@ gsk_transform_node_draw (GskRenderNode *node,
|
||||
ctm.xy, ctm.yy,
|
||||
ctm.x0, ctm.y0));
|
||||
cairo_transform (cr, &ctm);
|
||||
|
||||
|
||||
gsk_render_node_draw (self->child, cr);
|
||||
}
|
||||
|
||||
@@ -2062,7 +2062,7 @@ gsk_transform_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_transform_node_new:
|
||||
* gsk_transform_node_new:
|
||||
* @child: The node to transform
|
||||
* @transform: (transfer none): The transform to apply
|
||||
*
|
||||
@@ -2188,7 +2188,7 @@ gsk_opacity_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_opacity_node_new:
|
||||
* gsk_opacity_node_new:
|
||||
* @child: The node to draw
|
||||
* @opacity: The opacity to apply
|
||||
*
|
||||
@@ -2380,7 +2380,7 @@ nope:
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_color_matrix_node_new:
|
||||
* gsk_color_matrix_node_new:
|
||||
* @child: The node to draw
|
||||
* @color_matrix: The matrix to apply
|
||||
* @color_offset: Values to add to the color
|
||||
@@ -2533,7 +2533,7 @@ gsk_repeat_node_draw (GskRenderNode *node,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_repeat_node_new:
|
||||
* gsk_repeat_node_new:
|
||||
* @bounds: The bounds of the area to be painted
|
||||
* @child: The child to repeat
|
||||
* @child_bounds: (allow-none): The area of the child to repeat or %NULL to
|
||||
@@ -2670,7 +2670,7 @@ gsk_clip_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_clip_node_new:
|
||||
* gsk_clip_node_new:
|
||||
* @child: The node to draw
|
||||
* @clip: The clip to apply
|
||||
*
|
||||
@@ -2800,7 +2800,7 @@ gsk_rounded_clip_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_rounded_clip_node_new:
|
||||
* gsk_rounded_clip_node_new:
|
||||
* @child: The node to draw
|
||||
* @clip: The clip to apply
|
||||
*
|
||||
@@ -3013,7 +3013,7 @@ gsk_shadow_node_get_bounds (GskShadowNode *self,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_shadow_node_new:
|
||||
* gsk_shadow_node_new:
|
||||
* @child: The node to draw
|
||||
* @shadows: (array length=n_shadows): The shadows to apply
|
||||
* @n_shadows: number of entries in the @shadows array
|
||||
@@ -3210,7 +3210,7 @@ gsk_blend_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_blend_node_new:
|
||||
* gsk_blend_node_new:
|
||||
* @bottom: The bottom node to be drawn
|
||||
* @top: The node to be blended onto the @bottom node
|
||||
* @blend_mode: The blend mode to use
|
||||
@@ -3359,7 +3359,7 @@ gsk_cross_fade_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_cross_fade_node_new:
|
||||
* gsk_cross_fade_node_new:
|
||||
* @start: The start node to be drawn
|
||||
* @end: The node to be cross_fadeed onto the @start node
|
||||
* @progress: How far the fade has progressed from start to end. The value will
|
||||
@@ -3549,7 +3549,7 @@ font_has_color_glyphs (const PangoFont *font)
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_text_node_new:
|
||||
* gsk_text_node_new:
|
||||
* @font: the #PangoFont containing the glyphs
|
||||
* @glyphs: the #PangoGlyphString to render
|
||||
* @color: the foreground color to render with
|
||||
@@ -3953,7 +3953,7 @@ gsk_blur_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_blur_node_new:
|
||||
* gsk_blur_node_new:
|
||||
* @child: the child node to blur
|
||||
* @radius: the blur radius
|
||||
*
|
||||
@@ -4076,9 +4076,9 @@ gsk_debug_node_diff (GskRenderNode *node1,
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_debug_node_new:
|
||||
* gsk_debug_node_new:
|
||||
* @child: The child to add debug info for
|
||||
* @message: (transfer full): The debug message
|
||||
* @message: (transfer full): The debug message
|
||||
*
|
||||
* Creates a #GskRenderNode that will add debug information about
|
||||
* the given @child.
|
||||
|
||||
+2
-1
@@ -123,7 +123,8 @@ gsk_transform_alloc (const GskTransformClass *transform_class,
|
||||
|
||||
self->transform_class = transform_class;
|
||||
self->category = next ? MIN (category, next->category) : category;
|
||||
self->next = gsk_transform_is_identity (next) ? NULL : next;
|
||||
self->next = gsk_transform_is_identity (next) ? NULL : gsk_transform_ref (next);
|
||||
g_clear_pointer (&next, gsk_transform_unref);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -295,7 +295,6 @@ gtk_cell_accessible_action_do_action (AtkAction *action,
|
||||
GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
|
||||
GtkCellAccessibleParent *parent;
|
||||
|
||||
cell = GTK_CELL_ACCESSIBLE (action);
|
||||
if (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ static gunichar
|
||||
gtk_password_entry_accessible_get_character_at_offset (AtkText *atk_text,
|
||||
gint offset)
|
||||
{
|
||||
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
|
||||
GtkText *text;
|
||||
char *contents, *index;
|
||||
gunichar result;
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@
|
||||
#include <gtk/gtkfontchooserdialog.h>
|
||||
#include <gtk/gtkfontchooserwidget.h>
|
||||
#include <gtk/gtkframe.h>
|
||||
#include <gtk/gtkfunctionslistitemfactory.h>
|
||||
#include <gtk/gtkgesture.h>
|
||||
#include <gtk/gtkgestureclick.h>
|
||||
#include <gtk/gtkgesturedrag.h>
|
||||
@@ -214,6 +213,7 @@
|
||||
#include <gtk/gtkscrolledwindow.h>
|
||||
#include <gtk/gtksearchbar.h>
|
||||
#include <gtk/gtksearchentry.h>
|
||||
#include <gtk/gtkselectionfiltermodel.h>
|
||||
#include <gtk/gtkselectionmodel.h>
|
||||
#include <gtk/gtkseparator.h>
|
||||
#include <gtk/gtksettings.h>
|
||||
@@ -247,6 +247,7 @@
|
||||
#include <gtk/gtkstringsorter.h>
|
||||
#include <gtk/gtkstylecontext.h>
|
||||
#include <gtk/gtkstyleprovider.h>
|
||||
#include <gtk/gtksuggestionentry.h>
|
||||
#include <gtk/gtkswitch.h>
|
||||
#include <gtk/gtktext.h>
|
||||
#include <gtk/gtktextbuffer.h>
|
||||
|
||||
+99
-7
@@ -193,12 +193,82 @@ gtk_bitset_get_maximum (const GtkBitset *self)
|
||||
return roaring_bitmap_maximum (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_size:
|
||||
* @self: a #GtkBitSet
|
||||
*
|
||||
* Gets the number of values that were added to the set.
|
||||
* For example, if the set is empty, 0 is returned.
|
||||
*
|
||||
* Note that this function returns a #guint64, because when all values are
|
||||
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set.
|
||||
**/
|
||||
guint64
|
||||
gtk_bitset_get_size (const GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return roaring_bitmap_get_cardinality (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_size_in_range:
|
||||
* @self: a #GtkBitSet
|
||||
* @first: the first element to include
|
||||
* @last: the last element to include
|
||||
*
|
||||
* Gets the number of values that are part of the set from @first to @last
|
||||
* (inclusive).
|
||||
*
|
||||
* Note that this function returns a #guint64, because when all values are
|
||||
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set from @first to @last.
|
||||
**/
|
||||
guint64
|
||||
gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
g_return_val_if_fail (last >= first, 0);
|
||||
|
||||
return roaring_bitmap_range_cardinality (&self->roaring, first, ((uint64_t) last) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_nth:
|
||||
* @self: a #GtkBitset
|
||||
* @nth: index of the item to get
|
||||
*
|
||||
* Returns the value of the @nth item in self.
|
||||
*
|
||||
* If @nth is >= the size of @self, 0 is returned.
|
||||
*
|
||||
* Returns: the value of the @nth item in @self
|
||||
**/
|
||||
guint
|
||||
gtk_bitset_get_nth (const GtkBitset *self,
|
||||
guint nth)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
if (!roaring_bitmap_select (&self->roaring, nth, &result))
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_new_empty:
|
||||
*
|
||||
* Creates a new empty bitset.
|
||||
*
|
||||
* Returns: A new empty bitset.
|
||||
* Returns: A new empty bitset
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_new_empty (void)
|
||||
@@ -214,6 +284,28 @@ gtk_bitset_new_empty (void)
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_new_range:
|
||||
* @start: first value to add
|
||||
* @n_items: number of consecutive values to add
|
||||
*
|
||||
* Creates a bitset with the given range set.
|
||||
*
|
||||
* Returns: A new bitset
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_new_range (guint start,
|
||||
guint n_items)
|
||||
{
|
||||
GtkBitset *self;
|
||||
|
||||
self = gtk_bitset_new_empty ();
|
||||
|
||||
gtk_bitset_add_range (self, start, n_items);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_copy:
|
||||
* @self: a #GtkBitset
|
||||
@@ -615,7 +707,7 @@ gtk_bitset_shift_right (GtkBitset *self,
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_slice:
|
||||
* gtk_bitset_splice:
|
||||
* @self: a #GtkBitset
|
||||
* @position: position at which to slice
|
||||
* @removed: number of values to remove
|
||||
@@ -633,10 +725,10 @@ gtk_bitset_shift_right (GtkBitset *self,
|
||||
* up space that can then be filled.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_slice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
gtk_bitset_splice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
/* overflow */
|
||||
@@ -650,7 +742,7 @@ gtk_bitset_slice (GtkBitset *self,
|
||||
GtkBitset *shift = gtk_bitset_copy (self);
|
||||
|
||||
gtk_bitset_remove_range (shift, 0, position);
|
||||
gtk_bitset_remove_range (self, position, G_MAXUINT - position + 1);
|
||||
gtk_bitset_remove_range_closed (self, position, G_MAXUINT);
|
||||
if (added > removed)
|
||||
gtk_bitset_shift_right (shift, added - removed);
|
||||
else
|
||||
|
||||
+13
-1
@@ -48,6 +48,15 @@ GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_equals (const GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint64 gtk_bitset_get_size (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint64 gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_nth (const GtkBitset *self,
|
||||
guint nth);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_minimum (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_maximum (const GtkBitset *self);
|
||||
@@ -56,6 +65,9 @@ GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_new_empty (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_copy (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_new_range (guint start,
|
||||
guint n_items);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_remove_all (GtkBitset *self);
|
||||
@@ -113,7 +125,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_shift_right (GtkBitset *self,
|
||||
guint amount);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_slice (GtkBitset *self,
|
||||
void gtk_bitset_splice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added);
|
||||
|
||||
@@ -369,6 +369,8 @@ gtk_bookmark_list_start_loading (GtkBookmarkList *self)
|
||||
self);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_strfreev (uris);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
/**
|
||||
* SECTION:gtkbuilderlistitemfactory
|
||||
* @Tiitle: GtkBuilderListItemFactory
|
||||
* @Title: GtkBuilderListItemFactory
|
||||
* @Short_description: A listitem factory using ui files
|
||||
*
|
||||
* #GtkBuilderListItemFactory is a #GtkListItemFactory that creates
|
||||
|
||||
+2
-2
@@ -940,7 +940,7 @@ header_drag_end (GtkGestureDrag *gesture,
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (header), "dnd");
|
||||
gtk_widget_remove_css_class (header, "dnd");
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
|
||||
@@ -1027,7 +1027,7 @@ header_drag_update (GtkGestureDrag *gesture,
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
|
||||
gtk_widget_insert_after (header, self->header, gtk_widget_get_last_child (self->header));
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (header), "dnd");
|
||||
gtk_widget_add_css_class (header, "dnd");
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
if (!gtk_widget_has_focus (GTK_WIDGET (self)))
|
||||
|
||||
+17
-18
@@ -562,10 +562,12 @@ css_provider_commit (GtkCssProvider *css_provider,
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
{
|
||||
for (i = 0; i < n_selectors; i++)
|
||||
_gtk_css_selector_free (selectors[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_selectors; i ++)
|
||||
for (i = 0; i < n_selectors; i++)
|
||||
{
|
||||
GtkCssRuleset *new;
|
||||
|
||||
@@ -768,7 +770,11 @@ parse_selector_list (GtkCssScanner *scanner,
|
||||
GtkCssSelector *select = _gtk_css_selector_parse (scanner->parser);
|
||||
|
||||
if (select == NULL)
|
||||
return 0;
|
||||
{
|
||||
for (int i = 0; i < n_selectors; i++)
|
||||
g_clear_pointer (&out_selectors[i], _gtk_css_selector_free);
|
||||
return 0;
|
||||
}
|
||||
|
||||
out_selectors[n_selectors] = select;
|
||||
n_selectors++;
|
||||
@@ -778,6 +784,8 @@ parse_selector_list (GtkCssScanner *scanner,
|
||||
gtk_css_parser_error_syntax (scanner->parser,
|
||||
"Only %u selectors per ruleset allowed",
|
||||
MAX_SELECTOR_LIST_LENGTH);
|
||||
for (int i = 0; i < MAX_SELECTOR_LIST_LENGTH; i++)
|
||||
g_clear_pointer (&out_selectors[i], _gtk_css_selector_free);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -806,10 +814,7 @@ parse_declaration (GtkCssScanner *scanner,
|
||||
|
||||
name = gtk_css_parser_consume_ident (scanner->parser);
|
||||
if (name == NULL)
|
||||
{
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
return;
|
||||
}
|
||||
goto out;
|
||||
|
||||
property = _gtk_style_property_lookup (name);
|
||||
|
||||
@@ -821,25 +826,18 @@ parse_declaration (GtkCssScanner *scanner,
|
||||
if (!gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COLON))
|
||||
{
|
||||
gtk_css_parser_error_syntax (scanner->parser, "Expected ':'");
|
||||
g_free (name);
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
value = _gtk_style_property_parse_value (property,
|
||||
scanner->parser);
|
||||
value = _gtk_style_property_parse_value (property, scanner->parser);
|
||||
|
||||
if (value == NULL)
|
||||
{
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
return;
|
||||
}
|
||||
goto out;
|
||||
|
||||
if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
|
||||
{
|
||||
gtk_css_parser_error_syntax (scanner->parser, "Junk at end of value for %s", property->name);
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gtk_keep_css_sections)
|
||||
@@ -884,6 +882,7 @@ parse_declaration (GtkCssScanner *scanner,
|
||||
gtk_css_parser_error_value (scanner->parser, "No property named \"%s\"", name);
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (name);
|
||||
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
@@ -918,7 +917,7 @@ parse_ruleset (GtkCssScanner *scanner)
|
||||
{
|
||||
guint i;
|
||||
gtk_css_parser_error_syntax (scanner->parser, "Expected '{' after selectors");
|
||||
for (i = 0; i < n_selectors; i ++)
|
||||
for (i = 0; i < n_selectors; i++)
|
||||
_gtk_css_selector_free (selectors[i]);
|
||||
gtk_css_parser_skip_until (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
|
||||
gtk_css_parser_skip (scanner->parser);
|
||||
|
||||
@@ -321,7 +321,7 @@ gtk_custom_paper_unix_dialog_init (GtkCustomPaperUnixDialog *dialog)
|
||||
g_list_store_append (printer_list_list, printer_list);
|
||||
g_object_unref (printer_list);
|
||||
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PRINTER, G_LIST_MODEL (printer_list_list)));
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (printer_list_list)));
|
||||
g_object_unref (printer_list_list);
|
||||
|
||||
filter = gtk_custom_filter_new (match_func, NULL, NULL);
|
||||
|
||||
+229
-4
@@ -62,6 +62,7 @@ enum {
|
||||
PROP_IO_PRIORITY,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_LOADING,
|
||||
PROP_MONITORED,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@@ -70,8 +71,10 @@ struct _GtkDirectoryList
|
||||
GObject parent_instance;
|
||||
|
||||
char *attributes;
|
||||
int io_priority;
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
gboolean monitored;
|
||||
int io_priority;
|
||||
|
||||
GCancellable *cancellable;
|
||||
GError *error; /* Error while loading */
|
||||
@@ -147,13 +150,17 @@ gtk_directory_list_set_property (GObject *object,
|
||||
gtk_directory_list_set_io_priority (self, g_value_get_int (value));
|
||||
break;
|
||||
|
||||
case PROP_MONITORED:
|
||||
gtk_directory_list_set_monitored (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
gtk_directory_list_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
@@ -187,6 +194,10 @@ gtk_directory_list_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gtk_directory_list_is_loading (self));
|
||||
break;
|
||||
|
||||
case PROP_MONITORED:
|
||||
g_value_set_boolean (value, gtk_directory_list_get_monitored (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -204,12 +215,27 @@ gtk_directory_list_stop_loading (GtkDirectoryList *self)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void directory_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event,
|
||||
gpointer data);
|
||||
|
||||
static void
|
||||
gtk_directory_list_stop_monitoring (GtkDirectoryList *self)
|
||||
{
|
||||
if (self->monitor)
|
||||
g_signal_handlers_disconnect_by_func (self->monitor, directory_changed, self);
|
||||
g_clear_object (&self->monitor);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_directory_list_dispose (GObject *object)
|
||||
{
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (object);
|
||||
|
||||
gtk_directory_list_stop_loading (self);
|
||||
gtk_directory_list_stop_monitoring (self);
|
||||
|
||||
g_clear_object (&self->file);
|
||||
g_clear_pointer (&self->attributes, g_free);
|
||||
@@ -301,6 +327,18 @@ gtk_directory_list_class_init (GtkDirectoryListClass *class)
|
||||
FALSE,
|
||||
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkDirectoryList:monitored:
|
||||
*
|
||||
* %TRUE if the directory is monitored for changed
|
||||
*/
|
||||
properties[PROP_MONITORED] =
|
||||
g_param_spec_boolean ("monitored",
|
||||
P_("monitored"),
|
||||
P_("TRUE if the directory is monitored for changes"),
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
@@ -309,6 +347,7 @@ gtk_directory_list_init (GtkDirectoryList *self)
|
||||
{
|
||||
self->items = g_sequence_new (g_object_unref);
|
||||
self->io_priority = G_PRIORITY_DEFAULT;
|
||||
self->monitored = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,7 +363,6 @@ gtk_directory_list_init (GtkDirectoryList *self)
|
||||
GtkDirectoryList *
|
||||
gtk_directory_list_new (const char *attributes,
|
||||
GFile *file)
|
||||
|
||||
{
|
||||
g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
|
||||
|
||||
@@ -410,7 +448,7 @@ gtk_directory_list_got_files_cb (GObject *source,
|
||||
{
|
||||
GFileInfo *info;
|
||||
GFile *file;
|
||||
|
||||
|
||||
info = l->data;
|
||||
file = g_file_enumerator_get_child (enumerator, info);
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
@@ -496,6 +534,143 @@ gtk_directory_list_start_loading (GtkDirectoryList *self)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
|
||||
static void
|
||||
got_new_file_info_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GFile *file = G_FILE (source);
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
GFileInfo *info;
|
||||
guint position;
|
||||
|
||||
info = g_file_query_info_finish (file, res, NULL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
position = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, info);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
got_existing_file_info_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GFile *file = G_FILE (source);
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
GFileInfo *info;
|
||||
GSequenceIter *iter;
|
||||
|
||||
info = g_file_query_info_finish (file, res, NULL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (self->items);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
GFileInfo *item = g_sequence_get (iter);
|
||||
GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
|
||||
if (g_file_equal (f, file))
|
||||
{
|
||||
guint position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_set (iter, g_object_ref (info));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_directory_list_remove_file (GtkDirectoryList *self,
|
||||
GFile *file)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (self->items);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
GFileInfo *item = g_sequence_get (iter);
|
||||
GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
|
||||
if (g_file_equal (f, file))
|
||||
{
|
||||
guint position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_remove (iter);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
directory_changed (GFileMonitor *monitor,
|
||||
GFile *file,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
switch (event)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
g_file_query_info_async (file,
|
||||
self->attributes,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
self->io_priority,
|
||||
self->cancellable,
|
||||
got_new_file_info_cb,
|
||||
self);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
gtk_directory_list_remove_file (self, file);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
||||
g_file_query_info_async (file,
|
||||
self->attributes,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
self->io_priority,
|
||||
self->cancellable,
|
||||
got_existing_file_info_cb,
|
||||
self);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_CHANGED:
|
||||
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
||||
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
|
||||
case G_FILE_MONITOR_EVENT_UNMOUNTED:
|
||||
case G_FILE_MONITOR_EVENT_MOVED:
|
||||
case G_FILE_MONITOR_EVENT_RENAMED:
|
||||
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
||||
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_directory_list_start_monitoring (GtkDirectoryList *self)
|
||||
{
|
||||
g_assert (self->monitor == NULL);
|
||||
self->monitor = g_file_monitor_directory (self->file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
g_signal_connect (self->monitor, "changed", G_CALLBACK (directory_changed), self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_directory_list_update_monitoring (GtkDirectoryList *self)
|
||||
{
|
||||
gtk_directory_list_stop_monitoring (self);
|
||||
if (self->file && self->monitored)
|
||||
gtk_directory_list_start_monitoring (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_directory_list_set_file:
|
||||
* @self: a #GtkDirectoryList
|
||||
@@ -520,6 +695,7 @@ gtk_directory_list_set_file (GtkDirectoryList *self,
|
||||
|
||||
g_set_object (&self->file, file);
|
||||
|
||||
gtk_directory_list_update_monitoring (self);
|
||||
gtk_directory_list_start_loading (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]);
|
||||
@@ -679,3 +855,52 @@ gtk_directory_list_get_error (GtkDirectoryList *self)
|
||||
return self->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_directory_list_set_monitored:
|
||||
* @self: a #GtkDirectoryList
|
||||
* @monitored: %TRUE to monitor the directory for changes
|
||||
*
|
||||
* Sets whether the directory list will monitor the directory
|
||||
* for changes. If monitoring is enabled, the
|
||||
* #GListModel::items-changed signal will be emitted when the
|
||||
* directory contents change.
|
||||
*
|
||||
* When monitoring is turned on after the initial creation
|
||||
* of the directory list, the directory is reloaded to avoid
|
||||
* missing files that appeared between the initial loading
|
||||
* and when monitoring was turned on.
|
||||
*/
|
||||
void
|
||||
gtk_directory_list_set_monitored (GtkDirectoryList *self,
|
||||
gboolean monitored)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DIRECTORY_LIST (self));
|
||||
|
||||
if (self->monitored == monitored)
|
||||
return;
|
||||
|
||||
self->monitored = monitored;
|
||||
|
||||
gtk_directory_list_update_monitoring (self);
|
||||
if (monitored)
|
||||
gtk_directory_list_start_loading (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MONITORED]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_directory_list_get_monitored:
|
||||
* @self: a #GtkDirectoryList
|
||||
*
|
||||
* Returns whether the directory list is monitoring
|
||||
* the directory for changes.
|
||||
*
|
||||
* Returns: %TRUE if the directory is monitored
|
||||
*/
|
||||
gboolean
|
||||
gtk_directory_list_get_monitored (GtkDirectoryList *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_DIRECTORY_LIST (self), TRUE);
|
||||
|
||||
return self->monitored;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,12 @@ gboolean gtk_directory_list_is_loading (GtkDirectoryLis
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const GError * gtk_directory_list_get_error (GtkDirectoryList *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_directory_list_set_monitored (GtkDirectoryList *self,
|
||||
gboolean monitored);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_directory_list_get_monitored (GtkDirectoryList *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DIRECTORY_LIST_H__ */
|
||||
|
||||
@@ -224,7 +224,7 @@ gtk_drop_controller_motion_class_init (GtkDropControllerMotionClass *klass)
|
||||
props[PROP_CONTAINS_POINTER] =
|
||||
g_param_spec_boolean ("contains-pointer",
|
||||
P_("Contains Pointer"),
|
||||
P_("Whether the pointer is inthe controllers widget or a descendant"),
|
||||
P_("Whether the pointer is in the controllers widget or a descendant"),
|
||||
FALSE,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
|
||||
+2
-2
@@ -927,7 +927,7 @@ gtk_drop_down_get_expression (GtkDropDown *self)
|
||||
/**
|
||||
* gtk_drop_down_set_from_strings:
|
||||
* @self: a #GtkDropDown
|
||||
* @texts: a %NULL-terminated string array
|
||||
* @texts: (array zero-terminated=1) (element-type utf8): a %NULL-terminated string array
|
||||
*
|
||||
* Populates @self with the strings in @text,
|
||||
* by creating a suitable model and factory.
|
||||
@@ -943,7 +943,7 @@ gtk_drop_down_set_from_strings (GtkDropDown *self,
|
||||
|
||||
set_default_factory (self);
|
||||
|
||||
model = G_LIST_MODEL (gtk_string_list_new ((const char **)texts));
|
||||
model = G_LIST_MODEL (gtk_string_list_new (texts));
|
||||
gtk_drop_down_set_model (self, model);
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
|
||||
props[PROP_CONTAINS_POINTER] =
|
||||
g_param_spec_boolean ("contains-pointer",
|
||||
P_("Contains Pointer"),
|
||||
P_("Whether the pointer is inthe controllers widget or a descendant"),
|
||||
P_("Whether the pointer is in the controllers widget or a descendant"),
|
||||
FALSE,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
|
||||
+44
-11
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
@@ -28,18 +29,50 @@
|
||||
* @Short_description: Expressions to values
|
||||
* @Title: GtkExpression
|
||||
*
|
||||
* GtkExpression provides a way to describe references to #GValues.
|
||||
* GtkExpression provides a way to describe references to values.
|
||||
*
|
||||
* An expression needs to be "evaluated" to obtain the value that it currently refers
|
||||
* to. An evaluation always happens in the context of a current object called `this`
|
||||
* (it mirrors the behavior of object-oriented languages), which may or may not
|
||||
* influence the result of the evaluation. Use gtk_expression_evaluate() for
|
||||
* evaluating an expression.
|
||||
* An important aspect of expressions is that the value can be obtained
|
||||
* from a source that is several steps away. For example, an expression
|
||||
* may describe ‘the value of property A of @object1, which is itself the
|
||||
* value of a property of @object2’. And @object1 may not even exist yet
|
||||
* at the time that the expression is created. This is contrast to GObject
|
||||
* property bindings, which can only create direct connections between
|
||||
* the properties of two objects that must both exist for the duration
|
||||
* of the binding.
|
||||
*
|
||||
* An expression needs to be "evaluated" to obtain the value that it currently
|
||||
* refers to. An evaluation always happens in the context of a current object
|
||||
* called `this` (it mirrors the behavior of object-oriented languages),
|
||||
* which may or may not influence the result of the evaluation. Use
|
||||
* gtk_expression_evaluate() for evaluating an expression.
|
||||
*
|
||||
* Various methods for defining expressions exist, from simple constants via
|
||||
* gtk_constant_expression_new() to looking up properties in a #GObject (even
|
||||
* recursively) via gtk_property_expression_new() or providing custom functions to
|
||||
* transform and combine expressions via gtk_closure_expression_new().
|
||||
* recursively) via gtk_property_expression_new() or providing custom functions
|
||||
* to transform and combine expressions via gtk_closure_expression_new().
|
||||
*
|
||||
* Here is an example of a complex expression:
|
||||
* |[
|
||||
* color_expr = gtk_property_expression_new (GTK_TYPE_LIST_ITEM,
|
||||
* NULL, "item");
|
||||
* expression = gtk_property_expression_new (GTK_TYPE_COLOR,
|
||||
* color_expr,
|
||||
* "name");
|
||||
* ]|
|
||||
* when evaluated with `this` being a GtkListItem, it will obtain the
|
||||
* "item" property from the GtkListItem, and then obtain the "name" property
|
||||
* from the resulting object (which is assumed to be of type GTK_TYPE_COLOR).
|
||||
*
|
||||
* A more concise way to describe this would be
|
||||
* |[
|
||||
* this->item->name
|
||||
* ]|
|
||||
*
|
||||
* The most likely place where you will encounter expressions is in the context
|
||||
* of list models and list widgets using them. For example, #GtkDropDown is
|
||||
* evaluating a GtkExpression to obtain strings from the items in its model
|
||||
* that it can then use to match against the contents of its search entry.
|
||||
* #GtkStringFilter is using a GtkExpression for a similar reason.
|
||||
*
|
||||
* By default, expressions are not paying attention to changes and evaluation is
|
||||
* just a snapshot of the current state at a given time. To get informed about
|
||||
@@ -1537,12 +1570,12 @@ GTK_DEFINE_EXPRESSION_TYPE (GtkCClosureExpression,
|
||||
/**
|
||||
* gtk_cclosure_expression_new:
|
||||
* @value_type: the type of the value that this expression evaluates to
|
||||
* @marshal: (scope call): marshaller used for creating a closure
|
||||
* @marshal: (scope call) (nullable): marshaller used for creating a closure
|
||||
* @n_params: the number of params needed for evaluating @closure
|
||||
* @params: (array length=n_params) (transfer full): expressions for each parameter
|
||||
* @callback_func: (scope notified) (closure user_data) (destroy user_destroy): callback used for creating a closure
|
||||
* @user_data: user data used for creating a closure
|
||||
* @user_destroy: destroy notify for @user_data
|
||||
* @user_data: (nullable): user data used for creating a closure
|
||||
* @user_destroy: (nullable): destroy notify for @user_data
|
||||
*
|
||||
* This function is a variant of gtk_closure_expression_new() that
|
||||
* creates a #GClosure by calling gtk_cclosure_new() with the given
|
||||
|
||||
+63
-102
@@ -79,75 +79,6 @@ G_DEFINE_INTERFACE (GtkFileChooser, gtk_file_chooser, G_TYPE_OBJECT);
|
||||
static void
|
||||
gtk_file_chooser_default_init (GtkFileChooserInterface *iface)
|
||||
{
|
||||
GType iface_type = G_TYPE_FROM_INTERFACE (iface);
|
||||
|
||||
/**
|
||||
* GtkFileChooser::current-folder-changed:
|
||||
* @chooser: the object which received the signal.
|
||||
*
|
||||
* This signal is emitted when the current folder in a #GtkFileChooser
|
||||
* changes. This can happen due to the user performing some action that
|
||||
* changes folders, such as selecting a bookmark or visiting a folder on the
|
||||
* file list. It can also happen as a result of calling a function to
|
||||
* explicitly change the current folder in a file chooser.
|
||||
*
|
||||
* Normally you do not need to connect to this signal, unless you need to keep
|
||||
* track of which folder a file chooser is showing.
|
||||
*
|
||||
* See also: gtk_file_chooser_set_current_folder(),
|
||||
* gtk_file_chooser_get_current_folder(),
|
||||
*/
|
||||
g_signal_new (I_("current-folder-changed"),
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkFileChooserIface, current_folder_changed),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* GtkFileChooser::selection-changed:
|
||||
* @chooser: the object which received the signal.
|
||||
*
|
||||
* This signal is emitted when there is a change in the set of selected files
|
||||
* in a #GtkFileChooser. This can happen when the user modifies the selection
|
||||
* with the mouse or the keyboard, or when explicitly calling functions to
|
||||
* change the selection.
|
||||
*
|
||||
* Normally you do not need to connect to this signal, as it is easier to wait
|
||||
* for the file chooser to finish running, and then to get the list of
|
||||
* selected files using the functions mentioned below.
|
||||
*/
|
||||
g_signal_new (I_("selection-changed"),
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkFileChooserIface, selection_changed),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* GtkFileChooser::file-activated:
|
||||
* @chooser: the object which received the signal.
|
||||
*
|
||||
* This signal is emitted when the user "activates" a file in the file
|
||||
* chooser. This can happen by double-clicking on a file in the file list, or
|
||||
* by pressing `Enter`.
|
||||
*
|
||||
* Normally you do not need to connect to this signal. It is used internally
|
||||
* by #GtkFileChooserDialog to know when to activate the default button in the
|
||||
* dialog.
|
||||
*
|
||||
* See also: gtk_file_chooser_get_file(), gtk_file_chooser_get_files()
|
||||
*/
|
||||
g_signal_new (I_("file-activated"),
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkFileChooserIface, file_activated),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_enum ("action",
|
||||
P_("Action"),
|
||||
@@ -168,6 +99,38 @@ gtk_file_chooser_default_init (GtkFileChooserInterface *iface)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:filters:
|
||||
*
|
||||
* A #GListModel containing the filters that have been
|
||||
* added with gtk_file_chooser_add_filter().
|
||||
*
|
||||
* The returned object should not be modified. It may
|
||||
* or may not be updated for later changes.
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_object ("filters",
|
||||
P_("Filters"),
|
||||
P_("List model of filters"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:shortcut-folders:
|
||||
*
|
||||
* A #GListModel containing the shortcut folders that have been
|
||||
* added with gtk_file_chooser_add_shortcut().
|
||||
*
|
||||
* The returned object should not be modified. It may
|
||||
* or may not be updated for later changes.
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_object ("shortcut-folders",
|
||||
P_("Shortcut Folders"),
|
||||
P_("List model of shortcut folders"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:create-folders:
|
||||
*
|
||||
@@ -476,16 +439,15 @@ gtk_file_chooser_unselect_file (GtkFileChooser *chooser,
|
||||
/**
|
||||
* gtk_file_chooser_get_files:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Lists all the selected files and subfolders in the current folder of @chooser
|
||||
* as #GFile.
|
||||
*
|
||||
* Returns: (element-type GFile) (transfer full): a list
|
||||
* containing a #GFile for each selected file and subfolder in the
|
||||
* current folder. Free the returned list with g_slist_free(), and
|
||||
* the files with g_object_unref().
|
||||
**/
|
||||
GSList *
|
||||
* Lists all the selected files and subfolders in the current folder
|
||||
* of @chooser as #GFile.
|
||||
*
|
||||
* Returns: (transfer full): a list model containing a #GFile for each
|
||||
* selected file and subfolder in the current folder. Free the returned
|
||||
* list with g_object_unref().
|
||||
*/
|
||||
GListModel *
|
||||
gtk_file_chooser_get_files (GtkFileChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
@@ -565,19 +527,15 @@ gtk_file_chooser_set_file (GtkFileChooser *chooser,
|
||||
GFile *
|
||||
gtk_file_chooser_get_file (GtkFileChooser *chooser)
|
||||
{
|
||||
GSList *list;
|
||||
GListModel *list;
|
||||
GFile *result = NULL;
|
||||
|
||||
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
list = gtk_file_chooser_get_files (chooser);
|
||||
if (list)
|
||||
{
|
||||
result = list->data;
|
||||
list = g_slist_delete_link (list, list);
|
||||
|
||||
g_slist_free_full (list, g_object_unref);
|
||||
}
|
||||
if (g_list_model_get_n_items (list) > 0)
|
||||
result = g_list_model_get_item (list, 0);
|
||||
g_object_unref (list);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -682,23 +640,24 @@ gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_file_chooser_list_filters:
|
||||
* gtk_file_chooser_get_filters:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Lists the current set of user-selectable filters; see
|
||||
* Gets the current set of user-selectable filters, as a list model; see
|
||||
* gtk_file_chooser_add_filter(), gtk_file_chooser_remove_filter().
|
||||
*
|
||||
* Returns: (element-type GtkFileFilter) (transfer container): a
|
||||
* #GSList containing the current set of user selectable filters. The
|
||||
* contents of the list are owned by GTK+, but you must free the list
|
||||
* itself with g_slist_free() when you are done with it.
|
||||
* You should not modify the returned list model. Future changes to
|
||||
* @chooser may or may not affect the returned model.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel containing the current set
|
||||
* of user-selectable filters.
|
||||
**/
|
||||
GSList *
|
||||
gtk_file_chooser_list_filters (GtkFileChooser *chooser)
|
||||
GListModel *
|
||||
gtk_file_chooser_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_filters (chooser);
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_filters (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,21 +709,23 @@ gtk_file_chooser_get_filter (GtkFileChooser *chooser)
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_file_chooser_list_shortcut_folders:
|
||||
* gtk_file_chooser_get_shortcut_folders:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Queries the list of shortcut folders in the file chooser, as set by
|
||||
* gtk_file_chooser_add_shortcut_folder().
|
||||
*
|
||||
* Returns: (nullable) (element-type Gio.File) (transfer full): A list
|
||||
* of folder filenames, or %NULL if there are no shortcut folders.
|
||||
* You should not modify the returned list model. Future changes to
|
||||
* @chooser may or may not affect the returned model.
|
||||
*
|
||||
* Returns: (transfer full): A list model of #GFiles
|
||||
*/
|
||||
GSList *
|
||||
gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
GListModel *
|
||||
gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_shortcut_folders (chooser);
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_shortcut_folders (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+61
-68
@@ -72,7 +72,8 @@ GType gtk_file_chooser_get_type (void) G_GNUC_CONST;
|
||||
* @GTK_FILE_CHOOSER_ERROR_BAD_FILENAME: Indicates a malformed filename.
|
||||
* @GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS: Indicates a duplicate path (e.g. when
|
||||
* adding a bookmark).
|
||||
* @GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME: Indicates an incomplete hostname (e.g. "http://foo" without a slash after that).
|
||||
* @GTK_FILE_CHOOSER_ERROR_INCOMPLETE_HOSTNAME: Indicates an incomplete hostname
|
||||
* (e.g. "http://foo" without a slash after that).
|
||||
*
|
||||
* These identify the various errors that can occur while calling
|
||||
* #GtkFileChooser functions.
|
||||
@@ -87,108 +88,100 @@ typedef enum {
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GQuark gtk_file_chooser_error_quark (void);
|
||||
|
||||
/* Configuration
|
||||
*/
|
||||
/* Configuration */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_action (GtkFileChooser *chooser,
|
||||
GtkFileChooserAction action);
|
||||
GtkFileChooserAction action);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileChooserAction gtk_file_chooser_get_action (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_select_multiple (GtkFileChooser *chooser,
|
||||
gboolean select_multiple);
|
||||
gboolean select_multiple);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_get_select_multiple (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser,
|
||||
gboolean create_folders);
|
||||
gboolean create_folders);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_get_create_folders (GtkFileChooser *chooser);
|
||||
gboolean gtk_file_chooser_get_create_folders (GtkFileChooser *chooser);
|
||||
|
||||
/* Suggested name for the Save-type actions
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_current_name (GtkFileChooser *chooser,
|
||||
const gchar *name);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gchar *gtk_file_chooser_get_current_name (GtkFileChooser *chooser);
|
||||
/* Suggested name for the Save-type actions */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_select_all (GtkFileChooser *chooser);
|
||||
void gtk_file_chooser_set_current_name (GtkFileChooser *chooser,
|
||||
const char *name);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_unselect_all (GtkFileChooser *chooser);
|
||||
char * gtk_file_chooser_get_current_name (GtkFileChooser *chooser);
|
||||
|
||||
/* GFile manipulation */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GFile * gtk_file_chooser_get_file (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_set_file (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_select_file (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_unselect_file (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GSList * gtk_file_chooser_get_files (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_set_current_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GFile * gtk_file_chooser_get_current_folder (GtkFileChooser *chooser);
|
||||
|
||||
/* List of user selectable filters
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GFile * gtk_file_chooser_get_file (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
gboolean gtk_file_chooser_set_file (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GSList *gtk_file_chooser_list_filters (GtkFileChooser *chooser);
|
||||
GListModel * gtk_file_chooser_get_files (GtkFileChooser *chooser);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_set_current_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GFile * gtk_file_chooser_get_current_folder (GtkFileChooser *chooser);
|
||||
|
||||
/* List of user selectable filters */
|
||||
|
||||
/* Current filter
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
void gtk_file_chooser_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser);
|
||||
void gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_file_chooser_get_filters (GtkFileChooser *chooser);
|
||||
|
||||
/* Current filter */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter * gtk_file_chooser_get_filter (GtkFileChooser *chooser);
|
||||
|
||||
/* Per-application shortcut folders */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
gboolean gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
gboolean gtk_file_chooser_remove_shortcut_folder
|
||||
(GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GSList *gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
GListModel * gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
|
||||
/* Custom widgets */
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_add_choice (GtkFileChooser *chooser,
|
||||
const char *id,
|
||||
const char *label,
|
||||
const char **options,
|
||||
const char **option_labels);
|
||||
void gtk_file_chooser_add_choice (GtkFileChooser *chooser,
|
||||
const char *id,
|
||||
const char *label,
|
||||
const char **options,
|
||||
const char **option_labels);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_remove_choice (GtkFileChooser *chooser,
|
||||
const char *id);
|
||||
void gtk_file_chooser_remove_choice (GtkFileChooser *chooser,
|
||||
const char *id);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_choice (GtkFileChooser *chooser,
|
||||
const char *id,
|
||||
const char *option);
|
||||
void gtk_file_chooser_set_choice (GtkFileChooser *chooser,
|
||||
const char *id,
|
||||
const char *option);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char *gtk_file_chooser_get_choice (GtkFileChooser *chooser,
|
||||
const char *id);
|
||||
const char * gtk_file_chooser_get_choice (GtkFileChooser *chooser,
|
||||
const char *id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+13
-11
@@ -244,7 +244,7 @@ static gboolean gtk_file_chooser_button_select_file (GtkFileChooser *chooser,
|
||||
static void gtk_file_chooser_button_unselect_file (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
static void gtk_file_chooser_button_unselect_all (GtkFileChooser *chooser);
|
||||
static GSList *gtk_file_chooser_button_get_files (GtkFileChooser *chooser);
|
||||
static GListModel *gtk_file_chooser_button_get_files (GtkFileChooser *chooser);
|
||||
static gboolean gtk_file_chooser_button_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
@@ -627,7 +627,6 @@ emit_selection_changed_if_changing_selection (GtkFileChooserButton *button)
|
||||
if (button->is_changing_selection)
|
||||
{
|
||||
button->is_changing_selection = FALSE;
|
||||
g_signal_emit_by_name (button, "selection-changed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,8 +644,6 @@ gtk_file_chooser_button_set_current_folder (GtkFileChooser *chooser,
|
||||
|
||||
update_combo_box (button);
|
||||
|
||||
g_signal_emit_by_name (button, "current-folder-changed");
|
||||
|
||||
if (button->active)
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (button->chooser), file, NULL);
|
||||
|
||||
@@ -750,17 +747,23 @@ get_selected_file (GtkFileChooserButton *button)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
static GListModel *
|
||||
gtk_file_chooser_button_get_files (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (chooser);
|
||||
GFile *file;
|
||||
GListStore *store;
|
||||
|
||||
store = g_list_store_new (G_TYPE_FILE);
|
||||
|
||||
file = get_selected_file (button);
|
||||
if (file)
|
||||
return g_slist_prepend (NULL, file);
|
||||
else
|
||||
return NULL;
|
||||
{
|
||||
g_list_store_append (store, file);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1035,6 +1038,8 @@ gtk_file_chooser_button_get_property (GObject *object,
|
||||
case GTK_FILE_CHOOSER_PROP_FILTER:
|
||||
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
|
||||
case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
|
||||
case GTK_FILE_CHOOSER_PROP_FILTERS:
|
||||
case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS:
|
||||
g_object_get_property (G_OBJECT (button->chooser), pspec->name, value);
|
||||
break;
|
||||
|
||||
@@ -2510,9 +2515,6 @@ common_response_cb (GtkFileChooserButton *button,
|
||||
response == GTK_RESPONSE_OK)
|
||||
{
|
||||
save_inactive_state (button);
|
||||
|
||||
g_signal_emit_by_name (button, "current-folder-changed");
|
||||
g_signal_emit_by_name (button, "selection-changed");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -265,12 +265,8 @@ static void gtk_file_chooser_dialog_size_allocate (GtkWidget *wid
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
static void file_chooser_widget_file_activated (GtkFileChooser *chooser,
|
||||
GtkFileChooserDialog *dialog);
|
||||
static void file_chooser_widget_response_requested (GtkWidget *widget,
|
||||
GtkFileChooserDialog *dialog);
|
||||
static void file_chooser_widget_selection_changed (GtkWidget *widget,
|
||||
GtkFileChooserDialog *dialog);
|
||||
|
||||
static void response_cb (GtkDialog *dialog,
|
||||
gint response_id);
|
||||
@@ -310,9 +306,7 @@ gtk_file_chooser_dialog_class_init (GtkFileChooserDialogClass *class)
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserDialog, widget);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserDialog, buttons);
|
||||
gtk_widget_class_bind_template_callback (widget_class, response_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_chooser_widget_file_activated);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_chooser_widget_response_requested);
|
||||
gtk_widget_class_bind_template_callback (widget_class, file_chooser_widget_selection_changed);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -367,34 +361,6 @@ is_accept_response_id (gint response_id)
|
||||
response_id == GTK_RESPONSE_APPLY);
|
||||
}
|
||||
|
||||
/* Callback used when the user activates a file in the file chooser widget */
|
||||
static void
|
||||
file_chooser_widget_file_activated (GtkFileChooser *chooser,
|
||||
GtkFileChooserDialog *dialog)
|
||||
{
|
||||
gtk_widget_activate_default (GTK_WIDGET (chooser));
|
||||
}
|
||||
|
||||
static void
|
||||
file_chooser_widget_selection_changed (GtkWidget *widget,
|
||||
GtkFileChooserDialog *dialog)
|
||||
{
|
||||
GtkFileChooserDialogPrivate *priv = gtk_file_chooser_dialog_get_instance_private (dialog);
|
||||
GtkWidget *button;
|
||||
GSList *files;
|
||||
gboolean sensitive;
|
||||
|
||||
button = get_accept_action_widget (GTK_DIALOG (dialog), FALSE);
|
||||
if (button == NULL)
|
||||
return;
|
||||
|
||||
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (priv->widget));
|
||||
sensitive = (files != NULL);
|
||||
gtk_widget_set_sensitive (button, sensitive);
|
||||
|
||||
g_slist_free_full (files, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
file_chooser_widget_response_requested (GtkWidget *widget,
|
||||
GtkFileChooserDialog *dialog)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkfilefilterprivate.h"
|
||||
#include "gtkfilter.h"
|
||||
#include "gtkeventcontrollerfocus.h"
|
||||
|
||||
typedef struct _GtkFileChooserEntryClass GtkFileChooserEntryClass;
|
||||
@@ -194,65 +195,22 @@ match_func (GtkEntryCompletion *compl,
|
||||
* current file filter (e.g. just jpg files) here. */
|
||||
if (chooser_entry->current_filter != NULL)
|
||||
{
|
||||
char *mime_type = NULL;
|
||||
gboolean matches;
|
||||
GFile *file;
|
||||
GFileInfo *file_info;
|
||||
GtkFileFilterInfo filter_info;
|
||||
GtkFileFilterFlags needed_flags;
|
||||
GFileInfo *info;
|
||||
|
||||
file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
file_info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
|
||||
/* We always allow navigating into subfolders, so don't ever filter directories */
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR)
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
return TRUE;
|
||||
|
||||
needed_flags = gtk_file_filter_get_needed (chooser_entry->current_filter);
|
||||
if (!g_file_info_has_attribute (info, "standard::file"))
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
filter_info.display_name = g_file_info_get_display_name (file_info);
|
||||
filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_MIME_TYPE)
|
||||
{
|
||||
const char *s = g_file_info_get_content_type (file_info);
|
||||
if (s != NULL)
|
||||
{
|
||||
mime_type = g_content_type_get_mime_type (s);
|
||||
if (mime_type != NULL)
|
||||
{
|
||||
filter_info.mime_type = mime_type;
|
||||
filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_FILENAME)
|
||||
{
|
||||
const char *path = g_file_get_path (file);
|
||||
if (path != NULL)
|
||||
{
|
||||
filter_info.filename = path;
|
||||
filter_info.contains |= GTK_FILE_FILTER_FILENAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_URI)
|
||||
{
|
||||
const char *uri = g_file_get_uri (file);
|
||||
if (uri)
|
||||
{
|
||||
filter_info.uri = uri;
|
||||
filter_info.contains |= GTK_FILE_FILTER_URI;
|
||||
}
|
||||
}
|
||||
|
||||
matches = gtk_file_filter_filter (chooser_entry->current_filter, &filter_info);
|
||||
|
||||
g_free (mime_type);
|
||||
return matches;
|
||||
return gtk_filter_match (GTK_FILTER (chooser_entry->current_filter), info);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
+15
-24
@@ -158,21 +158,8 @@
|
||||
* possible to use with #GtkFileChooserNative, as such use would
|
||||
* prohibit the use of a native dialog.
|
||||
*
|
||||
* There is no support for the signals that are emitted when the user
|
||||
* navigates in the dialog, including:
|
||||
* * #GtkFileChooser::current-folder-changed
|
||||
* * #GtkFileChooser::selection-changed
|
||||
* * #GtkFileChooser::file-activated
|
||||
*
|
||||
* You can also not use the methods that directly control user navigation:
|
||||
* * gtk_file_chooser_unselect_filename()
|
||||
* * gtk_file_chooser_select_all()
|
||||
* * gtk_file_chooser_unselect_all()
|
||||
*
|
||||
* If you need any of the above you will have to use #GtkFileChooserDialog directly.
|
||||
*
|
||||
* No operations that change the dialog work while the dialog is visible. Set
|
||||
* all the properties that are required before showing the dialog.
|
||||
* No operations that change the dialog work while the dialog is visible.
|
||||
* Set all the properties that are required before showing the dialog.
|
||||
*
|
||||
* ## Win32 details ## {#gtkfilechooserdialognative-win32}
|
||||
*
|
||||
@@ -180,7 +167,7 @@
|
||||
* used. It supports many of the features that #GtkFileChooserDialog
|
||||
* does, but there are some things it does not handle:
|
||||
*
|
||||
* * Any #GtkFileFilter added using a mimetype or custom filter.
|
||||
* * Any #GtkFileFilter added using a mimetype
|
||||
*
|
||||
* If any of these features are used the regular #GtkFileChooserDialog
|
||||
* will be used in place of the native one.
|
||||
@@ -190,10 +177,7 @@
|
||||
* When the org.freedesktop.portal.FileChooser portal is available on the
|
||||
* session bus, it is used to bring up an out-of-process file chooser. Depending
|
||||
* on the kind of session the application is running in, this may or may not
|
||||
* be a GTK+ file chooser. In this situation, the following things are not
|
||||
* supported and will be silently ignored:
|
||||
*
|
||||
* * Any #GtkFileFilter added with a custom filter.
|
||||
* be a GTK file chooser.
|
||||
*
|
||||
* ## macOS details ## {#gtkfilechooserdialognative-macos}
|
||||
*
|
||||
@@ -201,8 +185,6 @@
|
||||
* file chooser dialogs. Some features provided by #GtkFileChooserDialog are
|
||||
* not supported:
|
||||
*
|
||||
* * Any #GtkFileFilter added with a custom filter.
|
||||
*
|
||||
* * Shortcut folders.
|
||||
*/
|
||||
|
||||
@@ -683,7 +665,7 @@ gtk_file_chooser_native_set_current_name (GtkFileChooser *chooser,
|
||||
g_clear_object (&self->current_file);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
static GListModel *
|
||||
gtk_file_chooser_native_get_files (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser);
|
||||
@@ -693,7 +675,16 @@ gtk_file_chooser_native_get_files (GtkFileChooser *chooser)
|
||||
case MODE_PORTAL:
|
||||
case MODE_WIN32:
|
||||
case MODE_QUARTZ:
|
||||
return g_slist_copy_deep (self->custom_files, (GCopyFunc)g_object_ref, NULL);
|
||||
{
|
||||
GListStore *store;
|
||||
GSList *l;
|
||||
|
||||
store = g_list_store_new (G_TYPE_FILE);
|
||||
for (l = self->custom_files; l; l = l->next)
|
||||
g_list_store_append (store, l->data);
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
case MODE_FALLBACK:
|
||||
default:
|
||||
|
||||
@@ -126,7 +126,7 @@ response_cb (GDBusConnection *connection,
|
||||
if (current_filter)
|
||||
{
|
||||
GtkFileFilter *filter = gtk_file_filter_new_from_gvariant (current_filter);
|
||||
const gchar *current_filter_name = gtk_file_filter_get_name (filter);
|
||||
const char *current_filter_name = gtk_file_filter_get_name (filter);
|
||||
|
||||
/* Try to find the given filter in the list of filters.
|
||||
* Since filters are compared by pointer value, using the passed
|
||||
@@ -137,18 +137,24 @@ response_cb (GDBusConnection *connection,
|
||||
* If there is no match, just set the filter as it was retrieved.
|
||||
*/
|
||||
GtkFileFilter *filter_to_select = filter;
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
for (GSList *l = filters; l; l = l->next)
|
||||
GListModel *filters;
|
||||
guint j, n;
|
||||
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
GtkFileFilter *f = l->data;
|
||||
GtkFileFilter *f = g_list_model_get_item (filters, j);
|
||||
if (g_strcmp0 (gtk_file_filter_get_name (f), current_filter_name) == 0)
|
||||
{
|
||||
filter_to_select = f;
|
||||
break;
|
||||
}
|
||||
g_object_unref (f);
|
||||
}
|
||||
g_slist_free (filters);
|
||||
g_object_unref (filters);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self), filter_to_select);
|
||||
g_object_unref (filter_to_select);
|
||||
}
|
||||
|
||||
g_slist_free_full (self->custom_files, g_object_unref);
|
||||
@@ -264,17 +270,20 @@ open_file_msg_cb (GObject *source_object,
|
||||
static GVariant *
|
||||
get_filters (GtkFileChooser *self)
|
||||
{
|
||||
GSList *list, *l;
|
||||
GListModel *filters;
|
||||
guint n, i;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa(us))"));
|
||||
list = gtk_file_chooser_list_filters (self);
|
||||
for (l = list; l; l = l->next)
|
||||
filters = gtk_file_chooser_get_filters (self);
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkFileFilter *filter = l->data;
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
g_variant_builder_add (&builder, "@(sa(us))", gtk_file_filter_to_gvariant (filter));
|
||||
g_object_unref (filter);
|
||||
}
|
||||
g_slist_free (list);
|
||||
g_object_unref (filters);
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
@@ -99,9 +99,10 @@ typedef struct {
|
||||
else
|
||||
[data->panel setAllowedFileTypes:filter];
|
||||
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
data->self->current_filter = g_slist_nth_data (filters, selected_index);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
data->self->current_filter = g_list_model_get_item (filters, selected_index);
|
||||
g_object_unref (data->self->current_filter);
|
||||
g_object_unref (filters);
|
||||
g_object_notify (G_OBJECT (data->self), "filter");
|
||||
}
|
||||
@end
|
||||
@@ -307,13 +308,28 @@ filechooser_quartz_launch (FileChooserQuartzData *data)
|
||||
|
||||
if (data->self->current_filter)
|
||||
{
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
gint current_filter_index = g_slist_index (filters, data->self->current_filter);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters;
|
||||
guint i, n;
|
||||
guint current_filter_index = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
if (current_filter_index >= 0)
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (filters, i);
|
||||
if (item == data->self->current_filter)
|
||||
{
|
||||
g_object_unref (item);
|
||||
current_filter_index = i;
|
||||
break;
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
if (current_filter_index != GTK_INVALID_LIST_POSITION)
|
||||
[data->filter_combo_box selectItemAtIndex:current_filter_index];
|
||||
else
|
||||
else
|
||||
[data->filter_combo_box selectItemAtIndex:0];
|
||||
}
|
||||
else
|
||||
@@ -437,15 +453,15 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
GtkWindow *transient_for;
|
||||
GtkFileChooserAction action;
|
||||
|
||||
GSList *filters, *l;
|
||||
int n_filters, i;
|
||||
GListModel *filters;
|
||||
guint n_filters, i;
|
||||
char *message = NULL;
|
||||
|
||||
data = g_new0 (FileChooserQuartzData, 1);
|
||||
|
||||
// examine filters!
|
||||
filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_slist_length (filters);
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_list_model_get_n_items (filters);
|
||||
if (n_filters > 0)
|
||||
{
|
||||
data->filters = [NSMutableArray arrayWithCapacity:n_filters];
|
||||
@@ -453,13 +469,17 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
data->filter_names = [NSMutableArray arrayWithCapacity:n_filters];
|
||||
[data->filter_names retain];
|
||||
|
||||
for (l = filters, i = 0; l != NULL; l = l->next, i++)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (!file_filter_to_quartz (l->data, data->filters, data->filter_names))
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
if (!file_filter_to_quartz (filter, data->filters, data->filter_names))
|
||||
{
|
||||
filechooser_quartz_data_free (data);
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
return FALSE;
|
||||
}
|
||||
g_object_unref (filter);
|
||||
}
|
||||
self->current_filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (self));
|
||||
}
|
||||
@@ -467,6 +487,8 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
{
|
||||
self->current_filter = NULL;
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
self->mode_data = data;
|
||||
data->self = g_object_ref (self);
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ typedef struct {
|
||||
char *cancel_label;
|
||||
char *title;
|
||||
|
||||
GSList *shortcut_files;
|
||||
GListModel *shortcut_files;
|
||||
GArray *choices_selections;
|
||||
|
||||
GFile *current_folder;
|
||||
@@ -244,9 +244,11 @@ ifiledialogevents_OnTypeChange (IFileDialogEvents * self,
|
||||
return S_OK;
|
||||
}
|
||||
fileType--; // fileTypeIndex starts at 1
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (events->data->self));
|
||||
events->data->self->current_filter = g_slist_nth_data (filters, fileType);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (events->data->self));
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, fileType);
|
||||
events->data->self->current_filter = filter;
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
g_object_notify (G_OBJECT (events->data->self), "filter");
|
||||
return S_OK;
|
||||
}
|
||||
@@ -328,7 +330,7 @@ filechooser_win32_thread_data_free (FilechooserWin32ThreadData *data)
|
||||
g_array_free (data->choices_selections, TRUE);
|
||||
data->choices_selections = NULL;
|
||||
}
|
||||
g_slist_free_full (data->shortcut_files, g_object_unref);
|
||||
g_object_unref (data->shortcut_files);
|
||||
g_slist_free_full (data->files, g_object_unref);
|
||||
if (data->self)
|
||||
g_object_unref (data->self);
|
||||
@@ -463,7 +465,7 @@ filechooser_win32_thread (gpointer _data)
|
||||
IFileDialog2 *pfd2 = NULL;
|
||||
DWORD flags;
|
||||
DWORD cookie;
|
||||
GSList *l;
|
||||
guint j, n_items;
|
||||
|
||||
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
@@ -529,9 +531,11 @@ filechooser_win32_thread (gpointer _data)
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
for (l = data->shortcut_files; l != NULL; l = l->next)
|
||||
n_items = g_list_model_get_n_items (data->shortcut_files);
|
||||
for (j = 0; j < n_items; j++)
|
||||
{
|
||||
IShellItem *item = get_shell_item_for_file (l->data);
|
||||
GFile *file = g_list_model_get_item (data->shortcut_files, j);
|
||||
IShellItem *item = get_shell_item_for_file (file);
|
||||
if (item)
|
||||
{
|
||||
hr = IFileDialog_AddPlace (pfd, item, FDAP_BOTTOM);
|
||||
@@ -539,6 +543,7 @@ filechooser_win32_thread (gpointer _data)
|
||||
g_warning_hr ("Can't add dialog shortcut", hr);
|
||||
IShellItem_Release (item);
|
||||
}
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
if (data->current_file)
|
||||
@@ -591,9 +596,23 @@ filechooser_win32_thread (gpointer _data)
|
||||
|
||||
if (data->self->current_filter)
|
||||
{
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
gint current_filter_index = g_slist_index (filters, data->self->current_filter);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters;
|
||||
guint current_filter_index = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
n_items = g_list_model_get_n_items (filters);
|
||||
for (j = 0; j < n_items; j++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (filters, j);
|
||||
if (item == data->self->current_filter)
|
||||
{
|
||||
current_filter_index = j;
|
||||
g_object_unref (item);
|
||||
break;
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
if (current_filter_index >= 0)
|
||||
hr = IFileDialog_SetFileTypeIndex (pfd, current_filter_index + 1);
|
||||
@@ -617,6 +636,8 @@ filechooser_win32_thread (gpointer _data)
|
||||
hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = data->self->choices; l; l = l->next, dialog_control_id++)
|
||||
{
|
||||
GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data;
|
||||
@@ -742,6 +763,8 @@ filechooser_win32_thread (gpointer _data)
|
||||
hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = data->self->choices; l; l = l->next)
|
||||
{
|
||||
GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data;
|
||||
@@ -864,21 +887,24 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
|
||||
FilechooserWin32ThreadData *data;
|
||||
GtkWindow *transient_for;
|
||||
GtkFileChooserAction action;
|
||||
GSList *filters, *l;
|
||||
int n_filters, i;
|
||||
GListModel *filters;
|
||||
guint n_filters, i;
|
||||
|
||||
data = g_new0 (FilechooserWin32ThreadData, 1);
|
||||
|
||||
filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_slist_length (filters);
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_list_model_get_n_items (filters);
|
||||
if (n_filters > 0)
|
||||
{
|
||||
data->filters = g_new0 (COMDLG_FILTERSPEC, n_filters + 1);
|
||||
|
||||
for (l = filters, i = 0; l != NULL; l = l->next, i++)
|
||||
for (i = 0; i < n_filters; i++)
|
||||
{
|
||||
if (!file_filter_to_win32 (l->data, &data->filters[i]))
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
if (!file_filter_to_win32 (filter, &data->filters[i]))
|
||||
{
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
filechooser_win32_thread_data_free (data);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -889,12 +915,13 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
|
||||
{
|
||||
self->current_filter = NULL;
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
self->mode_data = data;
|
||||
data->self = g_object_ref (self);
|
||||
|
||||
data->shortcut_files =
|
||||
gtk_file_chooser_list_shortcut_folders (GTK_FILE_CHOOSER (self->dialog));
|
||||
gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (self->dialog));
|
||||
|
||||
data->accept_label = translate_mnemonics (self->accept_label);
|
||||
data->cancel_label = translate_mnemonics (self->cancel_label);
|
||||
|
||||
+32
-25
@@ -58,34 +58,34 @@ struct _GtkFileChooserIface
|
||||
|
||||
/* Methods
|
||||
*/
|
||||
gboolean (*set_current_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile * (*get_current_folder) (GtkFileChooser *chooser);
|
||||
void (*set_current_name) (GtkFileChooser *chooser,
|
||||
const gchar *name);
|
||||
gboolean (*set_current_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile * (*get_current_folder) (GtkFileChooser *chooser);
|
||||
void (*set_current_name) (GtkFileChooser *chooser,
|
||||
const gchar *name);
|
||||
gchar * (*get_current_name) (GtkFileChooser *chooser);
|
||||
gboolean (*select_file) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
void (*unselect_file) (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
void (*select_all) (GtkFileChooser *chooser);
|
||||
void (*unselect_all) (GtkFileChooser *chooser);
|
||||
GSList * (*get_files) (GtkFileChooser *chooser);
|
||||
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
|
||||
void (*add_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
void (*remove_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GSList * (*list_filters) (GtkFileChooser *chooser);
|
||||
gboolean (*select_file) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
void (*unselect_file) (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
void (*select_all) (GtkFileChooser *chooser);
|
||||
void (*unselect_all) (GtkFileChooser *chooser);
|
||||
GListModel * (*get_files) (GtkFileChooser *chooser);
|
||||
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
|
||||
void (*add_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
void (*remove_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GListModel * (*get_filters) (GtkFileChooser *chooser);
|
||||
gboolean (*add_shortcut_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile *file,
|
||||
GError **error);
|
||||
gboolean (*remove_shortcut_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GSList * (*list_shortcut_folders) (GtkFileChooser *chooser);
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GListModel * (*get_shortcut_folders) (GtkFileChooser *chooser);
|
||||
|
||||
/* Signals
|
||||
*/
|
||||
@@ -111,6 +111,13 @@ struct _GtkFileChooserIface
|
||||
|
||||
GtkFileSystem *_gtk_file_chooser_get_file_system (GtkFileChooser *chooser);
|
||||
|
||||
void gtk_file_chooser_select_all (GtkFileChooser *chooser);
|
||||
void gtk_file_chooser_unselect_all (GtkFileChooser *chooser);
|
||||
gboolean gtk_file_chooser_select_file (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
void gtk_file_chooser_unselect_file (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_FILE_CHOOSER_PRIVATE_H__ */
|
||||
|
||||
+26
-53
@@ -39,29 +39,23 @@ static void delegate_unselect_file (GtkFileChooser *choose
|
||||
GFile *file);
|
||||
static void delegate_select_all (GtkFileChooser *chooser);
|
||||
static void delegate_unselect_all (GtkFileChooser *chooser);
|
||||
static GSList * delegate_get_files (GtkFileChooser *chooser);
|
||||
static GListModel * delegate_get_files (GtkFileChooser *chooser);
|
||||
static GtkFileSystem *delegate_get_file_system (GtkFileChooser *chooser);
|
||||
static void delegate_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static void delegate_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static GSList * delegate_list_filters (GtkFileChooser *chooser);
|
||||
static GListModel * delegate_get_filters (GtkFileChooser *chooser);
|
||||
static gboolean delegate_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static gboolean delegate_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static GSList * delegate_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
static GListModel * delegate_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
static void delegate_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer data);
|
||||
static void delegate_current_folder_changed (GtkFileChooser *chooser,
|
||||
gpointer data);
|
||||
static void delegate_selection_changed (GtkFileChooser *chooser,
|
||||
gpointer data);
|
||||
static void delegate_file_activated (GtkFileChooser *chooser,
|
||||
gpointer data);
|
||||
|
||||
static void delegate_add_choice (GtkFileChooser *chooser,
|
||||
const char *id,
|
||||
@@ -92,17 +86,23 @@ void
|
||||
_gtk_file_chooser_install_properties (GObjectClass *klass)
|
||||
{
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_ACTION,
|
||||
"action");
|
||||
GTK_FILE_CHOOSER_PROP_ACTION,
|
||||
"action");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
"filter");
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
"filter");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
"select-multiple");
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
"select-multiple");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
"create-folders");
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
"create-folders");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_FILTERS,
|
||||
"filters");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS,
|
||||
"shortcut-folders");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,10 +131,10 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
|
||||
iface->get_file_system = delegate_get_file_system;
|
||||
iface->add_filter = delegate_add_filter;
|
||||
iface->remove_filter = delegate_remove_filter;
|
||||
iface->list_filters = delegate_list_filters;
|
||||
iface->get_filters = delegate_get_filters;
|
||||
iface->add_shortcut_folder = delegate_add_shortcut_folder;
|
||||
iface->remove_shortcut_folder = delegate_remove_shortcut_folder;
|
||||
iface->list_shortcut_folders = delegate_list_shortcut_folders;
|
||||
iface->get_shortcut_folders = delegate_get_shortcut_folders;
|
||||
iface->add_choice = delegate_add_choice;
|
||||
iface->remove_choice = delegate_remove_choice;
|
||||
iface->set_choice = delegate_set_choice;
|
||||
@@ -162,12 +162,6 @@ _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
|
||||
g_object_set_data (G_OBJECT (receiver), I_("gtk-file-chooser-delegate"), delegate);
|
||||
g_signal_connect (delegate, "notify",
|
||||
G_CALLBACK (delegate_notify), receiver);
|
||||
g_signal_connect (delegate, "current-folder-changed",
|
||||
G_CALLBACK (delegate_current_folder_changed), receiver);
|
||||
g_signal_connect (delegate, "selection-changed",
|
||||
G_CALLBACK (delegate_selection_changed), receiver);
|
||||
g_signal_connect (delegate, "file-activated",
|
||||
G_CALLBACK (delegate_file_activated), receiver);
|
||||
}
|
||||
|
||||
GQuark
|
||||
@@ -215,7 +209,7 @@ delegate_unselect_all (GtkFileChooser *chooser)
|
||||
gtk_file_chooser_unselect_all (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static GSList *
|
||||
static GListModel *
|
||||
delegate_get_files (GtkFileChooser *chooser)
|
||||
{
|
||||
return gtk_file_chooser_get_files (get_delegate (chooser));
|
||||
@@ -241,10 +235,10 @@ delegate_remove_filter (GtkFileChooser *chooser,
|
||||
gtk_file_chooser_remove_filter (get_delegate (chooser), filter);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
delegate_list_filters (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
delegate_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
return gtk_file_chooser_list_filters (get_delegate (chooser));
|
||||
return gtk_file_chooser_get_filters (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -263,10 +257,10 @@ delegate_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
return gtk_file_chooser_remove_shortcut_folder (get_delegate (chooser), file, error);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
delegate_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
delegate_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
return gtk_file_chooser_list_shortcut_folders (get_delegate (chooser));
|
||||
return gtk_file_chooser_get_shortcut_folders (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -309,27 +303,6 @@ delegate_notify (GObject *object,
|
||||
g_object_notify (data, pspec->name);
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_selection_changed (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "selection-changed");
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_current_folder_changed (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "current-folder-changed");
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_file_activated (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "file-activated");
|
||||
}
|
||||
|
||||
GSettings *
|
||||
_gtk_file_chooser_get_settings_for_widget (GtkWidget *widget)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,9 @@ typedef enum {
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS
|
||||
GTK_FILE_CHOOSER_PROP_FILTERS,
|
||||
GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS,
|
||||
GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS
|
||||
} GtkFileChooserProp;
|
||||
|
||||
void _gtk_file_chooser_install_properties (GObjectClass *klass);
|
||||
|
||||
+131
-54
@@ -479,20 +479,20 @@ static void gtk_file_chooser_widget_unselect_file (GtkF
|
||||
GFile *file);
|
||||
static void gtk_file_chooser_widget_select_all (GtkFileChooser *chooser);
|
||||
static void gtk_file_chooser_widget_unselect_all (GtkFileChooser *chooser);
|
||||
static GSList * gtk_file_chooser_widget_get_files (GtkFileChooser *chooser);
|
||||
static GListModel * gtk_file_chooser_widget_get_files (GtkFileChooser *chooser);
|
||||
static GtkFileSystem *gtk_file_chooser_widget_get_file_system (GtkFileChooser *chooser);
|
||||
static void gtk_file_chooser_widget_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static void gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static GSList * gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser);
|
||||
static GListModel * gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser);
|
||||
static gboolean gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static gboolean gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static GSList * gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
static GListModel * gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
|
||||
static gboolean gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed);
|
||||
static void gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed);
|
||||
@@ -619,10 +619,10 @@ gtk_file_chooser_widget_iface_init (GtkFileChooserIface *iface)
|
||||
iface->get_current_name = gtk_file_chooser_widget_get_current_name;
|
||||
iface->add_filter = gtk_file_chooser_widget_add_filter;
|
||||
iface->remove_filter = gtk_file_chooser_widget_remove_filter;
|
||||
iface->list_filters = gtk_file_chooser_widget_list_filters;
|
||||
iface->get_filters = gtk_file_chooser_widget_get_filters;
|
||||
iface->add_shortcut_folder = gtk_file_chooser_widget_add_shortcut_folder;
|
||||
iface->remove_shortcut_folder = gtk_file_chooser_widget_remove_shortcut_folder;
|
||||
iface->list_shortcut_folders = gtk_file_chooser_widget_list_shortcut_folders;
|
||||
iface->get_shortcut_folders = gtk_file_chooser_widget_get_shortcut_folders;
|
||||
iface->add_choice = gtk_file_chooser_widget_add_choice;
|
||||
iface->remove_choice = gtk_file_chooser_widget_remove_choice;
|
||||
iface->set_choice = gtk_file_chooser_widget_set_choice;
|
||||
@@ -2220,14 +2220,66 @@ set_icon_cell_renderer_fixed_size (GtkFileChooserWidget *impl)
|
||||
ypad * 2 + ICON_SIZE);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
get_accept_action_widget (GtkDialog *dialog,
|
||||
gboolean sensitive_only)
|
||||
{
|
||||
gint response[] = {
|
||||
GTK_RESPONSE_ACCEPT,
|
||||
GTK_RESPONSE_OK,
|
||||
GTK_RESPONSE_YES,
|
||||
GTK_RESPONSE_APPLY
|
||||
};
|
||||
gint i;
|
||||
GtkWidget *widget;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (response); i++)
|
||||
{
|
||||
widget = gtk_dialog_get_widget_for_response (dialog, response[i]);
|
||||
if (widget)
|
||||
{
|
||||
if (!sensitive_only)
|
||||
return widget;
|
||||
|
||||
if (gtk_widget_is_sensitive (widget))
|
||||
return widget;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
update_default (GtkFileChooserWidget *impl)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *button;
|
||||
GListModel *files;
|
||||
gboolean sensitive;
|
||||
|
||||
dialog = gtk_widget_get_ancestor (GTK_WIDGET (impl), GTK_TYPE_DIALOG);
|
||||
if (dialog == NULL)
|
||||
return;
|
||||
|
||||
button = get_accept_action_widget (GTK_DIALOG (dialog), FALSE);
|
||||
if (button == NULL)
|
||||
return;
|
||||
|
||||
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (impl));
|
||||
sensitive = (g_list_model_get_n_items (files) > 0);
|
||||
gtk_widget_set_sensitive (button, sensitive);
|
||||
|
||||
g_object_unref (files);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
location_changed_timeout_cb (gpointer user_data)
|
||||
{
|
||||
GtkFileChooserWidget *impl = user_data;
|
||||
|
||||
gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (impl));
|
||||
g_signal_emit_by_name (impl, "selection-changed", 0);
|
||||
|
||||
update_default (impl);
|
||||
impl->location_changed_id = 0;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
@@ -3072,6 +3124,14 @@ gtk_file_chooser_widget_get_property (GObject *object,
|
||||
g_value_set_boolean (value, impl->create_folders);
|
||||
break;
|
||||
|
||||
case GTK_FILE_CHOOSER_PROP_FILTERS:
|
||||
g_value_set_object (value, impl->filters);
|
||||
break;
|
||||
|
||||
case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS:
|
||||
g_value_take_object (value, gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (impl)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -3429,25 +3489,27 @@ set_startup_mode (GtkFileChooserWidget *impl)
|
||||
static gboolean
|
||||
shortcut_exists (GtkFileChooserWidget *impl, GFile *needle)
|
||||
{
|
||||
GSList *haystack;
|
||||
GSList *l;
|
||||
GListModel *haystack;
|
||||
guint n, i;
|
||||
gboolean exists;
|
||||
|
||||
exists = FALSE;
|
||||
|
||||
haystack = gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
for (l = haystack; l; l = l->next)
|
||||
haystack = gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
n = g_list_model_get_n_items (haystack);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GFile *hay;
|
||||
GFile *hay = g_list_model_get_item (haystack, i);
|
||||
|
||||
hay = G_FILE (l->data);
|
||||
if (g_file_equal (hay, needle))
|
||||
{
|
||||
g_object_unref (hay);
|
||||
exists = TRUE;
|
||||
break;
|
||||
}
|
||||
g_object_unref (hay);
|
||||
}
|
||||
g_slist_free_full (haystack, g_object_unref);
|
||||
g_object_unref (haystack);
|
||||
|
||||
return exists;
|
||||
}
|
||||
@@ -5074,9 +5136,7 @@ update_current_folder_get_info_cb (GCancellable *cancellable,
|
||||
|
||||
g_object_notify (G_OBJECT (impl), "subtitle");
|
||||
|
||||
g_signal_emit_by_name (impl, "current-folder-changed", 0);
|
||||
|
||||
g_signal_emit_by_name (impl, "selection-changed", 0);
|
||||
update_default (impl);
|
||||
|
||||
out:
|
||||
g_object_unref (data->impl);
|
||||
@@ -5398,7 +5458,7 @@ check_save_entry (GtkFileChooserWidget *impl,
|
||||
|
||||
struct get_files_closure {
|
||||
GtkFileChooserWidget *impl;
|
||||
GSList *result;
|
||||
GListStore *result;
|
||||
GFile *file_from_entry;
|
||||
};
|
||||
|
||||
@@ -5415,10 +5475,25 @@ get_files_foreach (GtkTreeModel *model,
|
||||
file = _gtk_file_system_model_get_file (fs_model, iter);
|
||||
|
||||
if (!info->file_from_entry || !g_file_equal (info->file_from_entry, file))
|
||||
info->result = g_slist_prepend (info->result, g_object_ref (file));
|
||||
g_list_store_append (info->result, file);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
static GListModel *
|
||||
get_selected_files_as_model (GtkFileChooserWidget *impl)
|
||||
{
|
||||
GListStore *store;
|
||||
GSList *files, *l;
|
||||
|
||||
store = g_list_store_new (G_TYPE_FILE);
|
||||
files = get_selected_files (impl);
|
||||
for (l = files; l; l = l->next)
|
||||
g_list_store_append (store, l->data);
|
||||
g_slist_free_full (files, g_object_unref);
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
@@ -5427,12 +5502,8 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
|
||||
GtkWidget *current_focus;
|
||||
gboolean file_list_seen;
|
||||
|
||||
info.impl = impl;
|
||||
info.result = NULL;
|
||||
info.file_from_entry = NULL;
|
||||
|
||||
if (impl->operation_mode == OPERATION_MODE_SEARCH)
|
||||
return get_selected_files (impl);
|
||||
return get_selected_files_as_model (impl);
|
||||
|
||||
if (impl->operation_mode == OPERATION_MODE_RECENT)
|
||||
{
|
||||
@@ -5442,9 +5513,13 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
|
||||
goto file_entry;
|
||||
}
|
||||
else
|
||||
return get_selected_files (impl);
|
||||
return get_selected_files_as_model (impl);
|
||||
}
|
||||
|
||||
info.impl = impl;
|
||||
info.result = g_list_store_new (G_TYPE_FILE);
|
||||
info.file_from_entry = NULL;
|
||||
|
||||
toplevel = get_toplevel (GTK_WIDGET (impl));
|
||||
if (toplevel)
|
||||
current_focus = gtk_root_get_focus (GTK_ROOT (toplevel));
|
||||
@@ -5488,7 +5563,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
|
||||
return NULL;
|
||||
|
||||
if (info.file_from_entry)
|
||||
info.result = g_slist_prepend (info.result, info.file_from_entry);
|
||||
g_list_store_append (info.result, info.file_from_entry);
|
||||
else if (!file_list_seen)
|
||||
goto file_list;
|
||||
else
|
||||
@@ -5520,10 +5595,10 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
|
||||
current_folder = gtk_file_chooser_get_current_folder (chooser);
|
||||
|
||||
if (current_folder)
|
||||
info.result = g_slist_prepend (info.result, current_folder);
|
||||
g_list_store_append (info.result, current_folder);
|
||||
}
|
||||
|
||||
return g_slist_reverse (info.result);
|
||||
return G_LIST_MODEL (info.result);
|
||||
}
|
||||
|
||||
static GtkFileSystem *
|
||||
@@ -5564,6 +5639,8 @@ gtk_file_chooser_widget_add_filter (GtkFileChooser *chooser,
|
||||
set_current_filter (impl, filter);
|
||||
|
||||
show_filters (impl, TRUE);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "filters");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5597,25 +5674,16 @@ gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser,
|
||||
|
||||
if (!impl->filters)
|
||||
show_filters (impl, FALSE);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "filters");
|
||||
}
|
||||
|
||||
static GSList *
|
||||
gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
GSList *filters;
|
||||
guint i;
|
||||
|
||||
filters = NULL;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (impl->filters)); i++)
|
||||
{
|
||||
GtkFileFilter *filter = g_list_model_get_item (G_LIST_MODEL (impl->filters), i);
|
||||
filters = g_slist_append (filters, filter);
|
||||
g_object_unref (filter);
|
||||
}
|
||||
|
||||
return filters;
|
||||
return G_LIST_MODEL (g_object_ref (impl->filters));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -5626,6 +5694,9 @@ gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
gtk_places_sidebar_add_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "shortcut-folders");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -5637,15 +5708,18 @@ gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
gtk_places_sidebar_remove_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "shortcut-folders");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
return gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
return gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
}
|
||||
|
||||
struct switch_folder_closure {
|
||||
@@ -6134,18 +6208,18 @@ location_popup_on_paste_handler (GtkFileChooserWidget *impl)
|
||||
static void
|
||||
add_selection_to_recent_list (GtkFileChooserWidget *impl)
|
||||
{
|
||||
GSList *files;
|
||||
GSList *l;
|
||||
GListModel *files;
|
||||
guint i, n;
|
||||
|
||||
files = gtk_file_chooser_widget_get_files (GTK_FILE_CHOOSER (impl));
|
||||
|
||||
|
||||
if (!impl->recent_manager)
|
||||
impl->recent_manager = gtk_recent_manager_get_default ();
|
||||
|
||||
for (l = files; l; l = l->next)
|
||||
n = g_list_model_get_n_items (files);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GFile *file = l->data;
|
||||
GFile *file = g_list_model_get_item (files, i);
|
||||
char *uri;
|
||||
|
||||
uri = g_file_get_uri (file);
|
||||
@@ -6154,9 +6228,11 @@ add_selection_to_recent_list (GtkFileChooserWidget *impl)
|
||||
gtk_recent_manager_add_item (impl->recent_manager, uri);
|
||||
g_free (uri);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_slist_free_full (files, g_object_unref);
|
||||
g_object_unref (files);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -6933,6 +7009,8 @@ filter_combo_changed (GtkDropDown *dropdown,
|
||||
|
||||
new_filter = gtk_drop_down_get_selected_item (dropdown);
|
||||
|
||||
set_current_filter (impl, new_filter);
|
||||
|
||||
if (impl->location_entry != NULL)
|
||||
_gtk_file_chooser_entry_set_file_filter (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
|
||||
new_filter);
|
||||
@@ -6978,8 +7056,7 @@ list_selection_changed (GtkTreeSelection *selection,
|
||||
update_chooser_entry (impl);
|
||||
|
||||
location_bar_update (impl);
|
||||
|
||||
g_signal_emit_by_name (impl, "selection-changed", 0);
|
||||
update_default (impl);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -7031,7 +7108,7 @@ list_row_activated (GtkTreeView *tree_view,
|
||||
|
||||
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
|
||||
impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
g_signal_emit_by_name (impl, "file-activated");
|
||||
gtk_widget_activate_default (GTK_WIDGET (impl));
|
||||
|
||||
out:
|
||||
|
||||
|
||||
+336
-373
File diff suppressed because it is too large
Load Diff
+13
-78
@@ -33,99 +33,34 @@ G_BEGIN_DECLS
|
||||
#define GTK_IS_FILE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FILTER))
|
||||
|
||||
typedef struct _GtkFileFilter GtkFileFilter;
|
||||
typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
|
||||
|
||||
/**
|
||||
* GtkFileFilterFlags:
|
||||
* @GTK_FILE_FILTER_FILENAME: the filename of the file being tested
|
||||
* @GTK_FILE_FILTER_URI: the URI for the file being tested
|
||||
* @GTK_FILE_FILTER_DISPLAY_NAME: the string that will be used to
|
||||
* display the file in the file chooser
|
||||
* @GTK_FILE_FILTER_MIME_TYPE: the mime type of the file
|
||||
*
|
||||
* These flags indicate what parts of a #GtkFileFilterInfo struct
|
||||
* are filled or need to be filled.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_FILE_FILTER_FILENAME = 1 << 0,
|
||||
GTK_FILE_FILTER_URI = 1 << 1,
|
||||
GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
|
||||
GTK_FILE_FILTER_MIME_TYPE = 1 << 3
|
||||
} GtkFileFilterFlags;
|
||||
|
||||
/**
|
||||
* GtkFileFilterFunc:
|
||||
* @filter_info: a #GtkFileFilterInfo that is filled according
|
||||
* to the @needed flags passed to gtk_file_filter_add_custom()
|
||||
* @data: (closure): user data passed to gtk_file_filter_add_custom()
|
||||
*
|
||||
* The type of function that is used with custom filters, see
|
||||
* gtk_file_filter_add_custom().
|
||||
*
|
||||
* Returns: %TRUE if the file should be displayed
|
||||
*/
|
||||
typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* GtkFileFilterInfo:
|
||||
* @contains: Flags indicating which of the following fields need
|
||||
* are filled
|
||||
* @filename: the filename of the file being tested
|
||||
* @uri: the URI for the file being tested
|
||||
* @display_name: the string that will be used to display the file
|
||||
* in the file chooser
|
||||
* @mime_type: the mime type of the file
|
||||
*
|
||||
* A #GtkFileFilterInfo is used to pass information about the
|
||||
* tested file to gtk_file_filter_filter().
|
||||
*/
|
||||
struct _GtkFileFilterInfo
|
||||
{
|
||||
GtkFileFilterFlags contains;
|
||||
|
||||
const gchar *filename;
|
||||
const gchar *uri;
|
||||
const gchar *display_name;
|
||||
const gchar *mime_type;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_file_filter_get_type (void) G_GNUC_CONST;
|
||||
GType gtk_file_filter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter * gtk_file_filter_new (void);
|
||||
GtkFileFilter * gtk_file_filter_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_set_name (GtkFileFilter *filter,
|
||||
const gchar *name);
|
||||
void gtk_file_filter_set_name (GtkFileFilter *filter,
|
||||
const char *name);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const gchar * gtk_file_filter_get_name (GtkFileFilter *filter);
|
||||
const char * gtk_file_filter_get_name (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_mime_type (GtkFileFilter *filter,
|
||||
const gchar *mime_type);
|
||||
void gtk_file_filter_add_mime_type (GtkFileFilter *filter,
|
||||
const char *mime_type);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_pattern (GtkFileFilter *filter,
|
||||
const gchar *pattern);
|
||||
void gtk_file_filter_add_pattern (GtkFileFilter *filter,
|
||||
const char *pattern);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_custom (GtkFileFilter *filter,
|
||||
GtkFileFilterFlags needed,
|
||||
GtkFileFilterFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilterFlags gtk_file_filter_get_needed (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_filter_filter (GtkFileFilter *filter,
|
||||
const GtkFileFilterInfo *filter_info);
|
||||
const char ** gtk_file_filter_get_attributes (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GVariant *gtk_file_filter_to_gvariant (GtkFileFilter *filter);
|
||||
GVariant * gtk_file_filter_to_gvariant (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter *gtk_file_filter_new_from_gvariant (GVariant *variant);
|
||||
GtkFileFilter * gtk_file_filter_new_from_gvariant (GVariant *variant);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "gtktreedatalist.h"
|
||||
#include "gtktreednd.h"
|
||||
#include "gtktreemodel.h"
|
||||
#include "gtkfilter.h"
|
||||
|
||||
/*** Structure: how GtkFileSystemModel works
|
||||
*
|
||||
@@ -375,12 +376,6 @@ static gboolean
|
||||
node_should_be_filtered_out (GtkFileSystemModel *model, guint id)
|
||||
{
|
||||
FileModelNode *node = get_node (model, id);
|
||||
GtkFileFilterInfo filter_info = { 0, };
|
||||
GtkFileFilterFlags required;
|
||||
gboolean result;
|
||||
char *mime_type = NULL;
|
||||
char *filename = NULL;
|
||||
char *uri = NULL;
|
||||
|
||||
if (node->info == NULL)
|
||||
return TRUE;
|
||||
@@ -388,57 +383,10 @@ node_should_be_filtered_out (GtkFileSystemModel *model, guint id)
|
||||
if (model->filter == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* fill info */
|
||||
required = gtk_file_filter_get_needed (model->filter);
|
||||
if (!g_file_info_has_attribute (node->info, "standard::file"))
|
||||
g_file_info_set_attribute_object (node->info, "standard::file", G_OBJECT (node->file));
|
||||
|
||||
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)
|
||||
{
|
||||
const char *s = g_file_info_get_content_type (node->info);
|
||||
|
||||
if (!s)
|
||||
s = g_file_info_get_attribute_string (node->info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
result = !gtk_file_filter_filter (model->filter, &filter_info);
|
||||
|
||||
g_free (mime_type);
|
||||
g_free (filename);
|
||||
g_free (uri);
|
||||
|
||||
return result;
|
||||
return !gtk_filter_match (GTK_FILTER (model->filter), node->info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
+330
-393
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "gtkfilterlistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
@@ -35,40 +35,33 @@
|
||||
* listmodel.
|
||||
* It hides some elements from the other model according to
|
||||
* criteria given by a #GtkFilter.
|
||||
*
|
||||
* The model can be set up to do incremental searching, so that
|
||||
* filtering long lists doesn't block the UI. See
|
||||
* gtk_filter_list_model_set_incremental() for details.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_FILTER,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_INCREMENTAL,
|
||||
PROP_MODEL,
|
||||
PROP_PENDING,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
typedef struct _FilterNode FilterNode;
|
||||
typedef struct _FilterAugment FilterAugment;
|
||||
|
||||
struct _FilterNode
|
||||
{
|
||||
guint visible : 1;
|
||||
};
|
||||
|
||||
struct _FilterAugment
|
||||
{
|
||||
guint n_items;
|
||||
guint n_visible;
|
||||
};
|
||||
|
||||
struct _GtkFilterListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkFilter *filter;
|
||||
GtkFilterMatch strictness;
|
||||
gboolean incremental;
|
||||
|
||||
GtkRbTree *items; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||
GtkBitset *matches; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||
GtkBitset *pending; /* not yet filtered items or NULL if all filtered */
|
||||
guint pending_cb; /* idle callback handle */
|
||||
};
|
||||
|
||||
struct _GtkFilterListModelClass
|
||||
@@ -78,133 +71,16 @@ struct _GtkFilterListModelClass
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_augment (GtkRbTree *filter,
|
||||
gpointer _aug,
|
||||
gpointer _node,
|
||||
gpointer left,
|
||||
gpointer right)
|
||||
{
|
||||
FilterNode *node = _node;
|
||||
FilterAugment *aug = _aug;
|
||||
|
||||
aug->n_items = 1;
|
||||
aug->n_visible = node->visible ? 1 : 0;
|
||||
|
||||
if (left)
|
||||
{
|
||||
FilterAugment *left_aug = gtk_rb_tree_get_augment (filter, left);
|
||||
aug->n_items += left_aug->n_items;
|
||||
aug->n_visible += left_aug->n_visible;
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
FilterAugment *right_aug = gtk_rb_tree_get_augment (filter, right);
|
||||
aug->n_items += right_aug->n_items;
|
||||
aug->n_visible += right_aug->n_visible;
|
||||
}
|
||||
}
|
||||
|
||||
static FilterNode *
|
||||
gtk_filter_list_model_get_nth_filtered (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *out_unfiltered)
|
||||
{
|
||||
FilterNode *node, *tmp;
|
||||
guint unfiltered;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
unfiltered = 0;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_visible)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_visible;
|
||||
unfiltered += aug->n_items;
|
||||
}
|
||||
|
||||
if (node->visible)
|
||||
{
|
||||
if (position == 0)
|
||||
break;
|
||||
position--;
|
||||
}
|
||||
|
||||
unfiltered++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (out_unfiltered)
|
||||
*out_unfiltered = unfiltered;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static FilterNode *
|
||||
gtk_filter_list_model_get_nth (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *out_filtered)
|
||||
{
|
||||
FilterNode *node, *tmp;
|
||||
guint filtered;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
filtered = 0;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_items;
|
||||
filtered += aug->n_visible;
|
||||
}
|
||||
|
||||
if (position == 0)
|
||||
break;
|
||||
|
||||
position--;
|
||||
if (node->visible)
|
||||
filtered++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (out_filtered)
|
||||
*out_filtered = filtered;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_filter_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
FilterAugment *aug;
|
||||
FilterNode *node;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
@@ -215,18 +91,12 @@ gtk_filter_list_model_get_n_items (GListModel *list)
|
||||
return g_list_model_get_n_items (self->model);
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
break;
|
||||
return gtk_bitset_get_size (self->matches);
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = gtk_rb_tree_get_root (self->items);
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
|
||||
aug = gtk_rb_tree_get_augment (self->items, node);
|
||||
return aug->n_visible;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
@@ -246,7 +116,9 @@ gtk_filter_list_model_get_item (GListModel *list,
|
||||
break;
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
gtk_filter_list_model_get_nth_filtered (self->items, position, &unfiltered);
|
||||
unfiltered = gtk_bitset_get_nth (self->matches, position);
|
||||
if (unfiltered == 0 && position >= gtk_bitset_get_size (self->matches))
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -268,8 +140,8 @@ G_DEFINE_TYPE_WITH_CODE (GtkFilterListModel, gtk_filter_list_model, G_TYPE_OBJEC
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init))
|
||||
|
||||
static gboolean
|
||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
guint position)
|
||||
gtk_filter_list_model_run_filter_on_item (GtkFilterListModel *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean visible;
|
||||
@@ -284,26 +156,120 @@ gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
return visible;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_add_items (GtkFilterListModel *self,
|
||||
FilterNode *after,
|
||||
guint position,
|
||||
guint n_items)
|
||||
static void
|
||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
guint n_steps)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, n_visible;
|
||||
GtkBitsetIter iter;
|
||||
guint i, pos;
|
||||
gboolean more;
|
||||
|
||||
n_visible = 0;
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
if (self->pending == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0, more = gtk_bitset_iter_init_first (&iter, self->pending, &pos);
|
||||
i < n_steps && more;
|
||||
i++, more = gtk_bitset_iter_next (&iter, &pos))
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->visible = gtk_filter_list_model_run_filter (self, position + i);
|
||||
if (node->visible)
|
||||
n_visible++;
|
||||
if (gtk_filter_list_model_run_filter_on_item (self, pos))
|
||||
gtk_bitset_add (self->matches, pos);
|
||||
}
|
||||
|
||||
return n_visible;
|
||||
if (more)
|
||||
gtk_bitset_remove_range_closed (self->pending, 0, pos - 1);
|
||||
else
|
||||
g_clear_pointer (&self->pending, gtk_bitset_unref);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_stop_filtering (GtkFilterListModel *self)
|
||||
{
|
||||
gboolean notify_pending = self->pending != NULL;
|
||||
|
||||
g_clear_pointer (&self->pending, gtk_bitset_unref);
|
||||
g_clear_handle_id (&self->pending_cb, g_source_remove);
|
||||
|
||||
if (notify_pending)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (GtkFilterListModel *self,
|
||||
GtkBitset *old)
|
||||
{
|
||||
GtkBitset *changes;
|
||||
|
||||
changes = gtk_bitset_copy (self->matches);
|
||||
gtk_bitset_difference (changes, old);
|
||||
if (!gtk_bitset_is_empty (changes))
|
||||
{
|
||||
guint min, max;
|
||||
|
||||
min = gtk_bitset_get_minimum (changes);
|
||||
max = gtk_bitset_get_maximum (changes);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
min > 0 ? gtk_bitset_get_size_in_range (self->matches, 0, min - 1) : 0,
|
||||
gtk_bitset_get_size_in_range (old, min, max),
|
||||
gtk_bitset_get_size_in_range (self->matches, min, max));
|
||||
}
|
||||
gtk_bitset_unref (changes);
|
||||
gtk_bitset_unref (old);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_filter_list_model_run_filter_cb (gpointer data)
|
||||
{
|
||||
GtkFilterListModel *self = data;
|
||||
GtkBitset *old;
|
||||
|
||||
old = gtk_bitset_copy (self->matches);
|
||||
gtk_filter_list_model_run_filter (self, 512);
|
||||
|
||||
if (self->pending == NULL)
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/* NB: bitset is (transfer full) */
|
||||
static void
|
||||
gtk_filter_list_model_start_filtering (GtkFilterListModel *self,
|
||||
GtkBitset *items)
|
||||
{
|
||||
if (self->pending)
|
||||
{
|
||||
gtk_bitset_union (self->pending, items);
|
||||
gtk_bitset_unref (items);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gtk_bitset_is_empty (items))
|
||||
{
|
||||
gtk_bitset_unref (items);
|
||||
return;
|
||||
}
|
||||
|
||||
self->pending = items;
|
||||
|
||||
if (!self->incremental)
|
||||
{
|
||||
gtk_filter_list_model_run_filter (self, G_MAXUINT);
|
||||
g_assert (self->pending == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
g_assert (self->pending_cb == 0);
|
||||
self->pending_cb = g_idle_add (gtk_filter_list_model_run_filter_cb, self);
|
||||
g_source_set_name_by_id (self->pending_cb, "[gtk] gtk_filter_list_model_run_filter_cb");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -313,8 +279,7 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
||||
guint added,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, filter_position, filter_removed, filter_added;
|
||||
guint filter_removed, filter_added;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
@@ -332,22 +297,27 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
node = gtk_filter_list_model_get_nth (self->items, position, &filter_position);
|
||||
if (removed > 0)
|
||||
filter_removed = gtk_bitset_get_size_in_range (self->matches, position, position + removed - 1);
|
||||
else
|
||||
filter_removed = 0;
|
||||
|
||||
filter_removed = 0;
|
||||
for (i = 0; i < removed; i++)
|
||||
gtk_bitset_splice (self->matches, position, removed, added);
|
||||
if (self->pending)
|
||||
gtk_bitset_splice (self->pending, position, removed, added);
|
||||
|
||||
if (added > 0)
|
||||
{
|
||||
FilterNode *next = gtk_rb_tree_node_get_next (node);
|
||||
if (node->visible)
|
||||
filter_removed++;
|
||||
gtk_rb_tree_remove (self->items, node);
|
||||
node = next;
|
||||
gtk_filter_list_model_start_filtering (self, gtk_bitset_new_range (position, added));
|
||||
filter_added = gtk_bitset_get_size_in_range (self->matches, position, position + added - 1);
|
||||
}
|
||||
|
||||
filter_added = gtk_filter_list_model_add_items (self, node, position, added);
|
||||
else
|
||||
filter_added = 0;
|
||||
|
||||
if (filter_removed > 0 || filter_added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
position > 0 ? gtk_bitset_get_size_in_range (self->matches, 0, position - 1) : 0,
|
||||
filter_removed, filter_added);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -364,8 +334,8 @@ gtk_filter_list_model_set_property (GObject *object,
|
||||
gtk_filter_list_model_set_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
case PROP_INCREMENTAL:
|
||||
gtk_filter_list_model_set_incremental (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
@@ -392,14 +362,18 @@ gtk_filter_list_model_get_property (GObject *object,
|
||||
g_value_set_object (value, self->filter);
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
case PROP_INCREMENTAL:
|
||||
g_value_set_boolean (value, self->incremental);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_PENDING:
|
||||
g_value_set_uint (value, gtk_filter_list_model_get_pending (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -412,109 +386,16 @@ gtk_filter_list_model_clear_model (GtkFilterListModel *self)
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
if (self->items)
|
||||
gtk_rb_tree_remove_all (self->items);
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gtk_filter_list_model_find_filtered:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @start: (out) (caller-allocates): number of unfiltered items
|
||||
* at start of list
|
||||
* @end: (out) (caller-allocates): number of unfiltered items
|
||||
* at end of list
|
||||
* @n_items: (out) (caller-allocates): number of unfiltered items in
|
||||
* list
|
||||
*
|
||||
* Checks if elements in self->items are filtered out and returns
|
||||
* the range that they occupy.
|
||||
* This function is intended to be used for GListModel::items-changed
|
||||
* emissions, so it is called in an intermediate state for @self.
|
||||
*
|
||||
* Returns: %TRUE if elements are filtered out, %FALSE if none are
|
||||
**/
|
||||
static gboolean
|
||||
gtk_filter_list_model_find_filtered (GtkFilterListModel *self,
|
||||
guint *start,
|
||||
guint *end,
|
||||
guint *n_items)
|
||||
{
|
||||
FilterNode *root, *node, *tmp;
|
||||
FilterAugment *aug;
|
||||
|
||||
if (self->items == NULL || self->model == NULL)
|
||||
return FALSE;
|
||||
|
||||
root = gtk_rb_tree_get_root (self->items);
|
||||
if (root == NULL)
|
||||
return FALSE; /* empty parent model */
|
||||
|
||||
aug = gtk_rb_tree_get_augment (self->items, root);
|
||||
if (aug->n_items == aug->n_visible)
|
||||
return FALSE; /* all items visible */
|
||||
|
||||
/* find first filtered */
|
||||
*start = 0;
|
||||
*end = 0;
|
||||
*n_items = aug->n_visible;
|
||||
|
||||
node = root;
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
||||
if (aug->n_visible < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
*start += aug->n_items;
|
||||
}
|
||||
|
||||
if (!node->visible)
|
||||
break;
|
||||
|
||||
(*start)++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
/* find last filtered by doing everything the opposite way */
|
||||
node = root;
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_right (node);
|
||||
if (tmp)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
||||
if (aug->n_visible < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
*end += aug->n_items;
|
||||
}
|
||||
|
||||
if (!node->visible)
|
||||
break;
|
||||
|
||||
(*end)++;
|
||||
|
||||
node = gtk_rb_tree_node_get_left (node);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
if (self->matches)
|
||||
gtk_bitset_remove_all (self->matches);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self);
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self,
|
||||
GtkFilterChange change)
|
||||
{
|
||||
GtkFilterMatch new_strictness;
|
||||
|
||||
@@ -532,8 +413,9 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
guint n_before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
self->strictness = new_strictness;
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
if (n_before > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_before, 0);
|
||||
}
|
||||
@@ -553,16 +435,35 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
{
|
||||
guint start, end, n_before, n_after;
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
self->strictness = new_strictness;
|
||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_before))
|
||||
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
start = gtk_bitset_get_minimum (self->matches);
|
||||
end = gtk_bitset_get_maximum (self->matches);
|
||||
|
||||
n_before = gtk_bitset_get_size (self->matches);
|
||||
if (n_before == n_after)
|
||||
{
|
||||
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
GtkBitset *inverse;
|
||||
|
||||
inverse = gtk_bitset_new_range (0, n_after);
|
||||
gtk_bitset_subtract (inverse, self->matches);
|
||||
/* otherwise all items would be visible */
|
||||
g_assert (!gtk_bitset_is_empty (inverse));
|
||||
|
||||
/* find first filtered */
|
||||
start = gtk_bitset_get_minimum (inverse);
|
||||
end = n_after - gtk_bitset_get_maximum (inverse) - 1;
|
||||
|
||||
gtk_bitset_unref (inverse);
|
||||
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -574,40 +475,44 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
break;
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
GtkBitset *old, *pending;
|
||||
|
||||
if (self->matches == NULL)
|
||||
{
|
||||
guint n_after;
|
||||
self->strictness = new_strictness;
|
||||
self->items = gtk_rb_tree_new (FilterNode,
|
||||
FilterAugment,
|
||||
gtk_filter_list_model_augment,
|
||||
NULL, NULL);
|
||||
n_after = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (self->model));
|
||||
if (n_after > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, 0, n_after);
|
||||
if (self->strictness == GTK_FILTER_MATCH_ALL)
|
||||
old = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
else
|
||||
old = gtk_bitset_new_empty ();
|
||||
}
|
||||
break;
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
else
|
||||
{
|
||||
guint start, end, n_before, n_after;
|
||||
self->strictness = new_strictness;
|
||||
self->items = gtk_rb_tree_new (FilterNode,
|
||||
FilterAugment,
|
||||
gtk_filter_list_model_augment,
|
||||
NULL, NULL);
|
||||
n_before = g_list_model_get_n_items (self->model);
|
||||
gtk_filter_list_model_add_items (self, NULL, 0, n_before);
|
||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_after))
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
old = self->matches;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
gtk_filter_list_model_refilter (self);
|
||||
break;
|
||||
}
|
||||
self->strictness = new_strictness;
|
||||
switch (change)
|
||||
{
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_CHANGE_DIFFERENT:
|
||||
self->matches = gtk_bitset_new_empty ();
|
||||
pending = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
break;
|
||||
case GTK_FILTER_CHANGE_LESS_STRICT:
|
||||
self->matches = gtk_bitset_copy (old);
|
||||
pending = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
gtk_bitset_subtract (pending, self->matches);
|
||||
break;
|
||||
case GTK_FILTER_CHANGE_MORE_STRICT:
|
||||
self->matches = gtk_bitset_new_empty ();
|
||||
pending = gtk_bitset_copy (old);
|
||||
break;
|
||||
}
|
||||
gtk_filter_list_model_start_filtering (self, pending);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +521,7 @@ gtk_filter_list_model_filter_changed_cb (GtkFilter *filter,
|
||||
GtkFilterChange change,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, change);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -636,7 +541,7 @@ gtk_filter_list_model_dispose (GObject *object)
|
||||
|
||||
gtk_filter_list_model_clear_model (self);
|
||||
gtk_filter_list_model_clear_filter (self);
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -663,16 +568,16 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:item-type:
|
||||
* GtkFilterListModel:incremental:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
* If the model should filter items incrementally
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
properties[PROP_INCREMENTAL] =
|
||||
g_param_spec_boolean ("incremental",
|
||||
P_("Incremental"),
|
||||
P_("Filter items incrementally"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:model:
|
||||
@@ -684,7 +589,19 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
P_("Model"),
|
||||
P_("The model being filtered"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:pending:
|
||||
*
|
||||
* Number of items not yet filtered
|
||||
*/
|
||||
properties[PROP_PENDING] =
|
||||
g_param_spec_uint ("pending",
|
||||
P_("Pending"),
|
||||
P_("Number of items not yet filtered"),
|
||||
0, G_MAXUINT, 0,
|
||||
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
@@ -697,7 +614,7 @@ gtk_filter_list_model_init (GtkFilterListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new:
|
||||
* @model: the model to sort
|
||||
* @model: (allow-none): the model to sort
|
||||
* @filter: (allow-none): filter or %NULL to not filter items
|
||||
*
|
||||
* Creates a new #GtkFilterListModel that will filter @model using the given
|
||||
@@ -711,10 +628,10 @@ gtk_filter_list_model_new (GListModel *model,
|
||||
{
|
||||
GtkFilterListModel *result;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (filter == NULL || GTK_IS_FILTER (filter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
@@ -722,26 +639,6 @@ gtk_filter_list_model_new (GListModel *model,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new_for_type:
|
||||
* @item_type: the type of the items that will be returned
|
||||
*
|
||||
* Creates a new empty filter list model set up to return items of type @item_type.
|
||||
* It is up to the application to set a proper filter and model to ensure
|
||||
* the item type is matched.
|
||||
*
|
||||
* Returns: a new #GtkFilterListModel
|
||||
**/
|
||||
GtkFilterListModel *
|
||||
gtk_filter_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_set_filter:
|
||||
* @self: a #GtkFilterListModel
|
||||
@@ -769,7 +666,7 @@ gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTER]);
|
||||
@@ -828,13 +725,18 @@ gtk_filter_list_model_set_model (GtkFilterListModel *self,
|
||||
if (removed == 0)
|
||||
{
|
||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||
added = 0;
|
||||
}
|
||||
else if (self->items)
|
||||
added = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model));
|
||||
else if (self->matches)
|
||||
{
|
||||
gtk_filter_list_model_start_filtering (self, gtk_bitset_new_range (0, g_list_model_get_n_items (model)));
|
||||
added = gtk_bitset_get_size (self->matches);
|
||||
}
|
||||
else
|
||||
added = g_list_model_get_n_items (model);
|
||||
{
|
||||
added = g_list_model_get_n_items (model);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -864,54 +766,89 @@ gtk_filter_list_model_get_model (GtkFilterListModel *self)
|
||||
return self->model;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self)
|
||||
/**
|
||||
* gtk_filter_list_model_set_incremental:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @incremental: %TRUE to enable incremental filtering
|
||||
*
|
||||
* When incremental filtering is enabled, the filterlistmodel will not run
|
||||
* filters immediately, but will instead queue an idle handler that
|
||||
* incrementally filters the items and adds them to the list. This of course
|
||||
* means that items are not instantly added to the list, but only appear
|
||||
* incrementally.
|
||||
*
|
||||
* When your filter blocks the UI while filtering, you might consider
|
||||
* turning this on. Depending on your model and filters, this may become
|
||||
* interesting around 10,000 to 100,000 items.
|
||||
*
|
||||
* By default, incremental filtering is disabled.
|
||||
**/
|
||||
void
|
||||
gtk_filter_list_model_set_incremental (GtkFilterListModel *self,
|
||||
gboolean incremental)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, first_change, last_change;
|
||||
guint n_is_visible, n_was_visible;
|
||||
gboolean visible;
|
||||
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
|
||||
if (self->items == NULL || self->model == NULL)
|
||||
|
||||
if (self->incremental == incremental)
|
||||
return;
|
||||
|
||||
first_change = G_MAXUINT;
|
||||
last_change = 0;
|
||||
n_is_visible = 0;
|
||||
n_was_visible = 0;
|
||||
for (i = 0, node = gtk_rb_tree_get_first (self->items);
|
||||
node != NULL;
|
||||
i++, node = gtk_rb_tree_node_get_next (node))
|
||||
{
|
||||
visible = gtk_filter_list_model_run_filter (self, i);
|
||||
if (visible == node->visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
n_is_visible++;
|
||||
n_was_visible++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
self->incremental = incremental;
|
||||
|
||||
node->visible = visible;
|
||||
gtk_rb_tree_node_mark_dirty (node);
|
||||
first_change = MIN (n_is_visible, first_change);
|
||||
if (visible)
|
||||
n_is_visible++;
|
||||
else
|
||||
n_was_visible++;
|
||||
last_change = MAX (n_is_visible, last_change);
|
||||
if (!incremental)
|
||||
{
|
||||
GtkBitset *old;
|
||||
gtk_filter_list_model_run_filter (self, G_MAXUINT);
|
||||
|
||||
old = gtk_bitset_copy (self->matches);
|
||||
gtk_filter_list_model_run_filter (self, 512);
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
}
|
||||
|
||||
if (first_change <= last_change)
|
||||
{
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
first_change,
|
||||
last_change - first_change + n_was_visible - n_is_visible,
|
||||
last_change - first_change);
|
||||
}
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INCREMENTAL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_incremental:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Returns whether incremental filtering was enabled via
|
||||
* gtk_filter_list_model_set_incremental().
|
||||
*
|
||||
* Returns: %TRUE if incremental filtering is enabled
|
||||
**/
|
||||
gboolean
|
||||
gtk_filter_list_model_get_incremental (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE);
|
||||
|
||||
return self->incremental;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_pending:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Returns the number of items that have not been filtered yet.
|
||||
*
|
||||
* When incremental filtering is not enabled, this always returns 0.
|
||||
*
|
||||
* You can use this value to check if @self is busy filtering by
|
||||
* comparing the return value to 0 or you can compute the percentage
|
||||
* of the filter remaining by dividing the return value by
|
||||
* g_list_model_get_n_items(gtk_filter_list_model_get_model (self)).
|
||||
*
|
||||
* Returns: The number of items not yet filtered
|
||||
**/
|
||||
guint
|
||||
gtk_filter_list_model_get_pending (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE);
|
||||
|
||||
if (self->pending == NULL)
|
||||
return 0;
|
||||
|
||||
return gtk_bitset_get_size (self->pending);
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ G_DECLARE_FINAL_TYPE (GtkFilterListModel, gtk_filter_list_model, GTK, FILTER_LIS
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new (GListModel *model,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
@@ -52,6 +50,14 @@ void gtk_filter_list_model_set_model (GtkFilterListMo
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_filter_list_model_get_model (GtkFilterListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_incremental (GtkFilterListModel *self,
|
||||
gboolean incremental);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_filter_list_model_get_incremental (GtkFilterListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_filter_list_model_get_pending (GtkFilterListModel *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
@@ -64,7 +63,6 @@ struct _GtkFlattenListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkRbTree *items; /* NULL if model == NULL */
|
||||
};
|
||||
@@ -157,9 +155,7 @@ gtk_flatten_list_model_get_nth_model (GtkRbTree *tree,
|
||||
static GType
|
||||
gtk_flatten_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -299,7 +295,6 @@ gtk_flatten_list_model_add_items (GtkFlattenListModel *self,
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->model = g_list_model_get_item (self->model, position + i);
|
||||
g_warn_if_fail (g_type_is_a (g_list_model_get_item_type (node->model), self->item_type));
|
||||
g_signal_connect (node->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_flatten_list_model_items_changed_cb),
|
||||
@@ -321,10 +316,6 @@ gtk_flatten_list_model_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_flatten_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -345,10 +336,6 @@ gtk_flatten_list_model_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
@@ -416,18 +403,6 @@ gtk_flatten_list_model_class_init (GtkFlattenListModelClass *class)
|
||||
gobject_class->get_property = gtk_flatten_list_model_get_property;
|
||||
gobject_class->dispose = gtk_flatten_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:model:
|
||||
*
|
||||
@@ -450,26 +425,20 @@ gtk_flatten_list_model_init (GtkFlattenListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_flatten_list_model_new:
|
||||
* @item_type: The type of items in the to-be-flattened models
|
||||
* @model: (nullable) (transfer none): the item to be flattened
|
||||
* @model: (nullable) (transfer none): the model to be flattened
|
||||
*
|
||||
* Creates a new #GtkFlattenListModel that flattens @list. The
|
||||
* models returned by @model must conform to the given @item_type,
|
||||
* either by having an identical type or a subtype.
|
||||
* Creates a new #GtkFlattenListModel that flattens @list.
|
||||
*
|
||||
* Returns: a new #GtkFlattenListModel
|
||||
**/
|
||||
GtkFlattenListModel *
|
||||
gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model)
|
||||
gtk_flatten_list_model_new (GListModel *model)
|
||||
{
|
||||
GtkFlattenListModel *result;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FLATTEN_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
"model", model,
|
||||
NULL);
|
||||
|
||||
@@ -481,8 +450,7 @@ gtk_flatten_list_model_new (GType item_type,
|
||||
* @self: a #GtkFlattenListModel
|
||||
* @model: (nullable) (transfer none): the new model or %NULL
|
||||
*
|
||||
* Sets a new model to be flattened. The model must contain items of
|
||||
* #GListModel that conform to the item type of @self.
|
||||
* Sets a new model to be flattened.
|
||||
**/
|
||||
void
|
||||
gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
@@ -492,10 +460,6 @@ gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
|
||||
g_return_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
if (model)
|
||||
{
|
||||
g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), G_TYPE_LIST_MODEL));
|
||||
}
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
@@ -36,8 +36,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkFlattenListModel, gtk_flatten_list_model, GTK, FLATTEN_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFlattenListModel * gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model);
|
||||
GtkFlattenListModel * gtk_flatten_list_model_new (GListModel *model);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
|
||||
@@ -784,7 +784,7 @@ update_fontlist (GtkFontChooserWidget *self)
|
||||
if ((self->level & GTK_FONT_CHOOSER_LEVEL_STYLE) == 0)
|
||||
model = g_object_ref (G_LIST_MODEL (fontmap));
|
||||
else
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (PANGO_TYPE_FONT_FACE, G_LIST_MODEL (fontmap)));
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (fontmap)));
|
||||
gtk_filter_list_model_set_model (self->filter_model, model);
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkfunctionslistitemfactory.h"
|
||||
|
||||
#include "gtklistitemfactoryprivate.h"
|
||||
#include "gtklistitemprivate.h"
|
||||
|
||||
struct _GtkFunctionsListItemFactory
|
||||
{
|
||||
GtkListItemFactory parent_instance;
|
||||
|
||||
GtkListItemSetupFunc setup_func;
|
||||
GtkListItemBindFunc bind_func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_destroy;
|
||||
};
|
||||
|
||||
struct _GtkFunctionsListItemFactoryClass
|
||||
{
|
||||
GtkListItemFactoryClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkFunctionsListItemFactory, gtk_functions_list_item_factory, GTK_TYPE_LIST_ITEM_FACTORY)
|
||||
|
||||
static void
|
||||
gtk_functions_list_item_factory_setup (GtkListItemFactory *factory,
|
||||
GtkListItemWidget *widget,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (factory);
|
||||
|
||||
if (self->setup_func)
|
||||
self->setup_func (list_item, self->user_data);
|
||||
|
||||
GTK_LIST_ITEM_FACTORY_CLASS (gtk_functions_list_item_factory_parent_class)->setup (factory, widget, list_item);
|
||||
|
||||
if (gtk_list_item_get_item (list_item) != NULL && self->bind_func)
|
||||
self->bind_func (list_item, self->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_functions_list_item_factory_update (GtkListItemFactory *factory,
|
||||
GtkListItemWidget *widget,
|
||||
GtkListItem *list_item,
|
||||
guint position,
|
||||
gpointer item,
|
||||
gboolean selected)
|
||||
{
|
||||
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (factory);
|
||||
|
||||
GTK_LIST_ITEM_FACTORY_CLASS (gtk_functions_list_item_factory_parent_class)->update (factory, widget, list_item, position, item, selected);
|
||||
|
||||
if (item != NULL && self->bind_func)
|
||||
self->bind_func (list_item, self->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_functions_list_item_factory_finalize (GObject *object)
|
||||
{
|
||||
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (object);
|
||||
|
||||
if (self->user_destroy)
|
||||
self->user_destroy (self->user_data);
|
||||
|
||||
G_OBJECT_CLASS (gtk_functions_list_item_factory_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_functions_list_item_factory_class_init (GtkFunctionsListItemFactoryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkListItemFactoryClass *factory_class = GTK_LIST_ITEM_FACTORY_CLASS (klass);
|
||||
|
||||
object_class->finalize = gtk_functions_list_item_factory_finalize;
|
||||
|
||||
factory_class->setup = gtk_functions_list_item_factory_setup;
|
||||
factory_class->update = gtk_functions_list_item_factory_update;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_functions_list_item_factory_init (GtkFunctionsListItemFactory *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_functions_list_item_factory_new: (skip)
|
||||
* @setup_func: (scope call) (destroy user_destroy): the setup function for the list item factory
|
||||
* @bind_func: (scope call) (destroy user_destroy): the bind function for the list item factory
|
||||
* @user_data: user data for the @setup_func and @bind_func functions
|
||||
* @user_destroy: a function called to destroy @user_data
|
||||
*
|
||||
* Creates a new #GtkListItemFactory with the given functions.
|
||||
*
|
||||
* Returns: (transfer full): the newly created list item factory object
|
||||
*/
|
||||
GtkListItemFactory *
|
||||
gtk_functions_list_item_factory_new (GtkListItemSetupFunc setup_func,
|
||||
GtkListItemBindFunc bind_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
GtkFunctionsListItemFactory *self;
|
||||
|
||||
g_return_val_if_fail (setup_func || bind_func, NULL);
|
||||
g_return_val_if_fail (user_data != NULL || user_destroy == NULL, NULL);
|
||||
|
||||
self = g_object_new (GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, NULL);
|
||||
|
||||
self->setup_func = setup_func;
|
||||
self->bind_func = bind_func;
|
||||
self->user_data = user_data;
|
||||
self->user_destroy = user_destroy;
|
||||
|
||||
return GTK_LIST_ITEM_FACTORY (self);
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* 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.1 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_FUNCTIONS_LIST_ITEM_FACTORY_H__
|
||||
#define __GTK_FUNCTIONS_LIST_ITEM_FACTORY_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtklistitemfactory.h>
|
||||
#include <gtk/gtklistitem.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY (gtk_functions_list_item_factory_get_type ())
|
||||
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactory))
|
||||
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactoryClass))
|
||||
#define GTK_IS_FUNCTIONS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY))
|
||||
#define GTK_IS_FUNCTIONS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY))
|
||||
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactoryClass))
|
||||
|
||||
typedef struct _GtkFunctionsListItemFactory GtkFunctionsListItemFactory;
|
||||
typedef struct _GtkFunctionsListItemFactoryClass GtkFunctionsListItemFactoryClass;
|
||||
|
||||
/**
|
||||
* GtkListItemSetupFunc:
|
||||
* @item: the #GtkListItem to set up
|
||||
* @user_data: (closure): user data
|
||||
*
|
||||
* Called whenever a new list item needs to be setup for managing a row in
|
||||
* the list.
|
||||
*
|
||||
* At this point, the list item is not bound yet, so gtk_list_item_get_item()
|
||||
* will return %NULL.
|
||||
* The list item will later be bound to an item via the #GtkListItemBindFunc.
|
||||
*/
|
||||
typedef void (* GtkListItemSetupFunc) (GtkListItem *item, gpointer user_data);
|
||||
|
||||
/**
|
||||
* GtkListItemBindFunc:
|
||||
* @item: the #GtkListItem to bind
|
||||
* @user_data: (closure): user data
|
||||
*
|
||||
* Binds a#GtkListItem previously set up via a #GtkListItemSetupFunc to
|
||||
* an @item.
|
||||
*
|
||||
* Rebinding a @item to different @items is supported as well as
|
||||
* unbinding it by setting @item to %NULL.
|
||||
*/
|
||||
typedef void (* GtkListItemBindFunc) (GtkListItem *item,
|
||||
gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_functions_list_item_factory_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkListItemFactory * gtk_functions_list_item_factory_new (GtkListItemSetupFunc setup_func,
|
||||
GtkListItemBindFunc bind_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_FUNCTIONS_LIST_ITEM_FACTORY_H__ */
|
||||
@@ -1171,6 +1171,8 @@ gtk_grid_view_init (GtkGridView *self)
|
||||
gtk_list_base_set_anchor_max_widgets (GTK_LIST_BASE (self),
|
||||
self->max_columns * GTK_GRID_VIEW_MAX_VISIBLE_ROWS,
|
||||
self->max_columns);
|
||||
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "view");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -595,7 +595,7 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
|
||||
g_param_spec_boolean ("show-title-buttons",
|
||||
P_("Show title buttons"),
|
||||
P_("Whether to show title buttons"),
|
||||
FALSE,
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
@@ -629,6 +629,7 @@ gtk_header_bar_init (GtkHeaderBar *bar)
|
||||
|
||||
priv->title_widget = NULL;
|
||||
priv->decoration_layout = NULL;
|
||||
priv->show_title_buttons = TRUE;
|
||||
priv->state = GDK_SURFACE_STATE_WITHDRAWN;
|
||||
|
||||
priv->handle = gtk_window_handle_new ();
|
||||
@@ -646,6 +647,7 @@ gtk_header_bar_init (GtkHeaderBar *bar)
|
||||
gtk_center_box_set_end_widget (GTK_CENTER_BOX (priv->center_box), priv->end_box);
|
||||
|
||||
construct_title_label (bar);
|
||||
create_window_controls (bar);
|
||||
}
|
||||
|
||||
static GtkBuildableIface *parent_buildable_iface;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user