Compare commits

..

1 Commits

Author SHA1 Message Date
Matthias Clasen
c640e4a4cc wip: Add a bin with slack
Just an experiment: Make a bin that adds 'slack' around
its child, and avoids resizing unless the child size changes
more than the slack allows.
2020-05-18 21:18:36 -04:00
629 changed files with 34975 additions and 147013 deletions

View File

@@ -17,12 +17,7 @@ stages:
# Common variables
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:v18"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
DOCS_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora-docs:v19"
.only-default:
only:
@@ -32,14 +27,14 @@ variables:
style-check-diff:
extends: .only-default
image: $FEDORA_IMAGE
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v17
stage: .pre
allow_failure: true
script:
- .gitlab-ci/run-style-check-diff.sh
.build-fedora-default:
image: $FEDORA_IMAGE
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v17
artifacts:
when: always
reports:
@@ -71,7 +66,11 @@ fedora-x86_64:
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS}
-Dx11-backend=true
-Dwayland-backend=true
-Dbroadway-backend=true
-Dvulkan=yes
-Dprofiler=true
_build
- ninja -C _build
@@ -85,7 +84,11 @@ release-build:
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS}
-Dx11-backend=true
-Dwayland-backend=true
-Dbroadway-backend=true
-Dvulkan=yes
_build
- ninja -C _build
- .gitlab-ci/run-tests.sh _build x11
@@ -114,7 +117,7 @@ msys2-mingw32:
CHERE_INVOKING: "yes"
.flatpak-defaults:
image: $FLATPAK_IMAGE
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
stage: flatpak
allow_failure: true
tags:
@@ -168,7 +171,7 @@ flatpak-master:icon-browser:
APPID: org.gtk.IconBrowser4
static-scan:
image: $FEDORA_IMAGE
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v16
stage: analysis
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug"
@@ -181,7 +184,7 @@ static-scan:
allow_failure: true
reference:
image: $DOCS_IMAGE
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v16
stage: docs
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"

View File

@@ -1,89 +0,0 @@
FROM fedora:31
RUN dnf -y install \
adwaita-icon-theme \
atk-devel \
at-spi2-atk-devel \
avahi-gobject-devel \
cairo-devel \
cairo-gobject-devel \
ccache \
clang \
clang-analyzer \
colord-devel \
cups-devel \
dbus-daemon \
dbus-x11 \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
elfutils-libelf-devel \
fribidi-devel \
gcc \
gcc-c++ \
gdk-pixbuf2-devel \
gdk-pixbuf2-modules \
gettext \
git \
glib2-devel \
glib2-static \
glibc-devel \
glibc-headers \
gobject-introspection-devel \
graphene-devel \
gstreamer1-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
gstreamer1-plugins-base-devel \
gtk-doc \
hicolor-icon-theme \
iso-codes \
itstool \
json-glib-devel \
lcov \
libattr-devel \
libcloudproviders-devel \
libepoxy-devel \
libffi-devel \
libmount-devel \
librsvg2 \
libselinux-devel \
libXcomposite-devel \
libXcursor-devel \
libXcursor-devel \
libXdamage-devel \
libXfixes-devel \
libXi-devel \
libXinerama-devel \
libxkbcommon-devel \
libXrandr-devel \
libXrender-devel \
libXtst-devel \
libxslt \
mesa-dri-drivers \
mesa-libEGL-devel \
mesa-libwayland-egl-devel \
ninja-build \
pango-devel \
pcre-devel \
pcre-static \
python3 \
python3-jinja2 \
python3-pip \
python3-pygments \
python3-wheel \
redhat-rpm-config \
sassc \
sysprof-devel \
systemtap-sdt-devel \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
weston \
weston-libs \
which \
xorg-x11-server-Xvfb \
&& dnf clean all
RUN pip3 install meson==0.53.1

View File

@@ -1,12 +0,0 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
RUN dnf -y install pandoc
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -1,4 +1,90 @@
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v20
FROM fedora:31
RUN dnf -y install \
adwaita-icon-theme \
atk-devel \
at-spi2-atk-devel \
avahi-gobject-devel \
cairo-devel \
cairo-gobject-devel \
ccache \
clang \
clang-analyzer \
colord-devel \
cups-devel \
dbus-daemon \
dbus-x11 \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
elfutils-libelf-devel \
fribidi-devel \
gcc \
gcc-c++ \
gdk-pixbuf2-devel \
gdk-pixbuf2-modules \
gettext \
git \
glib2-devel \
glib2-static \
glibc-devel \
glibc-headers \
gobject-introspection-devel \
graphene-devel \
gstreamer1-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
gstreamer1-plugins-base-devel \
gtk-doc \
hicolor-icon-theme \
iso-codes \
itstool \
json-glib-devel \
lcov \
libattr-devel \
libepoxy-devel \
libffi-devel \
libmount-devel \
librsvg2 \
libselinux-devel \
libXcomposite-devel \
libXcursor-devel \
libXcursor-devel \
libXdamage-devel \
libXfixes-devel \
libXi-devel \
libXinerama-devel \
libxkbcommon-devel \
libXrandr-devel \
libXrender-devel \
libXtst-devel \
libxslt \
mesa-dri-drivers \
mesa-libEGL-devel \
mesa-libwayland-egl-devel \
ninja-build \
pango-devel \
pcre-devel \
pcre-static \
python3 \
python3-jinja2 \
python3-pip \
python3-pygments \
python3-wheel \
redhat-rpm-config \
sassc \
sysprof-devel \
systemtap-sdt-devel \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
weston \
weston-libs \
which \
xorg-x11-server-Xvfb \
&& dnf clean all
RUN pip3 install meson==0.53.1
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}

View File

@@ -25,7 +25,7 @@ case "${backend}" in
wayland)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
weston --backend=headless-backend.so --socket=wayland-5 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5

View File

@@ -34,8 +34,8 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-shared-mime-info
# https://gitlab.gnome.org/GNOME/gtk/issues/2243
wget "https://gitlab.gnome.org/creiter/gitlab-ci-win32-runner-v2/raw/master/pango/mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
pacman --noconfirm -U "mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
wget "https://gitlab.gnome.org/creiter/gitlab-ci-win32-runner-v2/raw/master/pango/mingw-w64-$MSYS2_ARCH-pango-1.44.7-1-any.pkg.tar.xz"
pacman --noconfirm -U "mingw-w64-$MSYS2_ARCH-pango-1.44.7-1-any.pkg.tar.xz"
# https://github.com/msys2/MINGW-packages/pull/6465
pacman --noconfirm -S --needed mingw-w64-$MSYS2_ARCH-brotli

89
NEWS
View File

@@ -1,92 +1,3 @@
Overview of Changes in GTK 3.98.5
=================================
* Introduce new list widgets and supporting infrastructure.
The main APIs are:
- GtkListView
- GtkGridView
- GtkColumnView and GtkColumnViewColumn
- GtkDropDown
- GtkListItemFactory and implementations
- GtkExpression
- GtkFilter and subclasses, and GtkFilterListModel
- GtkSorter and subclasses, and GtkSortListModel
- GtkSelectionModel and subclasses
- GtkTreeListModel, GtkTreeExpander and GtkTreeListRowSorter
* GtkFileChooser:
- Add a tracker3-based search engine implementation
- Rate-limit updates from the trash monitor
* GtkWindow:
- Redo the css node setup. There is now a single 'window' node
- Fix rounded corners on tiled windows
* GtkApplication:
- Drop app menu support. Menubar support is still there
* GtkFixed:
- Change coordinate APIs to take doubles
* GtkOverlay:
- Make GtkOverlayLayout public
* GtkTooltips:
- Fix line wrapping of tooltips
* Shortcuts:
- Fix mnemonic cycling
- Fix using '0' as a mnemonic
* Menus:
- Differentiate keypad keys in accelerators
* GtkIMContext:
- Add gtk_im_context_filter_key to allow event reinjection
* Themes:
- Adwaita: Limit the scope of backdrop
* Accessibility:
- Clean up and reorganize the code to prepare for the
dropping of ATK
* GDK:
- Drop unused enum and struct definitions from headers
- Make keymap translation API public again. Still needed
- Frameclock: Always use compositor refresh rate info
- Frameclock: Use quadratic correction for frame time jitter
- Frameclock: Ensure monotonicity
- Frameclock: Track resason for paint
- X11: Improve sync when the Nvidia driver is used
* GSK:
- GL renderer: Fix blurred outset shadows
- GL renderer: handle nested transform nodes properly
- GL renderer: Optimize clip handling
* gtk-demo:
- Improve the Drag-and-Drop demo with proper drag icons
- Don't show the main window if --run is given
- Add demos for list widgets and GtkDropDrown
* Documentation:
- Convert freestanding sections to markdown
- Drop the glossary
- Expand and improve the migration guide
* Build:
- We require pandoc now, for building the documentation
- Require Pango 1.45
* Translation updates:
Polish
Romanian
Slovenian
Turkish
Ukrainian
Overview of Changes in GTK 3.98.4
=================================

View File

@@ -27,6 +27,14 @@
/* Define to 1 if you have the `dcgettext' function. */
#mesondefine HAVE_DCGETTEXT
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISINF
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISNAN
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
@@ -72,6 +80,9 @@
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP
/* Define to 1 if you have the `nearbyint' function. */
#mesondefine HAVE_NEARBYINT
/* Define to 1 if you have the `posix_fallocate' function. */
#mesondefine HAVE_POSIX_FALLOCATE
@@ -81,9 +92,21 @@
/* Have the Xrandr 1.5 extension library */
#mesondefine HAVE_RANDR15
/* Define to 1 if you have the `rint' function. */
#mesondefine HAVE_RINT
/* Define to 1 if you have the `round' function. */
#mesondefine HAVE_ROUND
/* Define to 1 if you have the `sincos' function. */
#mesondefine HAVE_SINCOS
/* Define to 1 if you have the `log2` function */
#mesondefine HAVE_LOG2
/* Define to 1 if you ahve the `exp2` function */
#mesondefine HAVE_EXP2
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
@@ -123,9 +146,6 @@
/* Have the Xcursor library */
#mesondefine HAVE_XCURSOR
/* Have the XDAMAGE X extension */
#mesondefine HAVE_XDAMAGE
/* Have the XFIXES X extension */
#mesondefine HAVE_XFIXES
@@ -272,6 +292,3 @@
#mesondefine HAVE_PANGOFT
#mesondefine ISO_CODES_PREFIX
/* Define if tracker3 is available */
#mesondefine HAVE_TRACKER3

View File

@@ -487,6 +487,8 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->finalize = constraint_editor_window_finalize;
gtk_widget_class_set_template_from_resource (widget_class,

View File

@@ -169,7 +169,6 @@ constraint_view_init (ConstraintView *self)
GListModel *guides;
GListModel *children;
GListModel *constraints;
GtkFilter *filter;
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
@@ -177,12 +176,8 @@ constraint_view_init (ConstraintView *self)
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
g_object_unref (filter);
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
g_object_unref (filter);
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, omit_internal, NULL, NULL);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);

View File

@@ -23,7 +23,6 @@
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
G_MODULE_EXPORT
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
ConstraintView * constraint_view_new (void);

View File

@@ -184,6 +184,58 @@ max_input (GtkSpinButton *spin_button,
return FALSE;
}
static gboolean
min_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == 0.0)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static gboolean
max_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == (double)G_MAXINT)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static void
guide_editor_constructed (GObject *object)
{
@@ -192,12 +244,16 @@ guide_editor_constructed (GObject *object)
guide_strength_combo (editor->strength);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_width, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_width, "output", G_CALLBACK (max_output), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "output", G_CALLBACK (max_output), NULL);
if (editor->guide)
{

View File

@@ -328,14 +328,19 @@ static void
startup (GApplication *app)
{
GtkBuilder *builder;
GMenuModel *appmenu;
GMenuModel *menubar;
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/application_demo/menus.ui", NULL);
gtk_application_set_menubar (GTK_APPLICATION (app),
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder);
}
@@ -348,7 +353,6 @@ create_window (GApplication *app,
window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (),
"application", app,
"show-menubar", TRUE,
NULL);
if (content)
gtk_text_buffer_set_text (window->buffer, content, -1);

18
demos/gtk-demo/appmenu.ui Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="appmenu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Control&gt;q</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -83,7 +83,7 @@ do_builder (GtkWidget *do_widget)
window);
gtk_widget_insert_action_group (window, "win", actions);
g_object_unref (builder);
g_object_set_data_full (G_OBJECT(window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* Constraints/Interactive
*
* Demonstrate how constraints can be updates during user interaction.
* The vertical edge between the buttons can be dragged with the mouse.
* Demonstrate how constraints can be updates during
* user interaction.
*/
#include <glib/gi18n.h>

View File

@@ -97,7 +97,7 @@ do_css_basics (GtkWidget *do_widget)
container = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_box_append (GTK_BOX (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);

View File

@@ -134,8 +134,6 @@ do_css_blendmodes (GtkWidget *do_widget)
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
setup_listbox (builder, provider);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))

View File

@@ -85,7 +85,7 @@ do_css_multiplebgs (GtkWidget *do_widget)
if (!window)
{
GtkWidget *paned, *overlay, *child, *sw;
GtkWidget *paned, *container, *child;
GtkStyleProvider *provider;
GtkTextBuffer *text;
GBytes *bytes;
@@ -96,25 +96,25 @@ do_css_multiplebgs (GtkWidget *do_widget)
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
container = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), container);
child = gtk_drawing_area_new ();
gtk_widget_set_name (child, "canvas");
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
drawing_area_draw,
NULL, NULL);
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
gtk_box_append (GTK_BOX (container), child);
child = gtk_button_new ();
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
gtk_overlay_add_overlay (GTK_OVERLAY (container), child);
gtk_widget_set_name (child, "bricks-button");
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
gtk_widget_set_size_request (child, 250, 84);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), paned);
gtk_overlay_add_overlay (GTK_OVERLAY (container), paned);
/* Need a filler so we get a handle */
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
@@ -132,10 +132,10 @@ do_css_multiplebgs (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_paned_set_end_child (GTK_PANED (paned), sw);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_paned_set_end_child (GTK_PANED (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
g_signal_connect (text,
"changed",
G_CALLBACK (css_text_changed),

View File

@@ -1,8 +1,9 @@
/* Cursors
*
* Demonstrates a useful set of available cursors. The cursors shown here are the
* ones defined by CSS, which we assume to be available. The example shows creating
* cursors by name or from an image, with or without a fallback.
* Demonstrates a useful set of available cursors. The cursors shown here are the ones
* defined by CSS, which we assume to be available.
*
* The example shows creating cursors by name or from an image, with or without a fallback.
*/
#include <gtk/gtk.h>
@@ -28,7 +29,7 @@ do_cursors (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (on_destroy), NULL);
g_object_unref (builder);
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))

View File

@@ -1,10 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
</gresource>
<gresource prefix="/ui">
<file preprocess="xml-stripblanks">main.ui</file>
<file preprocess="xml-stripblanks">main-listitem.ui</file>
<file preprocess="xml-stripblanks">appmenu.ui</file>
</gresource>
<gresource prefix="/application_demo">
<file>application.c</file>
@@ -121,23 +119,6 @@
<file>gnome-fs-directory.png</file>
<file>gnome-fs-regular.png</file>
</gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
<file>listview_filebrowser.css</file>
</gresource>
<gresource prefix="/listview_minesweeper">
<file>listview_minesweeper.ui</file>
<file>listview_minesweeper_cell.ui</file>
</gresource>
<gresource prefix="/listview_settings">
<file>listview_settings.ui</file>
</gresource>
<gresource prefix="/listview_weather">
<file compressed="true">listview_weather.txt</file>
</gresource>
<gresource prefix="/listview_colors">
<file compressed="true">color.names.txt</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
@@ -190,7 +171,6 @@
<file>cursors.c</file>
<file>dialog.c</file>
<file>drawingarea.c</file>
<file>dropdown.c</file>
<file>dnd.c</file>
<file>editable_cells.c</file>
<file>entry_completion.c</file>
@@ -215,13 +195,6 @@
<file>infobar.c</file>
<file>links.c</file>
<file>listbox.c</file>
<file>listview_applauncher.c</file>
<file>listview_colors.c</file>
<file>listview_clocks.c</file>
<file>listview_filebrowser.c</file>
<file>listview_minesweeper.c</file>
<file>listview_settings.c</file>
<file>listview_weather.c</file>
<file>list_store.c</file>
<file>markup.c</file>
<file>modelbutton.c</file>

View File

@@ -7,292 +7,6 @@
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
struct _CanvasItem {
GtkWidget parent;
GtkWidget *fixed;
GtkWidget *label;
double r;
double angle;
double delta;
GtkWidget *editor;
};
struct _CanvasItemClass {
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
static int n_items = 0;
static void
set_color (CanvasItem *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
str = gdk_rgba_to_string (color);
css = g_strdup_printf ("* { background: %s; padding: 10px; margin: 1px; }", str);
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y)
{
GtkWidget *label = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
CanvasItem *item = CANVAS_ITEM (gtk_widget_get_parent (gtk_widget_get_parent (label)));
set_color (item, g_value_get_boxed (value));
return TRUE;
}
static void
apply_transform (CanvasItem *item)
{
GskTransform *transform;
double x, y;
x = gtk_widget_get_allocated_width (item->label) / 2.0;
y = gtk_widget_get_allocated_height (item->label) / 2.0;
item->r = sqrt (x*x + y*y);
transform = gsk_transform_translate (
gsk_transform_rotate (
gsk_transform_translate (NULL,
&(graphene_point_t) { item->r, item->r }),
item->angle + item->delta),
&(graphene_point_t) { - x, - y });
gtk_fixed_set_child_transform (GTK_FIXED (item->fixed), item->label, transform);
gsk_transform_unref (transform);
}
static void
angle_changed (GtkGestureRotate *gesture,
double angle,
double delta)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->delta = angle / M_PI * 180.0;
apply_transform (item);
}
static void
rotate_done (GtkGesture *gesture)
{
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
item->angle = item->angle + item->delta;
item->delta = 0;
}
static void
click_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
GtkWidget *canvas = gtk_widget_get_parent (item);
GtkWidget *last_child;
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
}
static void
canvas_item_init (CanvasItem *item)
{
char *text;
char *id;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
n_items++;
text = g_strdup_printf ("Item %d", n_items);
item->label = gtk_label_new (text);
g_free (text);
item->fixed = gtk_fixed_new ();
gtk_widget_set_parent (item->fixed, GTK_WIDGET (item));
gtk_fixed_put (GTK_FIXED (item->fixed), item->label, 0, 0);
gtk_widget_add_css_class (item->label, "frame");
id = g_strdup_printf ("item%d", n_items);
gtk_widget_set_name (item->label, id);
g_free (id);
gdk_rgba_parse (&rgba, "yellow");
set_color (item, &rgba);
item->angle = 0;
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (item->label), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
}
static void
canvas_item_dispose (GObject *object)
{
CanvasItem *item = CANVAS_ITEM (object);
g_clear_pointer (&item->fixed, gtk_widget_unparent);
g_clear_pointer (&item->editor, gtk_widget_unparent);
G_OBJECT_CLASS (canvas_item_parent_class)->dispose (object);
}
static void
canvas_item_map (GtkWidget *widget)
{
CanvasItem *item = CANVAS_ITEM (widget);
GTK_WIDGET_CLASS (canvas_item_parent_class)->map (widget);
apply_transform (item);
}
static void
canvas_item_class_init (CanvasItemClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = canvas_item_dispose;
widget_class->map = canvas_item_map;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_css_name (widget_class, "item");
}
static GtkWidget *
canvas_item_new (void)
{
CanvasItem *item = g_object_new (canvas_item_get_type (), NULL);
return GTK_WIDGET (item);
}
static GdkPaintable *
canvas_item_get_drag_icon (CanvasItem *item)
{
return gtk_widget_paintable_new (item->fixed);
}
static gboolean
canvas_item_is_editing (CanvasItem *item)
{
return item->editor != NULL;
}
static void
scale_changed (GtkRange *range,
CanvasItem *item)
{
item->angle = gtk_range_get_value (range);
apply_transform (item);
}
static void
text_changed (GtkEditable *editable,
GParamSpec *pspec,
CanvasItem *item)
{
gtk_label_set_text (GTK_LABEL (item->label), gtk_editable_get_text (editable));
apply_transform (item);
}
static void
canvas_item_stop_editing (CanvasItem *item)
{
GtkWidget *scale;
if (!item->editor)
return;
scale = gtk_widget_get_last_child (item->editor);
g_signal_handlers_disconnect_by_func (scale, scale_changed, item);
gtk_fixed_remove (GTK_FIXED (gtk_widget_get_parent (item->editor)), item->editor);
item->editor = NULL;
}
static void
canvas_item_start_editing (CanvasItem *item)
{
GtkWidget *canvas = gtk_widget_get_parent (GTK_WIDGET (item));
GtkWidget *entry;
GtkWidget *scale;
double x, y;
if (item->editor)
return;
item->editor = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
entry = gtk_entry_new ();
gtk_editable_set_text (GTK_EDITABLE (entry),
gtk_label_get_text (GTK_LABEL (item->label)));
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), item);
g_signal_connect_swapped (entry, "activate", G_CALLBACK (canvas_item_stop_editing), item);
gtk_box_append (GTK_BOX (item->editor), entry);
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 360, 1);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
gtk_range_set_value (GTK_RANGE (scale), fmod (item->angle, 360));
g_signal_connect (scale, "value-changed", G_CALLBACK (scale_changed), item);
gtk_box_append (GTK_BOX (item->editor), scale);
gtk_widget_translate_coordinates (GTK_WIDGET (item), canvas, 0, 0, &x, &y);
gtk_fixed_put (GTK_FIXED (canvas), item->editor, x, y + 2 * item->r);
gtk_widget_grab_focus (entry);
}
static GdkContentProvider *
prepare (GtkDragSource *source,
double x,
@@ -304,8 +18,7 @@ prepare (GtkDragSource *source,
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
item = gtk_widget_get_ancestor (item, canvas_item_get_type ());
if (!item)
if (!GTK_IS_LABEL (item))
return NULL;
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
@@ -318,17 +31,12 @@ drag_begin (GtkDragSource *source,
GdkDrag *drag)
{
GtkWidget *canvas;
CanvasItem *item;
GdkPaintable *paintable;
GtkWidget *item;
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
item = CANVAS_ITEM (g_object_get_data (G_OBJECT (canvas), "dragged-item"));
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
paintable = canvas_item_get_drag_icon (item);
gtk_drag_source_set_icon (source, paintable, item->r, item->r);
g_object_unref (paintable);
gtk_widget_set_opacity (GTK_WIDGET (item), 0.3);
gtk_widget_set_opacity (item, 0.5);
}
static void
@@ -353,56 +61,110 @@ drag_cancel (GtkDragSource *source,
return FALSE;
}
typedef struct {
double x, y;
double angle;
double delta;
} TransformData;
static void
apply_transform (GtkWidget *item)
{
GtkWidget *canvas = gtk_widget_get_parent (item);
TransformData *data;
GskTransform *transform;
data = g_object_get_data (G_OBJECT (item), "transform-data");
transform = gsk_transform_rotate (gsk_transform_translate (NULL, &(graphene_point_t){data->x, data->y}),
data->angle + data->delta);
gtk_fixed_set_child_transform (GTK_FIXED (canvas), item, transform);
gsk_transform_unref (transform);
}
static gboolean
drag_drop (GtkDropTarget *target,
const GValue *value,
double x,
double y)
{
CanvasItem *item;
GtkWidget *item;
TransformData *transform_data;
GtkWidget *canvas;
GtkWidget *last_child;
item = g_value_get_object (value);
transform_data = g_object_get_data (G_OBJECT (item), "transform-data");
canvas = gtk_widget_get_parent (GTK_WIDGET (item));
transform_data->x = x;
transform_data->y = y;
canvas = gtk_widget_get_parent (item);
last_child = gtk_widget_get_last_child (canvas);
if (GTK_WIDGET (item) != last_child)
gtk_widget_insert_after (GTK_WIDGET (item), canvas, last_child);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
gtk_fixed_move (GTK_FIXED (canvas), GTK_WIDGET (item), x - item->r, y - item->r);
apply_transform (item);
return TRUE;
}
static double pos_x, pos_y;
static GtkWidget * canvas_item_new (double x, double y);
static void
new_item_cb (GtkWidget *button, gpointer data)
{
GtkWidget *canvas = data;
GtkWidget *popover;
GtkWidget *item;
GdkRectangle rect;
popover = gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER);
gtk_popover_get_pointing_to (GTK_POPOVER (popover), &rect);
item = canvas_item_new ();
gtk_fixed_put (GTK_FIXED (canvas), item, rect.x, rect.y);
apply_transform (CANVAS_ITEM (item));
item = canvas_item_new (pos_x, pos_y);
gtk_fixed_put (GTK_FIXED (canvas), item, 0, 0);
apply_transform (item);
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
}
static void
edit_label_done (GtkWidget *entry, gpointer data)
{
GtkWidget *canvas = gtk_widget_get_parent (entry);
GtkWidget *label;
int x, y;
gtk_fixed_get_child_position (GTK_FIXED (canvas), entry, &x, &y);
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
gtk_label_set_text (GTK_LABEL (label), gtk_editable_get_text (GTK_EDITABLE (entry)));
gtk_widget_show (label);
gtk_fixed_remove (GTK_FIXED (canvas), entry);
}
static void
edit_cb (GtkWidget *button, GtkWidget *child)
{
CanvasItem *item = CANVAS_ITEM (child);
GtkWidget *canvas = gtk_widget_get_parent (child);
int x, y;
gtk_fixed_get_child_position (GTK_FIXED (canvas), child, &x, &y);
if (GTK_IS_LABEL (child))
{
GtkWidget *entry = gtk_entry_new ();
g_object_set_data (G_OBJECT (entry), "label", child);
gtk_editable_set_text (GTK_EDITABLE (entry), gtk_label_get_text (GTK_LABEL (child)));
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
g_signal_connect (entry, "activate", G_CALLBACK (edit_label_done), NULL);
gtk_fixed_put (GTK_FIXED (canvas), entry, x, y);
gtk_widget_grab_focus (entry);
gtk_widget_hide (child);
}
if (button)
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
if (!canvas_item_is_editing (item))
canvas_item_start_editing (item);
}
static void
@@ -427,7 +189,6 @@ pressed_cb (GtkGesture *gesture,
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, GTK_PICK_DEFAULT);
child = gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_SECONDARY)
{
@@ -435,6 +196,9 @@ pressed_cb (GtkGesture *gesture,
GtkWidget *box;
GtkWidget *item;
pos_x = x;
pos_y = y;
menu = gtk_popover_new ();
gtk_widget_set_parent (menu, widget);
gtk_popover_set_has_arrow (GTK_POPOVER (menu), FALSE);
@@ -478,20 +242,14 @@ released_cb (GtkGesture *gesture,
{
GtkWidget *widget;
GtkWidget *child;
CanvasItem *item;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
child = gtk_widget_pick (widget, x, y, 0);
item = (CanvasItem *)gtk_widget_get_ancestor (child, canvas_item_get_type ());
if (!item)
return;
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_PRIMARY)
{
if (canvas_item_is_editing (item))
canvas_item_stop_editing (item);
else
canvas_item_start_editing (item);
if (child != NULL && child != widget)
edit_cb (NULL, child);
}
}
@@ -529,6 +287,131 @@ canvas_new (void)
return canvas;
}
static void
set_color (GtkWidget *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
str = gdk_rgba_to_string (color);
css = g_strdup_printf ("* { background: %s; padding: 10px; }", str);
context = gtk_widget_get_style_context (item);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (item), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
}
static gboolean
item_drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
set_color (item, g_value_get_boxed (value));
return TRUE;
}
static void
angle_changed (GtkGestureRotate *gesture,
double angle,
double delta)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
data->delta = angle / M_PI * 180.0;
apply_transform (item);
}
static void
rotate_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data");
data->angle = data->angle + data->delta;
data->delta = 0;
}
static void
click_done (GtkGesture *gesture)
{
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
GtkWidget *canvas = gtk_widget_get_parent (item);
GtkWidget *last_child;
last_child = gtk_widget_get_last_child (canvas);
if (item != last_child)
gtk_widget_insert_after (item, canvas, last_child);
}
static int n_items = 0;
static GtkWidget *
canvas_item_new (double x,
double y)
{
GtkWidget *widget;
char *label;
char *id;
TransformData *transform_data;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
n_items++;
label = g_strdup_printf ("Item %d", n_items);
id = g_strdup_printf ("item%d", n_items);
gdk_rgba_parse (&rgba, "yellow");
widget = gtk_label_new (label);
gtk_widget_add_css_class (widget, "frame");
gtk_widget_set_name (widget, id);
set_color (widget, &rgba);
transform_data = g_new0 (TransformData, 1);
transform_data->x = x;
transform_data->y = y;
transform_data->angle = 0.0;
g_object_set_data_full (G_OBJECT (widget), "transform-data", transform_data, g_free);
g_free (label);
g_free (id);
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture));
return widget;
}
static GtkWidget *window = NULL;
GtkWidget *
@@ -575,9 +458,9 @@ do_dnd (GtkWidget *do_widget)
{
GtkWidget *item;
item = canvas_item_new ();
gtk_fixed_put (GTK_FIXED (canvas), item, x, y);
apply_transform (CANVAS_ITEM (item));
item = canvas_item_new (x, y);
gtk_fixed_put (GTK_FIXED (canvas), item, 0, 0);
apply_transform (item);
x += 150;
y += 100;

View File

@@ -1,305 +0,0 @@
/* Drop Downs
*
* 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 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.
*/
#include <gtk/gtk.h>
#define STRING_TYPE_HOLDER (string_holder_get_type ())
G_DECLARE_FINAL_TYPE (StringHolder, string_holder, STRING, HOLDER, GObject)
struct _StringHolder {
GObject parent_instance;
char *title;
char *icon;
char *description;
};
G_DEFINE_TYPE (StringHolder, string_holder, G_TYPE_OBJECT);
static void
string_holder_init (StringHolder *holder)
{
}
static void
string_holder_finalize (GObject *object)
{
StringHolder *holder = STRING_HOLDER (object);
g_free (holder->title);
g_free (holder->icon);
g_free (holder->description);
G_OBJECT_CLASS (string_holder_parent_class)->finalize (object);
}
static void
string_holder_class_init (StringHolderClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = string_holder_finalize;
}
static StringHolder *
string_holder_new (const char *title, const char *icon, const char *description)
{
StringHolder *holder = g_object_new (STRING_TYPE_HOLDER, NULL);
holder->title = g_strdup (title);
holder->icon = g_strdup (icon);
holder->description = g_strdup (description);
return holder;
}
static void
strings_setup_item_single_line (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *image, *title;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
image = gtk_image_new ();
title = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), title);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
gtk_list_item_set_child (item, box);
}
static void
strings_setup_item_full (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *box, *box2, *image, *title, *description;
image = gtk_image_new ();
title = gtk_label_new ("");
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");
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_box_append (GTK_BOX (box), image);
gtk_box_append (GTK_BOX (box), box2);
gtk_box_append (GTK_BOX (box2), title);
gtk_box_append (GTK_BOX (box2), description);
g_object_set_data (G_OBJECT (item), "title", title);
g_object_set_data (G_OBJECT (item), "image", image);
g_object_set_data (G_OBJECT (item), "description", description);
gtk_list_item_set_child (item, box);
}
static void
strings_bind_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *image, *title, *description;
StringHolder *holder;
holder = gtk_list_item_get_item (item);
title = g_object_get_data (G_OBJECT (item), "title");
image = g_object_get_data (G_OBJECT (item), "image");
description = g_object_get_data (G_OBJECT (item), "description");
gtk_label_set_label (GTK_LABEL (title), holder->title);
if (image)
{
gtk_image_set_from_icon_name (GTK_IMAGE (image), holder->icon);
gtk_widget_set_visible (image, holder->icon != NULL);
}
if (description)
{
gtk_label_set_label (GTK_LABEL (description), holder->description);
gtk_widget_set_visible (description , holder->description != NULL);
}
}
static GtkListItemFactory *
strings_factory_new (gboolean full)
{
GtkListItemFactory *factory;
factory = gtk_signal_list_item_factory_new ();
if (full)
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_full), NULL);
else
g_signal_connect (factory, "setup", G_CALLBACK (strings_setup_item_single_line), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (strings_bind_item), NULL);
return factory;
}
static GListModel *
strings_model_new (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GListStore *store;
int i;
store = g_list_store_new (STRING_TYPE_HOLDER);
for (i = 0; titles[i]; i++)
{
StringHolder *holder = string_holder_new (titles[i],
icons ? icons[i] : NULL,
descriptions ? descriptions[i] : NULL);
g_list_store_append (store, holder);
g_object_unref (holder);
}
return G_LIST_MODEL (store);
}
static GtkWidget *
drop_down_new_from_strings (const char *const *titles,
const char *const *icons,
const char *const *descriptions)
{
GtkWidget *widget;
GListModel *model;
GtkListItemFactory *factory;
GtkListItemFactory *list_factory;
g_return_val_if_fail (titles != NULL, NULL);
g_return_val_if_fail (icons == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)titles), NULL);
g_return_val_if_fail (descriptions == NULL || g_strv_length ((char **)icons) == g_strv_length ((char **)descriptions), NULL);
model = strings_model_new (titles, icons, descriptions);
factory = strings_factory_new (FALSE);
if (icons != NULL || descriptions != NULL)
list_factory = strings_factory_new (TRUE);
else
list_factory = NULL;
widget = g_object_new (GTK_TYPE_DROP_DOWN,
"model", model,
"factory", factory,
"list-factory", list_factory,
NULL);
g_object_unref (model);
g_object_unref (factory);
if (list_factory)
g_object_unref (list_factory);
return widget;
}
static char *
get_family_name (gpointer item)
{
return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
}
static char *
get_title (gpointer item)
{
return g_strdup (STRING_HOLDER (item)->title);
}
GtkWidget *
do_dropdown (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *button, *box, *spin, *check;
GListModel *model;
GtkExpression *expression;
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",
"25 minutes", "30 minutes", "35 minutes", "40 minutes", "45 minutes", "50 minutes",
"55 minutes", "1 hour", "2 hours", "3 hours", "5 hours", "6 hours", "7 hours",
"8 hours", "9 hours", "10 hours", "11 hours", "12 hours", NULL
};
const char * const device_titles[] = { "Digital Output", "Headphones", "Digital Output", "Analog Output", NULL };
const char * const device_icons[] = { "audio-card-symbolic", "audio-headphones-symbolic", "audio-card-symbolic", "audio-card-symbolic", NULL };
const char * const device_descriptions[] = {
"Built-in Audio", "Built-in audio", "Thinkpad Tunderbolt 3 Dock USB Audio", "Thinkpad Tunderbolt 3 Dock USB Audio", NULL
};
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_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);
button = gtk_drop_down_new ();
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
0, NULL,
(GCallback)get_family_name,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (button), expression);
gtk_expression_unref (expression);
gtk_box_append (GTK_BOX (box), button);
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);
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");
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);
button = drop_down_new_from_strings (device_titles, device_icons, device_descriptions);
gtk_box_append (GTK_BOX (box), button);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -249,14 +249,6 @@ fishbowl_changes_toggled_cb (GtkToggleButton *button,
gtk_button_set_icon_name (GTK_BUTTON (button), "changes-allow");
}
char *
format_header_cb (GObject *object,
guint count,
double fps)
{
return g_strdup_printf ("%u Icons, %.2f fps", count, fps);
}
GtkWidget *
do_fishbowl (GtkWidget *do_widget)
{

View File

@@ -28,12 +28,22 @@
</child>
<child type="end">
<object class="GtkLabel">
<binding name="label">
<closure type="gchararray" function="format_header_cb">
<lookup name="count">bowl</lookup>
<lookup name="framerate">bowl</lookup>
</closure>
</binding>
<property name="label">fps</property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="framerate-string"/>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label">Icons, </property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="count"/>
</object>
</child>
<child type="end">

View File

@@ -1,4 +1,4 @@
/* Fixed Layout
/* Fixed layout
*
* GtkFixed is a container that allows placing and transforming
* widgets manually.
@@ -126,7 +126,7 @@ create_demo_window (GtkWidget *do_widget)
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Fixed Layout");
gtk_window_set_title (GTK_WINDOW (window), "Fixed layout");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);

View File

@@ -1,10 +1,9 @@
/* Flow Box
*
* GtkFlowBox allows flexible and responsive grids which reflow
* as needed and support sorting and filtering. The children of
* a GtkFlowBox are regular widgets
* as needed and support sorting and filtering.
*
* The dataset used here has 665 colors.
* The children of a GtkFlowBox are regular widgets
*/
#include <gtk/gtk.h>

View File

@@ -13,16 +13,17 @@ in_files = sys.argv[2:]
file_output = """
typedef GtkWidget *(*GDoDemoFunc) (GtkWidget *do_widget);
typedef struct _DemoData DemoData;
typedef struct _Demo Demo;
struct _DemoData
struct _Demo
{
const char *name;
const char *title;
const char *filename;
GDoDemoFunc func;
DemoData *children;
Demo *children;
};
"""
# Demo = namedtuple('Demo', ['name', 'title', 'file', 'func'])
@@ -66,7 +67,7 @@ for demo in demos:
i = 0
for parent in parents:
id = parent_ids[i]
file_output += "\nDemoData child" + str(id) + "[] = {\n"
file_output += "\nDemo child" + str(id) + "[] = {\n"
# iterate over all demos and check if the name starts with the given parent name
for child in demos:
if child[1].startswith(parent + "/"):
@@ -81,7 +82,7 @@ for parent in parents:
# Sort demos by title
demos = sorted(demos, key=lambda x: x[1])
file_output += "\nDemoData gtk_demos[] = {\n"
file_output += "\nDemo gtk_demos[] = {\n"
for demo in demos:
# Do not generate one of these for demos with a parent demo
if "/" not in demo[1]:

View File

@@ -25,7 +25,7 @@ typedef struct _GtkFishbowlChild GtkFishbowlChild;
struct _GtkFishbowlPrivate
{
GtkFishCreationFunc creation_func;
GHashTable *children;
GList *children;
guint count;
gint64 last_frame_time;
@@ -53,6 +53,7 @@ enum {
PROP_BENCHMARK,
PROP_COUNT,
PROP_FRAMERATE,
PROP_FRAMERATE_STRING,
PROP_UPDATE_DELAY,
NUM_PROPERTIES
};
@@ -67,8 +68,6 @@ gtk_fishbowl_init (GtkFishbowl *fishbowl)
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
priv->update_delay = G_USEC_PER_SEC;
priv->children = g_hash_table_new_full (NULL, NULL,
NULL, (GDestroyNotify) g_free);
}
/**
@@ -95,18 +94,16 @@ gtk_fishbowl_measure (GtkWidget *widget,
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GHashTableIter iter;
gpointer key, value;
GtkFishbowlChild *child;
GList *children;
gint child_min, child_nat;
*minimum = 0;
*natural = 0;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (children = priv->children; children; children = children->next)
{
child = value;
child = children->data;
if (!gtk_widget_get_visible (child->widget))
continue;
@@ -140,13 +137,11 @@ gtk_fishbowl_size_allocate (GtkWidget *widget,
GtkFishbowlChild *child;
GtkAllocation child_allocation;
GtkRequisition child_requisition;
GHashTableIter iter;
gpointer key, value;
GList *children;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (children = priv->children; children; children = children->next)
{
child = value;
child = children->data;
if (!gtk_widget_get_visible (child->widget))
continue;
@@ -187,7 +182,7 @@ gtk_fishbowl_add (GtkFishbowl *fishbowl,
gtk_widget_set_parent (widget, GTK_WIDGET (fishbowl));
g_hash_table_insert (priv->children, widget, child_info);
priv->children = g_list_prepend (priv->children, child_info);
priv->count++;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
}
@@ -197,32 +192,34 @@ gtk_fishbowl_remove (GtkFishbowl *fishbowl,
GtkWidget *widget)
{
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GtkWidget *widget_bowl = GTK_WIDGET (fishbowl);
GList *children;
if (g_hash_table_remove (priv->children, widget))
for (children = priv->children; children; children = children->next)
{
gboolean was_visible = gtk_widget_get_visible (widget);
child = children->data;
gtk_widget_unparent (widget);
if (child->widget == widget)
{
gboolean was_visible = gtk_widget_get_visible (widget);
if (was_visible && gtk_widget_get_visible (widget_bowl))
gtk_widget_queue_resize (widget_bowl);
gtk_widget_unparent (widget);
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
priv->children = g_list_remove_link (priv->children, children);
g_list_free (children);
g_free (child);
if (was_visible && gtk_widget_get_visible (widget_bowl))
gtk_widget_queue_resize (widget_bowl);
priv->count--;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_COUNT]);
break;
}
}
}
static void
gtk_fishbowl_finalize (GObject *object)
{
GtkFishbowl *fishbowl = GTK_FISHBOWL (object);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
g_hash_table_destroy (priv->children);
priv->children = NULL;
}
static void
gtk_fishbowl_dispose (GObject *object)
{
@@ -292,6 +289,14 @@ gtk_fishbowl_get_property (GObject *object,
g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl));
break;
case PROP_FRAMERATE_STRING:
{
char *s = g_strdup_printf ("%.2f", gtk_fishbowl_get_framerate (fishbowl));
g_value_set_string (value, s);
g_free (s);
}
break;
case PROP_UPDATE_DELAY:
g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl));
break;
@@ -308,7 +313,6 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gtk_fishbowl_finalize;
object_class->dispose = gtk_fishbowl_dispose;
object_class->set_property = gtk_fishbowl_set_property;
object_class->get_property = gtk_fishbowl_get_property;
@@ -346,6 +350,13 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
0,
G_PARAM_READABLE);
props[PROP_FRAMERATE_STRING] =
g_param_spec_string ("framerate-string",
"Framerate as string",
"Framerate as string, with 2 decimals",
NULL,
G_PARAM_READABLE);
props[PROP_UPDATE_DELAY] =
g_param_spec_int64 ("update-delay",
"Update delay",
@@ -497,6 +508,7 @@ gtk_fishbowl_do_update (GtkFishbowl *fishbowl)
priv->framerate = ((int)(priv->framerate * 100))/100.0;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE_STRING]);
if (!priv->benchmark)
return;
@@ -540,9 +552,8 @@ gtk_fishbowl_tick (GtkWidget *widget,
GtkFishbowl *fishbowl = GTK_FISHBOWL (widget);
GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
GtkFishbowlChild *child;
GList *l;
gint64 frame_time, elapsed;
GHashTableIter iter;
gpointer key, value;
gboolean do_update;
frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
@@ -554,10 +565,9 @@ gtk_fishbowl_tick (GtkWidget *widget,
if (elapsed == frame_time)
return G_SOURCE_CONTINUE;
g_hash_table_iter_init (&iter, priv->children);
while (g_hash_table_iter_next (&iter, &key, &value))
for (l = priv->children; l; l = l->next)
{
child = value;
child = l->data;
child->x += child->dx * ((double) elapsed / G_USEC_PER_SEC);
child->y += child->dy * ((double) elapsed / G_USEC_PER_SEC);

View File

@@ -197,7 +197,7 @@ gtk_gears_class_init (GtkGearsClass *klass)
* @param v the vertex to fill
* @param x the x coordinate
* @param y the y coordinate
* @param z the z coordinate
* @param z the z coortinate
* @param n pointer to the normal table
*
* @return the operation error code

View File

@@ -12,7 +12,7 @@ static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow;
static int selected;
#define N_WIDGET_TYPES 6
#define N_WIDGET_TYPES 4
static int hincrement = 5;
@@ -64,7 +64,6 @@ populate_icons (void)
gtk_grid_attach (GTK_GRID (grid), create_icon (), left, top, 1, 1);
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
@@ -101,7 +100,6 @@ populate_text (gboolean hilight)
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
@@ -126,7 +124,6 @@ populate_image (void)
gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE);
hincrement = 5;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
@@ -134,42 +131,6 @@ populate_image (void)
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), image);
}
extern GtkWidget *create_weather_view (void);
static void
populate_list (void)
{
GtkWidget *list;
list = create_weather_view ();
hincrement = 5;
vincrement = 0;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), list);
}
extern GtkWidget *create_color_grid (void);
static void
populate_grid (void)
{
GtkWidget *list;
list = create_color_grid ();
hincrement = 0;
vincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), list);
}
static void
set_widget_type (int type)
{
@@ -203,16 +164,6 @@ set_widget_type (int type)
populate_image ();
break;
case 4:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list");
populate_list ();
break;
case 5:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid");
populate_grid ();
break;
default:
g_assert_not_reached ();
}

View File

@@ -236,6 +236,7 @@ reshare_clicked (GtkMessageRow *row,
priv->message->n_reshares++;
gtk_message_row_update (row);
}
static void
@@ -254,12 +255,11 @@ gtk_message_row_state_flags_changed (GtkWidget *widget,
{
GtkMessageRowPrivate *priv = GTK_MESSAGE_ROW (widget)->priv;
GtkStateFlags flags;
gboolean visible;
flags = gtk_widget_get_state_flags (widget);
visible = flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED) ? TRUE : FALSE;
gtk_widget_set_visible (priv->extra_buttons_box, visible);
gtk_widget_set_visible (priv->extra_buttons_box,
flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED));
GTK_WIDGET_CLASS (gtk_message_row_parent_class)->state_flags_changed (widget, previous_state_flags);
}

View File

@@ -150,7 +150,7 @@
</object>
</child>
<child>
<object class="GtkButton" id="favorite-button">
<object class="GtkButton" id="favorite-buttton">
<property name="label" translatable="yes">Favorite</property>
<property name="receives-default">1</property>
<property name="has-frame">0</property>

View File

@@ -1,202 +0,0 @@
/* Lists/Application launcher
*
* This demo uses the GtkListView widget as a fancy application launcher.
*
* It is also a very small introduction to listviews.
*/
#include <gtk/gtk.h>
/* This is the function that creates the #GListModel that we need.
* GTK list widgets need a #GListModel to display, as models support change
* notifications.
* Unfortunately various older APIs do not provide list models, so we create
* our own.
*/
static GListModel *
create_application_list (void)
{
GListStore *store;
GList *apps, *l;
/* We use a #GListStore here, which is a simple array-like list implementation
* for manual management.
* List models need to know what type of data they provide, so we need to
* provide the type here. As we want to do a list of applications, #GAppInfo
* is the object we provide.
*/
store = g_list_store_new (G_TYPE_APP_INFO);
apps = g_app_info_get_all ();
for (l = apps; l; l = l->next)
g_list_store_append (store, l->data);
g_list_free_full (apps, g_object_unref);
return G_LIST_MODEL (store);
}
/* This is the function we use for setting up new listitems to display.
* We add just an #GtkImage and a #GtkKabel here to display the application's
* icon and name, as this is just a simple demo.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box;
GtkWidget *image;
GtkWidget *label;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
image = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_box_append (GTK_BOX (box), image);
label = gtk_label_new ("");
gtk_box_append (GTK_BOX (box), label);
gtk_list_item_set_child (list_item, box);
}
/* Here we need to prepare the listitem for displaying its item. We get the
* listitem already set up from the previous function, so we can reuse the
* #GtkImage widget we set up above.
* We get the item - which we know is a #GAppInfo because it comes out of
* the model we set up above, grab its icon and display it.
*/
static void
bind_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
GtkWidget *label;
GAppInfo *app_info;
image = gtk_widget_get_first_child (gtk_list_item_get_child (list_item));
label = gtk_widget_get_next_sibling (image);
app_info = gtk_list_item_get_item (list_item);
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
gtk_label_set_label (GTK_LABEL (label), g_app_info_get_display_name (app_info));
}
/* In more complex code, we would also need functions to unbind and teardown
* the listitem, but this is simple code, so the default implementations are
* enough. If we had connected signals, this step would have been necessary.
*
* The #GtkSignalListItemFactory documentation contains more information about
* this step.
*/
/* This function is called whenever an item in the list is activated. This is
* the simple way to allow reacting to the Enter key or double-clicking on a
* listitem.
* Of course, it is possible to use far more complex interactions by turning
* off activation and adding buttons or other widgets in the setup function
* above, but this is a simple demo, so we'll use the simple way.
*/
static void
activate_cb (GtkListView *list,
guint position,
gpointer unused)
{
GAppInfo *app_info;
GdkAppLaunchContext *context;
GError *error = NULL;
app_info = g_list_model_get_item (gtk_list_view_get_model (list), position);
/* Prepare the context for launching the application and launch it. This
* code is explained in detail in the documentation for #GdkAppLaunchContext
* and #GAppInfo.
*/
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (list)));
if (!g_app_info_launch (app_info,
NULL,
G_APP_LAUNCH_CONTEXT (context),
&error))
{
GtkWidget *dialog;
/* And because error handling is important, even a simple demo has it:
* We display an error dialog that something went wrong.
*/
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (list))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Could not launch %s", g_app_info_get_display_name (app_info));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
g_clear_error (&error);
gtk_widget_show (dialog);
}
g_object_unref (context);
g_object_unref (app_info);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_applauncher (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *list, *sw;
GListModel *model;
GtkListItemFactory *factory;
/* Create a window and set a few defaults */
window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (window), 640, 320);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
/* The #GtkListitemFactory is what is used to create #GtkListItems
* to display the data from the model. So it is absolutely necessary
* to create one.
* We will use a #GtkSignalListItemFactory because it is the simplest
* one to use. Different ones are available for different use cases.
* The most powerful one is #GtkBuilderListItemFactory which uses
* #GtkBuilder .ui files, so it requires little code.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
/* Create the list widget here.
*/
list = gtk_list_view_new_with_factory (factory);
/* We connect the activate signal here. It's the function we defined
* above for launching the selected application.
*/
g_signal_connect (list, "activate", G_CALLBACK (activate_cb), NULL);
/* And of course we need to set the data model. Here we call the function
* we wrote above that gives us the list of applications. Then we set
* it on the list widget.
* The list will now take items from the model and use the factory
* to create as many listitems as it needs to show itself to the user.
*/
model = create_application_list ();
gtk_list_view_set_model (GTK_LIST_VIEW (list), model);
g_object_unref (model);
/* List widgets should always be contained in a #GtkScrolledWindow,
* because otherwise they might get too large or they might not
* be scrollable.
*/
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,506 +0,0 @@
/* Lists/Clocks
*
* This demo displays the time in different timezones.
*
* The goal is to show how to set up expressions that track changes
* in objects and make them update widgets. For that, we create a
* GtkClock object that updates its time every second and then use
* various ways to display that time.
*
* Typically, this will be done using GtkBuilder .ui files with the
* help of the <binding> tag, but this demo shows the code that runs
* behind that.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_CLOCK (gtk_clock_get_type ())
G_DECLARE_FINAL_TYPE (GtkClock, gtk_clock, GTK, CLOCK, GObject)
/* This is our object. It's just a timezone */
typedef struct _GtkClock GtkClock;
struct _GtkClock
{
GObject parent_instance;
/* We allow this to be NULL for the local timezone */
GTimeZone *timezone;
/* Name of the location we're displaying time for */
char *location;
};
enum {
PROP_0,
PROP_LOCATION,
PROP_TIME,
PROP_TIMEZONE,
N_PROPS
};
/* This function returns the current time in the clock's timezone.
* Note that this returns a new object every time, so we need to
* remember to unref it after use.
*/
static GDateTime *
gtk_clock_get_time (GtkClock *clock)
{
if (clock->timezone)
return g_date_time_new_now (clock->timezone);
else
return g_date_time_new_now_local ();
}
/* Here, we implement the functionality required by the GdkPaintable
* interface. This way we have a trivial way to display an analog clock.
* It also allows demonstrating how to directly use objects in the
* listview later by making this object do something interesting.
*/
static void
gtk_clock_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkClock *self = GTK_CLOCK (paintable);
GDateTime *time;
GskRoundedRect outline;
#define BLACK ((GdkRGBA) { 0, 0, 0, 1 })
/* save/restore() is necessary so we can undo the transforms we start
* out with.
*/
gtk_snapshot_save (snapshot);
/* First, we move the (0, 0) point to the center of the area so
* we can draw everything relative to it.
*/
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2, height / 2));
/* Next we scale it, so that we can pretend that the clock is
* 100px in size. That way, we don't need to do any complicated
* math later. We use MIN() here so that we use the smaller
* dimension for sizing. That way we don't overdraw but keep
* the aspect ratio.
*/
gtk_snapshot_scale (snapshot, MIN (width, height) / 100.0, MIN (width, height) / 100.0);
/* Now we have a circle with diameter 100px (and radius 50px) that
* has its (0, 0) point at the center. Let's draw a simple clock into it.
*/
time = gtk_clock_get_time (self);
/* First, draw a circle. This is a neat little trick to draw a circle
* without requiring Cairo.
*/
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-50, -50, 100, 100), 50);
gtk_snapshot_append_border (snapshot,
&outline,
(float[4]) { 4, 4, 4, 4 },
(GdkRGBA [4]) { BLACK, BLACK, BLACK, BLACK });
/* Next, draw the hour hand.
* We do this using tranforms again: Instead of computing where the angle
* points to, we just rotate everything and then draw the hand as if it
* was :00. We don't even need to care about am/pm here because rotations
* just work.
*/
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 30 * g_date_time_get_hour (time) + 0.5 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -23, 4, 25), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And the same as above for the minute hand. Just make this one longer
* so people can tell the hands apart.
*/
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 45), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* and finally, the second indicator. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_second (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 10), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And finally, don't forget to restore the initial save() that
* we did for the initial transformations.
*/
gtk_snapshot_restore (snapshot);
g_date_time_unref (time);
}
/* Our desired size is 100px. That sounds okay for an analog clock */
static int
gtk_clock_get_intrinsic_width (GdkPaintable *paintable)
{
return 100;
}
static int
gtk_clock_get_intrinsic_height (GdkPaintable *paintable)
{
return 100;
}
/* Initialize the paintable interface. This way we turn our clocks
* into objects that can be drawn. There are more functions to this
* interface to define desired size, but this is enough.
*/
static void
gtk_clock_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_clock_snapshot;
iface->get_intrinsic_width = gtk_clock_get_intrinsic_width;
iface->get_intrinsic_height = gtk_clock_get_intrinsic_height;
}
/* Finally, we define the type. The important part is adding the
* paintable interface, so GTK knows that this object can indeed
* be drawn.
*/
G_DEFINE_TYPE_WITH_CODE (GtkClock, gtk_clock, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_clock_paintable_init))
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_clock_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
g_value_set_string (value, self->location);
break;
case PROP_TIME:
g_value_take_boxed (value, gtk_clock_get_time (self));
break;
case PROP_TIMEZONE:
g_value_set_boxed (value, self->timezone);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_clock_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
self->location = g_value_dup_string (value);
break;
case PROP_TIMEZONE:
self->timezone = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* This is the list of all the ticking clocks */
static GSList *ticking_clocks = NULL;
/* This is the ID of the timeout source that is updating all
* ticking clocks.
*/
static guint ticking_clock_id = 0;
/* Every second, this function is called to tell everybody that
* the clocks are ticking.
*/
static gboolean
gtk_clock_tick (gpointer unused)
{
GSList *l;
for (l = ticking_clocks; l; l = l->next)
{
GtkClock *clock = l->data;
/* We will now return a different value for the time porperty,
* so notify about that.
*/
g_object_notify_by_pspec (G_OBJECT (clock), properties[PROP_TIME]);
/* We will also draw the hands of the clock differently.
* So notify about that, too.
*/
gdk_paintable_invalidate_contents (GDK_PAINTABLE (clock));
}
return G_SOURCE_CONTINUE;
}
static void
gtk_clock_stop_ticking (GtkClock *self)
{
ticking_clocks = g_slist_remove (ticking_clocks, self);
/* If no clock is remaining, stop running the tick updates */
if (ticking_clocks == NULL && ticking_clock_id != 0)
g_clear_handle_id (&ticking_clock_id, g_source_remove);
}
static void
gtk_clock_start_ticking (GtkClock *self)
{
/* if no clock is ticking yet, start */
if (ticking_clock_id == 0)
ticking_clock_id = g_timeout_add_seconds (1, gtk_clock_tick, NULL);
ticking_clocks = g_slist_prepend (ticking_clocks, self);
}
static void
gtk_clock_finalize (GObject *object)
{
GtkClock *self = GTK_CLOCK (object);
gtk_clock_stop_ticking (self);
g_free (self->location);
g_clear_pointer (&self->timezone, g_time_zone_unref);
G_OBJECT_CLASS (gtk_clock_parent_class)->finalize (object);
}
static void
gtk_clock_class_init (GtkClockClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_clock_get_property;
gobject_class->set_property = gtk_clock_set_property;
gobject_class->finalize = gtk_clock_finalize;
properties[PROP_LOCATION] =
g_param_spec_string ("location", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_TIME] =
g_param_spec_boxed ("time", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READABLE);
properties[PROP_TIMEZONE] =
g_param_spec_boxed ("timezone", NULL, NULL, G_TYPE_TIME_ZONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_clock_init (GtkClock *self)
{
gtk_clock_start_ticking (self);
}
static GtkClock *
gtk_clock_new (const char *location,
GTimeZone *_timezone)
{
GtkClock *result;
result = g_object_new (GTK_TYPE_CLOCK,
"location", location,
"timezone", _timezone,
NULL);
g_clear_pointer (&_timezone, g_time_zone_unref);
return result;
}
static GListModel *
create_clocks_model (void)
{
GListStore *result;
GtkClock *clock;
result = g_list_store_new (GTK_TYPE_CLOCK);
/* local time */
clock = gtk_clock_new ("local", NULL);
g_list_store_append (result, clock);
g_object_unref (clock);
/* UTC time */
clock = gtk_clock_new ("UTC", g_time_zone_new_utc ());
g_list_store_append (result, clock);
g_object_unref (clock);
/* A bunch of timezones with GTK hackers */
clock = gtk_clock_new ("San Francisco", g_time_zone_new ("America/Los_Angeles"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Xalapa", g_time_zone_new ("America/Mexico_City"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Boston", g_time_zone_new ("America/New_York"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("London", g_time_zone_new ("Europe/London"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Berlin", g_time_zone_new ("Europe/Berlin"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Moscow", g_time_zone_new ("Europe/Moscow"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("New Delhi", g_time_zone_new ("Asia/Kolkata"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Shanghai", g_time_zone_new ("Asia/Shanghai"));
g_list_store_append (result, clock);
g_object_unref (clock);
return G_LIST_MODEL (result);
}
static char *
convert_time_to_string (GObject *image,
GDateTime *time,
gpointer unused)
{
return g_date_time_format (time, "%x\n%X");
}
/* And this function is the crux for this whole demo.
* It shows how to use expressions to set up bindings.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *location_label, *time_label;
GtkExpression *clock_expression, *expression;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
/* First, we create an expression that gets us the clock from the listitem:
* 1. Create an expression that gets the list item.
* 2. Use that expression's "item" property to get the clock
*/
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
clock_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
/* Bind the clock's location to a label.
* This is easy: We just get the "location" property of the clock.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"location");
/* Now create the label and bind the expression to it. */
location_label = gtk_label_new (NULL);
gtk_expression_bind (expression, location_label, "label", location_label);
gtk_box_append (GTK_BOX (box), location_label);
/* Here we bind the item itself to a GdkPicture.
* This is simply done by using the clock expression itself.
*/
expression = gtk_expression_ref (clock_expression);
/* Now create the widget and bind the expression to it. */
picture = gtk_picture_new ();
gtk_expression_bind (expression, picture, "paintable", picture);
gtk_box_append (GTK_BOX (box), picture);
/* And finally, everything comes together.
* We create a label for displaying the time as text.
* For that, we need to transform the "GDateTime" of the
* time property into a string so that the label can display it.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"time");
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, (GtkExpression *[1]) { expression },
G_CALLBACK (convert_time_to_string),
NULL, NULL);
/* Now create the label and bind the expression to it. */
time_label = gtk_label_new (NULL);
gtk_expression_bind (expression, time_label, "label", time_label);
gtk_box_append (GTK_BOX (box), time_label);
gtk_expression_unref (clock_expression);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_clocks (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *gridview, *sw;
GtkListItemFactory *factory;
GListModel *model;
GtkNoSelection *selection;
/* This is the normal window setup code every demo does */
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Clocks");
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
/* List widgets go into a scrolled window. Always. */
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
/* Create the factory that creates the listitems. Because we
* used bindings above during setup, we only need to connect
* to the setup signal.
* The bindings take care of the bind step.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
gridview = gtk_grid_view_new_with_factory (factory);
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
model = create_clocks_model ();
selection = gtk_no_selection_new (model);
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), G_LIST_MODEL (selection));
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
g_object_unref (selection);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,607 +0,0 @@
/* Lists/Colors
*
* This demo displays a list of named colors.
*
* It is using a GtkGridView, and shows how to display
* and sort the data in various ways. The controls for
* this are implemented using GtkDropDown.
*
* The dataset used here has 9283 items.
*/
#include <gtk/gtk.h>
#include <stdlib.h>
#define GTK_TYPE_COLOR (gtk_color_get_type ())
G_DECLARE_FINAL_TYPE (GtkColor, gtk_color, GTK, COLOR, GObject)
/* This is our object. It's just a color */
typedef struct _GtkColor GtkColor;
struct _GtkColor
{
GObject parent_instance;
char *name;
GdkRGBA *color;
int h, s, v;
gboolean selected;
};
enum {
PROP_0,
PROP_NAME,
PROP_COLOR,
PROP_RED,
PROP_GREEN,
PROP_BLUE,
PROP_HUE,
PROP_SATURATION,
PROP_VALUE,
PROP_SELECTED,
N_PROPS
};
static void
gtk_color_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkColor *self = GTK_COLOR (paintable);
gtk_snapshot_append_color (snapshot, self->color, &GRAPHENE_RECT_INIT (0, 0, width, height));
}
static int
gtk_color_get_intrinsic_width (GdkPaintable *paintable)
{
return 32;
}
static int
gtk_color_get_intrinsic_height (GdkPaintable *paintable)
{
return 32;
}
static void
gtk_color_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_color_snapshot;
iface->get_intrinsic_width = gtk_color_get_intrinsic_width;
iface->get_intrinsic_height = gtk_color_get_intrinsic_height;
}
/*
* Finally, we define the type. The important part is adding the paintable
* interface, so GTK knows that this object can indeed be drawm.
*/
G_DEFINE_TYPE_WITH_CODE (GtkColor, gtk_color, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_color_paintable_init))
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_color_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkColor *self = GTK_COLOR (object);
switch (property_id)
{
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_COLOR:
g_value_set_boxed (value, self->color);
break;
case PROP_RED:
g_value_set_float (value, self->color->red);
break;
case PROP_GREEN:
g_value_set_float (value, self->color->green);
break;
case PROP_BLUE:
g_value_set_float (value, self->color->blue);
break;
case PROP_HUE:
g_value_set_int (value, self->h);
break;
case PROP_SATURATION:
g_value_set_int (value, self->s);
break;
case PROP_VALUE:
g_value_set_int (value, self->v);
break;
case PROP_SELECTED:
g_value_set_boolean (value, self->selected);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_color_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkColor *self = GTK_COLOR (object);
switch (property_id)
{
case PROP_NAME:
self->name = g_value_dup_string (value);
break;
case PROP_COLOR:
self->color = g_value_dup_boxed (value);
break;
case PROP_HUE:
self->h = g_value_get_int (value);
break;
case PROP_SATURATION:
self->s = g_value_get_int (value);
break;
case PROP_VALUE:
self->v = g_value_get_int (value);
break;
case PROP_SELECTED:
self->selected = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_color_finalize (GObject *object)
{
GtkColor *self = GTK_COLOR (object);
g_free (self->name);
g_clear_pointer (&self->color, gdk_rgba_free);
G_OBJECT_CLASS (gtk_color_parent_class)->finalize (object);
}
static void
gtk_color_class_init (GtkColorClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_color_get_property;
gobject_class->set_property = gtk_color_set_property;
gobject_class->finalize = gtk_color_finalize;
properties[PROP_NAME] =
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_COLOR] =
g_param_spec_boxed ("color", NULL, NULL, GDK_TYPE_RGBA, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_RED] =
g_param_spec_float ("red", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_GREEN] =
g_param_spec_float ("green", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_BLUE] =
g_param_spec_float ("blue", NULL, NULL, 0, 1, 0, G_PARAM_READABLE);
properties[PROP_HUE] =
g_param_spec_int ("hue", NULL, NULL, 0, 360, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_SATURATION] =
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_VALUE] =
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_SELECTED] =
g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_color_init (GtkColor *self)
{
}
static GtkColor *
gtk_color_new (const char *name,
float r, float g, float b,
int h, int s, int v)
{
GtkColor *result;
GdkRGBA color = { r, g, b, 1.0 };
result = g_object_new (GTK_TYPE_COLOR,
"name", name,
"color", &color,
"hue", h,
"saturation", s,
"value", v,
NULL);
return result;
}
static GListModel *
create_colors_model (void)
{
GListStore *result;
GtkColor *color;
GBytes *data;
char **lines;
guint i;
result = g_list_store_new (GTK_TYPE_COLOR);
data = g_resources_lookup_data ("/listview_colors/color.names.txt", 0, NULL);
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
for (i = 0; lines[i]; i++)
{
const char *name;
char **fields;
int red, green, blue;
int h, s, v;
if (lines[i][0] == '#' || lines[i][0] == '\0')
continue;
fields = g_strsplit (lines[i], " ", 0);
name = fields[1];
red = atoi (fields[3]);
green = atoi (fields[4]);
blue = atoi (fields[5]);
h = atoi (fields[9]);
s = atoi (fields[10]);
v = atoi (fields[11]);
color = gtk_color_new (name, red / 255., green / 255., blue / 255., h, s, v);
g_list_store_append (result, color);
g_object_unref (color);
g_strfreev (fields);
}
g_strfreev (lines);
g_bytes_unref (data);
return G_LIST_MODEL (result);
}
static char *
get_rgb_markup (gpointer this,
GtkColor *color)
{
if (!color)
return NULL;
return g_strdup_printf ("<b>R:</b> %d <b>G:</b> %d <b>B:</b> %d",
(int)(color->color->red * 255),
(int)(color->color->green * 255),
(int)(color->color->blue * 255));
}
static char *
get_hsv_markup (gpointer this,
GtkColor *color)
{
if (!color)
return NULL;
return g_strdup_printf ("<b>H:</b> %d <b>S:</b> %d <b>V:</b> %d",
color->h,
color->s,
color->v);
}
static void
setup_simple_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, 32, 32);
gtk_expression_bind (color_expression, picture, "paintable", NULL);
gtk_list_item_set_child (list_item, picture);
}
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *name_label, *rgb_label, *hsv_label;
GtkExpression *color_expression, *expression;
GtkExpression *params[1];
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
expression = gtk_property_expression_new (GTK_TYPE_COLOR,
gtk_expression_ref (color_expression),
"name");
name_label = gtk_label_new (NULL);
gtk_expression_bind (expression, name_label, "label", NULL);
gtk_box_append (GTK_BOX (box), name_label);
expression = gtk_expression_ref (color_expression);
picture = gtk_picture_new ();
gtk_expression_bind (expression, picture, "paintable", NULL);
gtk_box_append (GTK_BOX (box), picture);
params[0] = gtk_expression_ref (color_expression);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, params,
(GCallback)get_rgb_markup,
NULL, NULL);
rgb_label = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (rgb_label), TRUE);
gtk_expression_bind (expression, rgb_label, "label", NULL);
gtk_box_append (GTK_BOX (box), rgb_label);
params[0] = gtk_expression_ref (color_expression);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, params,
(GCallback)get_hsv_markup,
NULL, NULL);
hsv_label = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (hsv_label), TRUE);
gtk_expression_bind (expression, hsv_label, "label", NULL);
gtk_box_append (GTK_BOX (box), hsv_label);
gtk_expression_unref (color_expression);
}
static void
set_title (gpointer item,
const char *title)
{
g_object_set_data (G_OBJECT (item), "title", (gpointer)title);
}
static char *
get_title (gpointer item)
{
return g_strdup ((char *)g_object_get_data (G_OBJECT (item), "title"));
}
static gboolean
set_item (GBinding *binding,
const GValue *from,
GValue *to,
gpointer data)
{
GObject *source = g_binding_get_source (binding);
GListModel *model;
guint selected;
gpointer item;
selected = g_value_get_uint (from);
model = gtk_drop_down_get_model (GTK_DROP_DOWN (source));
item = g_list_model_get_item (model, selected);
g_value_set_object (to, item);
g_clear_object (&item);
return TRUE;
}
GtkWidget *
create_color_grid (void)
{
GtkWidget *gridview;
GtkListItemFactory *factory;
GListModel *model, *selection;
gridview = gtk_grid_view_new ();
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
gtk_grid_view_set_factory (GTK_GRID_VIEW (gridview), factory);
g_object_unref (factory);
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
model = G_LIST_MODEL (gtk_sort_list_model_new (create_colors_model (), NULL));
selection = G_LIST_MODEL (gtk_property_selection_new (model, "selected"));
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
g_object_unref (selection);
g_object_unref (model);
return gridview;
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_colors (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *header, *gridview, *sw, *box, *dropdown;
GtkListItemFactory *factory;
GListStore *factories;
GListModel *model;
GtkSorter *sorter;
GtkSorter *multi_sorter;
GListStore *sorters;
GtkExpression *expression;
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);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
gridview = create_color_grid ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
g_object_get (model, "model", &model, NULL);
sorters = g_list_store_new (GTK_TYPE_SORTER);
sorter = gtk_string_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "name"));
set_title (sorter, "Name");
g_list_store_append (sorters, sorter);
g_object_unref (sorter);
multi_sorter = gtk_multi_sorter_new ();
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "red"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Red");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "green"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Green");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "blue"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Blue");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
set_title (multi_sorter, "RGB");
g_list_store_append (sorters, multi_sorter);
g_object_unref (multi_sorter);
multi_sorter = gtk_multi_sorter_new ();
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "hue"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Hue");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "saturation"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Saturation");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "value"));
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
set_title (sorter, "Value");
g_list_store_append (sorters, sorter);
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
set_title (multi_sorter, "HSV");
g_list_store_append (sorters, multi_sorter);
g_object_unref (multi_sorter);
dropdown = gtk_drop_down_new ();
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_append (GTK_BOX (box), gtk_label_new ("Sort by:"));
gtk_box_append (GTK_BOX (box), dropdown);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), box);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression);
gtk_expression_unref (expression);
gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (sorters));
g_object_unref (sorters);
g_object_bind_property_full (dropdown, "selected",
model, "sorter",
G_BINDING_SYNC_CREATE,
set_item, NULL,
NULL, NULL);
factories = g_list_store_new (GTK_TYPE_LIST_ITEM_FACTORY);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
set_title (factory, "Colors");
g_list_store_append (factories, factory);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
set_title (factory, "Everything");
g_list_store_append (factories, factory);
dropdown = gtk_drop_down_new ();
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_append (GTK_BOX (box), gtk_label_new ("Show:"));
gtk_box_append (GTK_BOX (box), dropdown);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), box);
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
0, NULL,
(GCallback)get_title,
NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (dropdown), expression);
gtk_expression_unref (expression);
gtk_drop_down_set_model (GTK_DROP_DOWN (dropdown), G_LIST_MODEL (factories));
g_object_unref (factories);
g_object_bind_property_full (dropdown, "selected",
gridview, "factory",
G_BINDING_SYNC_CREATE,
set_item, NULL,
NULL, NULL);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,281 +0,0 @@
/* Lists/File browser
*
* This demo shows off the different layouts that are quickly achievable
* with GtkListview and GtkGridView by implementing a file browser with
* different views.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
/* Create a simple object that holds the data for the different views */
typedef struct _FileBrowserView FileBrowserView;
struct _FileBrowserView
{
GObject parent_instance;
GtkListItemFactory *factory;
char *icon_name;
char *title;
GtkOrientation orientation;
};
enum {
PROP_0,
PROP_FACTORY,
PROP_ICON_NAME,
PROP_TITLE,
PROP_ORIENTATION,
N_PROPS
};
#define FILE_BROWSER_TYPE_VIEW (file_browser_view_get_type ())
G_DECLARE_FINAL_TYPE (FileBrowserView, file_browser_view, FILE_BROWSER, VIEW, GObject);
G_DEFINE_TYPE (FileBrowserView, file_browser_view, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
file_browser_view_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (property_id)
{
case PROP_FACTORY:
g_value_set_object (value, self->factory);
break;
case PROP_ICON_NAME:
g_value_set_string (value, self->icon_name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, self->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
file_browser_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (prop_id)
{
case PROP_FACTORY:
g_set_object (&self->factory, g_value_get_object (value));
break;
case PROP_ICON_NAME:
g_free (self->icon_name);
self->icon_name = g_value_dup_string (value);
break;
case PROP_TITLE:
g_free (self->title);
self->title = g_value_dup_string (value);
break;
case PROP_ORIENTATION:
self->orientation = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
file_browser_view_finalize (GObject *object)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
g_object_unref (self->factory);
g_free (self->icon_name);
g_free (self->title);
G_OBJECT_CLASS (file_browser_view_parent_class)->dispose (object);
}
static void
file_browser_view_class_init (FileBrowserViewClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = file_browser_view_get_property;
gobject_class->set_property = file_browser_view_set_property;
gobject_class->finalize = file_browser_view_finalize;
properties[PROP_FACTORY] =
g_param_spec_object ("factory",
"factory",
"factory to use in the main view",
GTK_TYPE_LIST_ITEM_FACTORY,
G_PARAM_READWRITE);
properties[PROP_ICON_NAME] =
g_param_spec_string ("icon-name",
"icon name",
"icon to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"title",
"title to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_ORIENTATION] =
g_param_spec_enum ("orientation",
"orientation",
"orientation of the view",
GTK_TYPE_ORIENTATION,
GTK_ORIENTATION_VERTICAL,
G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void file_browser_view_init (FileBrowserView *self)
{
}
char *
filebrowser_get_display_name (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::display-name"));
}
char *
filebrowser_get_content_type (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::content-type"));
}
char *
filebrowser_get_size (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_format_size (g_file_info_get_attribute_uint64 (info, "standard::size"));
}
GIcon *
filebrowser_get_icon (GObject *object,
GFileInfo *info)
{
GIcon *icon;
if (info)
icon = G_ICON (g_file_info_get_attribute_object (info, "standard::icon"));
else
icon = NULL;
if (icon)
g_object_ref (icon);
return icon;
}
void
filebrowser_up_clicked_cb (GtkButton *button,
GtkDirectoryList *list)
{
GFile *file;
file = g_file_get_parent (gtk_directory_list_get_file (list));
if (file == NULL)
return;
gtk_directory_list_set_file (list, file);
}
void
filebrowser_view_activated_cb (GtkGridView *view,
guint pos,
GtkDirectoryList *list)
{
GFileInfo *info;
info = g_list_model_get_item (gtk_grid_view_get_model (view), pos);
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
gtk_directory_list_set_file (list, G_FILE (g_file_info_get_attribute_object (info, "standard::file")));
g_object_unref (info);
}
GtkWidget *
do_listview_filebrowser (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *view;
GtkBuilder *builder;
GtkDirectoryList *dirlist;
GFile *file;
char *cwd;
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/listview_filebrowser/listview_filebrowser.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/listview_filebrowser/listview_filebrowser.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
/* Create the model and fill it with the contents of the current directory */
cwd = g_get_current_dir ();
file = g_file_new_for_path (cwd);
g_free (cwd);
dirlist = GTK_DIRECTORY_LIST (gtk_builder_get_object (builder, "dirlist"));
gtk_directory_list_set_file (dirlist, file);
g_object_unref (file);
/* grab focus in the view */
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
gtk_widget_grab_focus (view);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,11 +0,0 @@
list.viewswitcher {
border: 1px solid gray;
}
list.viewswitcher > row {
padding: 5px;
}
list.viewswitcher row:selected {
background: gray;
}

View File

@@ -1,249 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="viewlist">
<property name="item-type">FileBrowserView</property>
<child>
<object class="FileBrowserView">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="icon-name">view-list-symbolic</property>
<property name="title" translatable="yes">List</property>
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-grid-symbolic</property>
<property name="title" translatable="yes">Grid</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="lines">2</property>
<property name="ellipsize">end</property>
<property name="width-chars">10</property>
<property name="max-width-chars">30</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">vertical</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-paged-symbolic</property>
<property name="title" translatable="yes">Paged</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_size">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_content_type">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">horizontal</property>
</object>
</child>
</object>
<object class="GtkDirectoryList" id="dirlist">
<property name="attributes">standard::name,standard::display-name,standard::icon,standard::size,standard::content-type</property>
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">File browser</property>
<property name="default-width">600</property>
<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>
<signal name="clicked" handler="filebrowser_up_clicked_cb" object="dirlist" swapped="no"/>
</object>
</child>
<child type="end">
<object class="GtkListView">
<property name="valign">center</property>
<property name="orientation">horizontal</property>
<style>
<class name="linked"/>
<class name="viewswitcher"/>
</style>
<property name="model">
<object class="GtkSingleSelection" id="selected-view">
<property name="model">viewlist</property>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkImage">
<binding name="icon-name">
<lookup type="FileBrowserView" name="icon-name">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
<binding name="tooltip-text">
<lookup type="FileBrowserView" name="title">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="can-focus">1</property>
<child>
<object class="GtkGridView" id="view">
<property name="model">dirlist</property>
<property name="max-columns">15</property>
<binding name="factory">
<lookup name="factory" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<binding name="orientation">
<lookup name="orientation" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<signal name="activate" handler="filebrowser_view_activated_cb" object="dirlist" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,472 +0,0 @@
/* Lists/Minesweeper
*
* This demo shows how to develop a user interface for small game using a
* gridview.
*
* It demonstrates how to use the activate signal and single-press behavior
* to implement rather different interaction behavior to a typical list.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/*** The cell object ***/
/* Create an object that holds the data for a cell in the game */
typedef struct _SweeperCell SweeperCell;
struct _SweeperCell
{
GObject parent_instance;
gboolean is_mine;
gboolean is_visible;
guint neighbor_mines;
};
enum {
CELL_PROP_0,
CELL_PROP_LABEL,
N_CELL_PROPS
};
#define SWEEPER_TYPE_CELL (sweeper_cell_get_type ())
G_DECLARE_FINAL_TYPE (SweeperCell, sweeper_cell, SWEEPER, CELL, GObject);
G_DEFINE_TYPE (SweeperCell, sweeper_cell, G_TYPE_OBJECT);
static GParamSpec *cell_properties[N_CELL_PROPS] = { NULL, };
static const char *
sweeper_cell_get_label (SweeperCell *self)
{
static const char *minecount_labels[10] = { "", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if (!self->is_visible)
return "?";
if (self->is_mine)
return "💣";
return minecount_labels[self->neighbor_mines];
}
static void
sweeper_cell_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperCell *self = SWEEPER_CELL (object);
switch (property_id)
{
case CELL_PROP_LABEL:
g_value_set_string (value, sweeper_cell_get_label (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_cell_class_init (SweeperCellClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = sweeper_cell_get_property;
cell_properties[CELL_PROP_LABEL] =
g_param_spec_string ("label",
"label",
"label to display for this row",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_CELL_PROPS, cell_properties);
}
static void
sweeper_cell_init (SweeperCell *self)
{
}
static void
sweeper_cell_reveal (SweeperCell *self)
{
if (self->is_visible)
return;
self->is_visible = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), cell_properties[CELL_PROP_LABEL]);
}
static SweeperCell *
sweeper_cell_new (void)
{
return g_object_new (SWEEPER_TYPE_CELL, NULL);
}
/*** The board object ***/
/* Create an object that holds the data for the game */
typedef struct _SweeperGame SweeperGame;
struct _SweeperGame
{
GObject parent_instance;
GPtrArray *cells;
guint width;
guint height;
gboolean playing;
gboolean win;
};
enum {
GAME_PROP_0,
GAME_PROP_HEIGHT,
GAME_PROP_PLAYING,
GAME_PROP_WIDTH,
GAME_PROP_WIN,
N_GAME_PROPS
};
#define SWEEPER_TYPE_GAME (sweeper_game_get_type ())
G_DECLARE_FINAL_TYPE (SweeperGame, sweeper_game, SWEEPER, GAME, GObject);
static GType
sweeper_game_list_model_get_item_type (GListModel *model)
{
return SWEEPER_TYPE_GAME;
}
static guint
sweeper_game_list_model_get_n_items (GListModel *model)
{
SweeperGame *self = SWEEPER_GAME (model);
return self->width * self->height;
}
static gpointer
sweeper_game_list_model_get_item (GListModel *model,
guint position)
{
SweeperGame *self = SWEEPER_GAME (model);
return g_object_ref (g_ptr_array_index (self->cells, position));
}
static void
sweeper_game_list_model_init (GListModelInterface *iface)
{
iface->get_item_type = sweeper_game_list_model_get_item_type;
iface->get_n_items = sweeper_game_list_model_get_n_items;
iface->get_item = sweeper_game_list_model_get_item;
}
G_DEFINE_TYPE_WITH_CODE (SweeperGame, sweeper_game, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, sweeper_game_list_model_init))
static GParamSpec *game_properties[N_GAME_PROPS] = { NULL, };
static void
sweeper_game_dispose (GObject *object)
{
SweeperGame *self = SWEEPER_GAME (object);
g_clear_pointer (&self->cells, g_ptr_array_unref);
G_OBJECT_CLASS (sweeper_game_parent_class)->dispose (object);
}
static void
sweeper_game_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperGame *self = SWEEPER_GAME (object);
switch (property_id)
{
case GAME_PROP_HEIGHT:
g_value_set_uint (value, self->height);
break;
case GAME_PROP_PLAYING:
g_value_set_boolean (value, self->playing);
break;
case GAME_PROP_WIDTH:
g_value_set_uint (value, self->width);
break;
case GAME_PROP_WIN:
g_value_set_boolean (value, self->win);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_game_class_init (SweeperGameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = sweeper_game_dispose;
gobject_class->get_property = sweeper_game_get_property;
game_properties[GAME_PROP_HEIGHT] =
g_param_spec_uint ("height",
"height",
"height of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_PLAYING] =
g_param_spec_boolean ("playing",
"playing",
"if the game is still going on",
FALSE,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIDTH] =
g_param_spec_uint ("width",
"width",
"width of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIN] =
g_param_spec_boolean ("win",
"win",
"if the game was won",
FALSE,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_GAME_PROPS, game_properties);
}
static void
sweeper_game_reset_board (SweeperGame *self,
guint width,
guint height)
{
guint i;
g_ptr_array_set_size (self->cells, 0);
for (i = 0; i < width * height; i++)
{
g_ptr_array_add (self->cells, sweeper_cell_new ());
}
if (self->width != width)
{
self->width = width;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIDTH]);
}
if (self->height != height)
{
self->height = height;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_HEIGHT]);
}
if (!self->playing)
{
self->playing = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win)
{
self->win = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_place_mines (SweeperGame *self,
guint n_mines)
{
guint i;
for (i = 0; i < n_mines; i++)
{
SweeperCell *cell;
do {
cell = g_ptr_array_index (self->cells, g_random_int_range (0, self->cells->len));
} while (cell->is_mine);
cell->is_mine = TRUE;
}
}
static SweeperCell *
get_cell (SweeperGame *self,
guint x,
guint y)
{
return g_ptr_array_index (self->cells, y * self->width + x);
}
static void
sweeper_game_count_neighbor_mines (SweeperGame *self,
guint width,
guint height)
{
guint x, y, x2, y2;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
SweeperCell *cell = get_cell (self, x, y);
for (y2 = MAX (1, y) - 1; y2 < MIN (height, y + 2); y2++)
{
for (x2 = MAX (1, x) - 1; x2 < MIN (width, x + 2); x2++)
{
SweeperCell *other = get_cell (self, x2, y2);
if (other->is_mine)
cell->neighbor_mines++;
}
}
}
}
}
static void
sweeper_game_new_game (SweeperGame *self,
guint width,
guint height,
guint n_mines)
{
guint n_items_before;
g_return_if_fail (n_mines <= width * height);
n_items_before = self->width * self->height;
g_object_freeze_notify (G_OBJECT (self));
sweeper_game_reset_board (self, width, height);
sweeper_game_place_mines (self, n_mines);
sweeper_game_count_neighbor_mines (self, width, height);
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, width * height);
g_object_thaw_notify (G_OBJECT (self));
}
static void
sweeper_game_init (SweeperGame *self)
{
self->cells = g_ptr_array_new_with_free_func (g_object_unref);
sweeper_game_new_game (self, 8, 8, 10);
}
static void
sweeper_game_end (SweeperGame *self,
gboolean win)
{
if (self->playing)
{
self->playing = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win != win)
{
self->win = win;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_check_finished (SweeperGame *self)
{
guint i;
if (!self->playing)
return;
for (i = 0; i < self->cells->len; i++)
{
SweeperCell *cell = g_ptr_array_index (self->cells, i);
/* There's still a non-revealed cell that isn't a mine */
if (!cell->is_visible && !cell->is_mine)
return;
}
sweeper_game_end (self, TRUE);
}
static void
sweeper_game_reveal_cell (SweeperGame *self,
guint position)
{
SweeperCell *cell;
if (!self->playing)
return;
cell = g_ptr_array_index (self->cells, position);
sweeper_cell_reveal (cell);
if (cell->is_mine)
sweeper_game_end (self, FALSE);
sweeper_game_check_finished (self);
}
void
minesweeper_cell_clicked_cb (GtkGridView *gridview,
guint pos,
SweeperGame *game)
{
sweeper_game_reveal_cell (game, pos);
}
void
minesweeper_new_game_cb (GtkButton *button,
SweeperGame *game)
{
sweeper_game_new_game (game, 8, 8, 10);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_minesweeper (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkBuilder *builder;
g_type_ensure (SWEEPER_TYPE_GAME);
builder = gtk_builder_new_from_resource ("/listview_minesweeper/listview_minesweeper.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="SweeperGame" id="game">
</object>
<object class="GtkWindow" id="window">
<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>
<signal name="clicked" handler="minesweeper_new_game_cb" object="game" swapped="no"/>
</object>
</child>
<child type="title">
<object class="GtkImage">
<property name="icon-name">trophy-gold</property>
<binding name="visible">
<lookup name="win">game</lookup>
</binding>
</object>
</child>
</object>
</child>
<child>
<object class="GtkGridView" id="view">
<property name="model">
<object class="GtkNoSelection">
<property name="model">game</property>
</object>
</property>
<property name="single-click-activate">1</property>
<binding name="max-columns">
<lookup name="width">game</lookup>
</binding>
<binding name="min-columns">
<lookup name="width">game</lookup>
</binding>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/listview_minesweeper/listview_minesweeper_cell.ui</property>
</object>
</property>
<signal name="activate" handler="minesweeper_cell_clicked_cb" object="game" swapped="no"/>
</object>
</child>
</object>
</interface>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="halign">center</property>
<property name="valign">center</property>
<binding name="label">
<lookup name="label" type="SweeperCell">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>

View File

@@ -1,432 +0,0 @@
/* Lists/Settings
*
* This demo shows a settings viewer for GSettings.
*
* It demonstrates how to implement support for trees with GtkListView.
* It also shows how to set up sorting and filtering for columns in a
* GtkColumnView.
*/
#include <gtk/gtk.h>
#include <stdlib.h>
/* Create an object that wraps GSettingsSchemaKey because that's a boxed type */
typedef struct _SettingsKey SettingsKey;
struct _SettingsKey
{
GObject parent_instance;
GSettings *settings;
GSettingsSchemaKey *key;
};
enum {
PROP_0,
PROP_NAME,
PROP_SUMMARY,
PROP_DESCRIPTION,
PROP_VALUE,
PROP_TYPE,
PROP_DEFAULT_VALUE,
N_PROPS
};
#define SETTINGS_TYPE_KEY (settings_key_get_type ())
G_DECLARE_FINAL_TYPE (SettingsKey, settings_key, SETTINGS, KEY, GObject);
G_DEFINE_TYPE (SettingsKey, settings_key, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
settings_key_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SettingsKey *self = SETTINGS_KEY (object);
switch (property_id)
{
case PROP_DESCRIPTION:
g_value_set_string (value, g_settings_schema_key_get_description (self->key));
break;
case PROP_NAME:
g_value_set_string (value, g_settings_schema_key_get_name (self->key));
break;
case PROP_SUMMARY:
g_value_set_string (value, g_settings_schema_key_get_summary (self->key));
break;
case PROP_VALUE:
{
GVariant *variant = g_settings_get_value (self->settings, g_settings_schema_key_get_name (self->key));
g_value_take_string (value, g_variant_print (variant, FALSE));
g_variant_unref (variant);
}
break;
case PROP_TYPE:
{
const GVariantType *type = g_settings_schema_key_get_value_type (self->key);
g_value_set_string (value, g_variant_type_peek_string (type));
}
break;
case PROP_DEFAULT_VALUE:
{
GVariant *variant = g_settings_schema_key_get_default_value (self->key);
g_value_take_string (value, g_variant_print (variant, FALSE));
g_variant_unref (variant);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
settings_key_finalize (GObject *object)
{
SettingsKey *self = SETTINGS_KEY (object);
g_object_unref (self->settings);
g_settings_schema_key_unref (self->key);
G_OBJECT_CLASS (settings_key_parent_class)->finalize (object);
}
static void
settings_key_class_init (SettingsKeyClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = settings_key_finalize;
gobject_class->get_property = settings_key_get_property;
properties[PROP_DESCRIPTION] =
g_param_spec_string ("description", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_SUMMARY] =
g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_VALUE] =
g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_TYPE] =
g_param_spec_string ("type", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_DEFAULT_VALUE] =
g_param_spec_string ("default-value", NULL, NULL, NULL, G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
settings_key_init (SettingsKey *self)
{
}
static SettingsKey *
settings_key_new (GSettings *settings,
GSettingsSchemaKey *key)
{
SettingsKey *result = g_object_new (SETTINGS_TYPE_KEY, NULL);
result->settings = g_object_ref (settings);
result->key = g_settings_schema_key_ref (key);
return result;
}
static void
item_value_changed (GtkListItem *item,
GtkEntry *entry)
{
SettingsKey *self;
const char *text;
const GVariantType *type;
GVariant *variant;
GError *error = NULL;
const char *name;
text = gtk_editable_get_text (GTK_EDITABLE (entry));
g_object_get (item, "item", &self, NULL);
g_object_unref (self);
type = g_settings_schema_key_get_value_type (self->key);
name = g_settings_schema_key_get_name (self->key);
variant = g_variant_parse (type, text, NULL, NULL, &error);
if (!variant)
{
g_warning ("%s", error->message);
g_clear_error (&error);
return;
}
if (!g_settings_schema_key_range_check (self->key, variant))
{
g_warning ("Not a valid value for %s", name);
return;
}
g_settings_set_value (self->settings, name, variant);
g_variant_unref (variant);
}
static int
strvcmp (gconstpointer p1,
gconstpointer p2)
{
const char * const *s1 = p1;
const char * const *s2 = p2;
return strcmp (*s1, *s2);
}
static GtkFilter *current_filter;
static gboolean
transform_settings_to_keys (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer data)
{
GtkTreeListRow *treelistrow;
GSettings *settings;
GSettingsSchema *schema;
GListStore *store;
GtkSortListModel *sort_model;
GtkFilterListModel *filter_model;
GtkFilter *filter;
GtkNoSelection *selection_model;
GtkExpression *expression;
char **keys;
guint i;
treelistrow = g_value_get_object (from_value);
if (treelistrow == NULL)
return TRUE;
settings = gtk_tree_list_row_get_item (treelistrow);
g_object_get (settings, "settings-schema", &schema, NULL);
store = g_list_store_new (SETTINGS_TYPE_KEY);
keys = g_settings_schema_list_keys (schema);
for (i = 0; keys[i] != NULL; i++)
{
GSettingsSchemaKey *almost_there = g_settings_schema_get_key (schema, keys[i]);
SettingsKey *finally = settings_key_new (settings, almost_there);
g_list_store_append (store, finally);
g_object_unref (finally);
g_settings_schema_key_unref (almost_there);
}
g_strfreev (keys);
g_settings_schema_unref (schema);
g_object_unref (settings);
sort_model = gtk_sort_list_model_new (G_LIST_MODEL (store),
gtk_column_view_get_sorter (GTK_COLUMN_VIEW (data)));
g_object_unref (store);
expression = gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name");
filter = gtk_string_filter_new ();
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (sort_model), filter);
gtk_expression_unref (expression);
g_object_unref (sort_model);
g_set_object (&current_filter, filter);
g_object_unref (filter);
selection_model = gtk_no_selection_new (G_LIST_MODEL (filter_model));
g_object_unref (filter_model);
g_value_take_object (to_value, selection_model);
return TRUE;
}
static GListModel *
create_settings_model (gpointer item,
gpointer unused)
{
GSettings *settings = item;
char **schemas;
GListStore *result;
guint i;
if (settings == NULL)
{
g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (),
TRUE,
&schemas,
NULL);
}
else
{
schemas = g_settings_list_children (settings);
}
if (schemas == NULL || schemas[0] == NULL)
{
g_free (schemas);
return NULL;
}
qsort (schemas, g_strv_length (schemas), sizeof (char *), strvcmp);
result = g_list_store_new (G_TYPE_SETTINGS);
for (i = 0; schemas[i] != NULL; i++)
{
GSettings *child;
if (settings == NULL)
child = g_settings_new (schemas[i]);
else
child = g_settings_get_child (settings, schemas[i]);
g_list_store_append (result, child);
g_object_unref (child);
}
g_strfreev (schemas);
return G_LIST_MODEL (result);
}
static void
search_enabled (GtkSearchEntry *entry)
{
gtk_editable_set_text (GTK_EDITABLE (entry), "");
}
static void
search_changed (GtkSearchEntry *entry,
gpointer data)
{
const char *text = gtk_editable_get_text (GTK_EDITABLE (entry));
if (current_filter)
gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), text);
}
static void
stop_search (GtkSearchEntry *entry,
gpointer data)
{
gtk_editable_set_text (GTK_EDITABLE (entry), "");
if (current_filter)
gtk_string_filter_set_search (GTK_STRING_FILTER (current_filter), "");
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_settings (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *columnview;
GListModel *model;
GtkTreeListModel *treemodel;
GtkSingleSelection *selection;
GtkBuilderScope *scope;
GtkBuilder *builder;
GtkColumnViewColumn *name_column;
GtkColumnViewColumn *type_column;
GtkColumnViewColumn *default_column;
GtkColumnViewColumn *summary_column;
GtkColumnViewColumn *description_column;
GtkSorter *sorter;
GActionGroup *actions;
GAction *action;
g_type_ensure (SETTINGS_TYPE_KEY);
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_enabled", (GCallback)search_enabled);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_changed", (GCallback)search_changed);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "stop_search", (GCallback)stop_search);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "item_value_changed", (GCallback)item_value_changed);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/listview_settings/listview_settings.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview"));
type_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "type_column"));
default_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "default_column"));
summary_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "summary_column"));
description_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "description_column"));
actions = G_ACTION_GROUP (g_simple_action_group_new ());
action = G_ACTION (g_property_action_new ("show-type", type_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-default", default_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-summary", summary_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
action = G_ACTION (g_property_action_new ("show-description", description_column, "visible"));
g_action_map_add_action (G_ACTION_MAP (actions), action);
g_object_unref (action);
gtk_widget_insert_action_group (columnview, "columnview", actions);
g_object_unref (actions);
model = create_settings_model (NULL, NULL);
treemodel = gtk_tree_list_model_new (FALSE,
model,
TRUE,
create_settings_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_object_bind_property_full (selection, "selected-item",
columnview, "model",
G_BINDING_SYNC_CREATE,
transform_settings_to_keys,
NULL,
columnview, NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
g_object_unref (selection);
g_object_unref (treemodel);
g_object_unref (model);
name_column = GTK_COLUMN_VIEW_COLUMN (gtk_builder_get_object (builder, "name_column"));
sorter = gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "name"));
gtk_column_view_column_set_sorter (name_column, sorter);
g_object_unref (sorter);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,281 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Settings</property>
<property name="default-width">640</property>
<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>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned">
<property name="position">300</property>
<child>
<object class="GtkScrolledWindow">
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="schema" type="GSettings">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar">
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional"/>
<signal name="notify::search-mode-enabled" handler="search_enabled" object="entry"/>
<child>
<object class="GtkSearchEntry" id="entry">
<signal name="search-changed" handler="search_changed"/>
<signal name="stop-search" handler="stop_search"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkColumnView" id="columnview">
<child>
<object class="GtkColumnViewColumn" id="name_column">
<property name="title">Name</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="name" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn">
<property name="title">Value</property>
<property name="resizable">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkEntry">
<signal name="activate" handler="item_value_changed" object="GtkListItem" swapped="yes"/>
<property name="xalign">0</property>
<binding name="text">
<lookup name="value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="type_column">
<property name="title">Type</property>
<property name="resizable">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="type" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="default_column">
<property name="title">Default</property>
<property name="resizable">1</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="default-value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="summary_column">
<property name="title">Summary</property>
<property name="resizable">1</property>
<property name="visible">0</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="summary" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn" id="description_column">
<property name="title">Description</property>
<property name="resizable">1</property>
<property name="visible">0</property>
<property name="expand">1</property>
<property name="header-menu">header_menu</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="wrap">1</property>
<binding name="label">
<lookup name="description" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<menu id="header_menu">
<section>
<item>
<attribute name="label" translatable="yes">Type</attribute>
<attribute name="action">columnview.show-type</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Default value</attribute>
<attribute name="action">columnview.show-default</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Summary</attribute>
<attribute name="action">columnview.show-summary</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Description</attribute>
<attribute name="action">columnview.show-description</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -1,326 +0,0 @@
/* Lists/Weather
*
* This demo shows a few of the rarer features of GtkListView and
* how they can be used to display weather information.
*
* The hourly weather info uses a horizontal listview. This is easy
* to achieve because GtkListView implements the GtkOrientable interface.
* To make the items in the list stand out more, the listview uses
* separators.
*
* A GtkNoSelectionModel is used to make sure no item in the list can be
* selected. All other interactions with the items is still possible.
*
* The dataset used here has 70000 items.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_WEATHER_INFO (gtk_weather_info_get_type ())
G_DECLARE_FINAL_TYPE (GtkWeatherInfo, gtk_weather_info, GTK, WEATHER_INFO, GObject)
typedef enum {
GTK_WEATHER_CLEAR,
GTK_WEATHER_FEW_CLOUDS,
GTK_WEATHER_FOG,
GTK_WEATHER_OVERCAST,
GTK_WEATHER_SCATTERED_SHOWERS,
GTK_WEATHER_SHOWERS,
GTK_WEATHER_SNOW,
GTK_WEATHER_STORM
} GtkWeatherType;
struct _GtkWeatherInfo
{
GObject parent_instance;
gint64 timestamp;
int temperature;
GtkWeatherType weather_type;
};
struct _GtkWeatherInfoClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (GtkWeatherInfo, gtk_weather_info, G_TYPE_OBJECT)
static void
gtk_weather_info_class_init (GtkWeatherInfoClass *klass)
{
}
static void
gtk_weather_info_init (GtkWeatherInfo *self)
{
}
static GtkWeatherInfo *
gtk_weather_info_new (GDateTime *timestamp,
GtkWeatherInfo *copy_from)
{
GtkWeatherInfo *result;
result = g_object_new (GTK_TYPE_WEATHER_INFO, NULL);
result->timestamp = g_date_time_to_unix (timestamp);
if (copy_from)
{
result->temperature = copy_from->temperature;
result->weather_type = copy_from->weather_type;
g_object_unref (copy_from);
}
return result;
}
static GDateTime *
parse_timestamp (const char *string,
GTimeZone *_timezone)
{
char *with_seconds;
GDateTime *result;
with_seconds = g_strconcat (string, ":00", NULL);
result = g_date_time_new_from_iso8601 (with_seconds, _timezone);
g_free (with_seconds);
return result;
}
static GtkWeatherType
parse_weather_type (const char *clouds,
const char *precip,
GtkWeatherType fallback)
{
if (strstr (precip, "SN"))
return GTK_WEATHER_SNOW;
if (strstr (precip, "TS"))
return GTK_WEATHER_STORM;
if (strstr (precip, "DZ"))
return GTK_WEATHER_SCATTERED_SHOWERS;
if (strstr (precip, "SH") || strstr (precip, "RA"))
return GTK_WEATHER_SHOWERS;
if (strstr (precip, "FG"))
return GTK_WEATHER_FOG;
if (g_str_equal (clouds, "M") ||
g_str_equal (clouds, ""))
return fallback;
if (strstr (clouds, "OVC") ||
strstr (clouds, "BKN"))
return GTK_WEATHER_OVERCAST;
if (strstr (clouds, "BKN") ||
strstr (clouds, "SCT"))
return GTK_WEATHER_FEW_CLOUDS;
if (strstr (clouds, "VV"))
return GTK_WEATHER_FOG;
return GTK_WEATHER_CLEAR;
}
static double
parse_temperature (const char *s,
double fallback)
{
char *endptr;
double d;
d = g_ascii_strtod (s, &endptr);
if (*endptr != '\0')
return fallback;
return d;
}
static GListModel *
create_weather_model (void)
{
GListStore *store;
GTimeZone *utc;
GDateTime *timestamp;
GtkWeatherInfo *info;
GBytes *data;
char **lines;
guint i;
store = g_list_store_new (GTK_TYPE_WEATHER_INFO);
data = g_resources_lookup_data ("/listview_weather/listview_weather.txt", 0, NULL);
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
utc = g_time_zone_new_utc ();
timestamp = g_date_time_new (utc, 2011, 1, 1, 0, 0, 0);
info = gtk_weather_info_new (timestamp, NULL);
g_list_store_append (store, info);
for (i = 0; lines[i] != NULL && *lines[i]; i++)
{
char **fields;
GDateTime *date;
fields = g_strsplit (lines[i], ",", 0);
date = parse_timestamp (fields[0], utc);
while (g_date_time_difference (date, timestamp) > 30 * G_TIME_SPAN_MINUTE)
{
GDateTime *new_timestamp = g_date_time_add_hours (timestamp, 1);
g_date_time_unref (timestamp);
timestamp = new_timestamp;
info = gtk_weather_info_new (timestamp, info);
g_list_store_append (store, info);
}
info->temperature = parse_temperature (fields[1], info->temperature);
info->weather_type = parse_weather_type (fields[2], fields[3], info->weather_type);
g_date_time_unref (date);
g_strfreev (fields);
}
g_strfreev (lines);
g_bytes_unref (data);
g_time_zone_unref (utc);
return G_LIST_MODEL (store);
}
static void
setup_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
child = gtk_label_new (NULL);
gtk_label_set_width_chars (GTK_LABEL (child), 5);
gtk_box_append (GTK_BOX (box), child);
child = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (child), GTK_ICON_SIZE_LARGE);
gtk_box_append (GTK_BOX (box), child);
child = gtk_label_new (NULL);
gtk_widget_set_vexpand (child, TRUE);
gtk_widget_set_valign (child, GTK_ALIGN_END);
gtk_label_set_width_chars (GTK_LABEL (child), 4);
gtk_box_append (GTK_BOX (box), child);
}
static void
bind_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
GtkWeatherInfo *info;
GDateTime *timestamp;
char *s;
box = gtk_list_item_get_child (list_item);
info = gtk_list_item_get_item (list_item);
child = gtk_widget_get_first_child (box);
timestamp = g_date_time_new_from_unix_utc (info->timestamp);
s = g_date_time_format (timestamp, "%R");
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
g_date_time_unref (timestamp);
child = gtk_widget_get_next_sibling (child);
switch (info->weather_type)
{
case GTK_WEATHER_CLEAR:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-clear-symbolic");
break;
case GTK_WEATHER_FEW_CLOUDS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-few-clouds-symbolic");
break;
case GTK_WEATHER_FOG:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-fog-symbolic");
break;
case GTK_WEATHER_OVERCAST:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-overcast-symbolic");
break;
case GTK_WEATHER_SCATTERED_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-scattered-symbolic");
break;
case GTK_WEATHER_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-symbolic");
break;
case GTK_WEATHER_SNOW:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-snow-symbolic");
break;
case GTK_WEATHER_STORM:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-storm-symbolic");
break;
default:
gtk_image_clear (GTK_IMAGE (child));
break;
}
child = gtk_widget_get_next_sibling (child);
s = g_strdup_printf ("%d°", info->temperature);
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
}
static GtkWidget *window = NULL;
GtkWidget *
create_weather_view (void)
{
GtkWidget *listview;
GListModel *model, *selection;
listview = gtk_list_view_new_with_factory (
gtk_functions_list_item_factory_new (setup_widget,
bind_widget,
NULL, NULL));
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 ();
selection = G_LIST_MODEL (gtk_no_selection_new (model));
gtk_list_view_set_model (GTK_LIST_VIEW (listview), selection);
g_object_unref (selection);
g_object_unref (model);
return listview;
}
GtkWidget *
do_listview_weather (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *sw;
window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
gtk_window_set_title (GTK_WINDOW (window), "Weather");
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Weather");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_window_set_child (GTK_WINDOW (window), sw);
listview = create_weather_view ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<lookup name="title" type="GtkDemo">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>

View File

@@ -16,96 +16,18 @@ static GtkWidget *source_view;
static gchar *current_file = NULL;
static GtkWidget *notebook;
static GtkSingleSelection *selection;
static GtkWidget *treeview;
static GtkWidget *toplevel;
typedef struct _GtkDemo GtkDemo;
struct _GtkDemo
{
GObject parent_instance;
const char *name;
const char *title;
const char *filename;
GDoDemoFunc func;
GListModel *children_model;
};
enum {
PROP_0,
PROP_FILENAME,
PROP_NAME,
PROP_TITLE,
N_PROPS
NAME_COLUMN,
TITLE_COLUMN,
FILENAME_COLUMN,
FUNC_COLUMN,
STYLE_COLUMN,
NUM_COLUMNS
};
# define GTK_TYPE_DEMO (gtk_demo_get_type ())
G_DECLARE_FINAL_TYPE (GtkDemo, gtk_demo, GTK, DEMO, GObject);
G_DEFINE_TYPE (GtkDemo, gtk_demo, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_demo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkDemo *self = GTK_DEMO (object);
switch (property_id)
{
case PROP_FILENAME:
g_value_set_string (value, self->filename);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void gtk_demo_class_init (GtkDemoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_demo_get_property;
properties[PROP_FILENAME] =
g_param_spec_string ("filename",
"filename",
"filename",
NULL,
G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name",
"name",
"name",
NULL,
G_PARAM_READABLE);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"title",
"title",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void gtk_demo_init (GtkDemo *self)
{
}
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
@@ -113,27 +35,6 @@ struct _CallbackData
GtkTreePath *path;
};
static gboolean
gtk_demo_run (GtkDemo *self,
GtkWidget *window)
{
GtkWidget *result;
if (!self->func)
return FALSE;
result = self->func (window);
if (result == NULL)
return FALSE;
if (GTK_IS_WINDOW (result))
{
gtk_window_set_transient_for (GTK_WINDOW (result), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (result), TRUE);
}
return TRUE;
}
static void
activate_about (GSimpleAction *action,
GVariant *parameter,
@@ -160,7 +61,7 @@ activate_about (GSimpleAction *action,
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
g_string_append_printf (s, "\nA link can appear here: <http://www.gtk.org>");
g_string_append_printf (s, "\nA link can apppear here: <http://www.gtk.org>");
version = g_strdup_printf ("%s\nRunning against GTK %d.%d.%d",
PACKAGE_VERSION,
@@ -214,15 +115,82 @@ activate_inspector (GSimpleAction *action,
gtk_window_set_interactive_debugging (TRUE);
}
static void
window_closed_cb (GtkWidget *window, gpointer data)
{
CallbackData *cbdata = data;
GtkTreeIter iter;
PangoStyle style;
gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
STYLE_COLUMN, &style,
-1);
if (style == PANGO_STYLE_ITALIC)
gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
gtk_tree_path_free (cbdata->path);
g_free (cbdata);
}
static void
run_example_for_row (GtkWidget *window,
GtkTreeModel *model,
GtkTreeIter *iter)
{
PangoStyle style;
GDoDemoFunc func;
GtkWidget *demo;
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
FUNC_COLUMN, &func,
STYLE_COLUMN, &style,
-1);
if (func)
{
gtk_tree_store_set (GTK_TREE_STORE (model),
iter,
STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
-1);
demo = (func) (window);
if (demo != NULL)
{
CallbackData *cbdata;
cbdata = g_new (CallbackData, 1);
cbdata->model = model;
cbdata->path = gtk_tree_model_get_path (model, iter);
if (GTK_IS_WINDOW (demo))
{
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
}
g_signal_connect (demo, "destroy",
G_CALLBACK (window_closed_cb), cbdata);
}
}
}
static void
activate_run (GSimpleAction *action,
GVariant *parameter,
gpointer window)
gpointer user_data)
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
GtkWidget *window = user_data;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
gtk_demo_run (demo, window);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
run_example_for_row (window, model, &iter);
}
/* Stupid syntax highlighting.
@@ -599,7 +567,7 @@ display_image (const char *resource)
{
GtkWidget *sw, *image;
image = gtk_picture_new_for_resource (resource);
image = gtk_image_new_from_resource (resource);
gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
sw = gtk_scrolled_window_new (NULL, NULL);
@@ -927,93 +895,124 @@ load_file (const gchar *demoname,
}
static void
activate_cb (GtkWidget *widget,
guint position,
gpointer window)
selection_cb (GtkTreeSelection *selection,
GtkTreeModel *model)
{
GtkTreeListRow *row = g_list_model_get_item (gtk_list_view_get_model (GTK_LIST_VIEW (widget)), position);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
GtkTreeIter iter;
char *name;
char *filename;
char *title;
gtk_demo_run (demo, window);
if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
g_object_unref (row);
gtk_tree_model_get (model, &iter,
NAME_COLUMN, &name,
TITLE_COLUMN, &title,
FILENAME_COLUMN, &filename,
-1);
if (filename)
load_file (name, filename);
gtk_window_set_title (GTK_WINDOW (toplevel), title);
g_free (name);
g_free (title);
g_free (filename);
}
static void
selection_cb (GtkSingleSelection *sel,
GParamSpec *pspec,
gpointer user_data)
populate_model (GtkTreeModel *model)
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (sel);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
Demo *d = gtk_demos;
if (demo->filename)
load_file (demo->name, demo->filename);
gtk_window_set_title (GTK_WINDOW (toplevel), demo->title);
}
static GListModel *
create_demo_model (void)
{
GListStore *store = g_list_store_new (GTK_TYPE_DEMO);
DemoData *demo = gtk_demos;
while (demo->title)
/* this code only supports 1 level of children. If we
* want more we probably have to use a recursing function.
*/
while (d->title)
{
GtkDemo *d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
DemoData *children = demo->children;
Demo *children = d->children;
GtkTreeIter iter;
d->name = demo->name;
d->title = demo->title;
d->filename = demo->filename;
d->func = demo->func;
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
g_list_store_append (store, d);
gtk_tree_store_set (GTK_TREE_STORE (model),
&iter,
NAME_COLUMN, d->name,
TITLE_COLUMN, d->title,
FILENAME_COLUMN, d->filename,
FUNC_COLUMN, d->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
if (children)
d++;
if (!children)
continue;
while (children->title)
{
d->children_model = G_LIST_MODEL (g_list_store_new (GTK_TYPE_DEMO));
GtkTreeIter child_iter;
while (children->title)
{
GtkDemo *child = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
child->name = children->name;
child->title = children->title;
child->filename = children->filename;
child->func = children->func;
gtk_tree_store_set (GTK_TREE_STORE (model),
&child_iter,
NAME_COLUMN, children->name,
TITLE_COLUMN, children->title,
FILENAME_COLUMN, children->filename,
FUNC_COLUMN, children->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
g_list_store_append (G_LIST_STORE (d->children_model), child);
children++;
}
children++;
}
demo++;
}
return G_LIST_MODEL (store);
}
static GListModel *
get_child_model (gpointer item,
gpointer user_data)
static void
startup (GApplication *app)
{
GtkDemo *demo = item;
GtkBuilder *builder;
GMenuModel *appmenu;
const char *ids[] = { "appmenu", NULL };
if (demo->children_model)
return g_object_ref (G_LIST_MODEL (demo->children_model));
builder = gtk_builder_new ();
gtk_builder_add_objects_from_resource (builder, "/ui/appmenu.ui", ids, NULL);
return NULL;
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
g_object_unref (builder);
}
static void
row_activated_cb (GtkWidget *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column)
{
GtkTreeIter iter;
GtkWidget *window;
GtkTreeModel *model;
window = GTK_WIDGET (gtk_widget_get_root (tree_view));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
gtk_tree_model_get_iter (model, &iter, path);
run_example_for_row (window, model, &iter);
}
static void
activate (GApplication *app)
{
GtkBuilder *builder;
GListModel *listmodel;
GtkTreeListModel *treemodel;
GtkWidget *window, *listview;
GtkWindow *window;
GtkWidget *widget;
GtkTreeModel *model;
GtkTreeIter iter;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
@@ -1021,33 +1020,35 @@ activate (GApplication *app)
builder = gtk_builder_new_from_resource ("/ui/main.ui");
window = (GtkWidget *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window));
window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window);
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
window);
notebook = GTK_WIDGET (gtk_builder_get_object (builder, "notebook"));
notebook = (GtkWidget *)gtk_builder_get_object (builder, "notebook");
info_view = GTK_WIDGET (gtk_builder_get_object (builder, "info-textview"));
source_view = GTK_WIDGET (gtk_builder_get_object (builder, "source-textview"));
info_view = (GtkWidget *)gtk_builder_get_object (builder, "info-textview");
source_view = (GtkWidget *)gtk_builder_get_object (builder, "source-textview");
treeview = (GtkWidget *)gtk_builder_get_object (builder, "treeview");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
toplevel = GTK_WIDGET (window);
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
g_signal_connect (listview, "activate", G_CALLBACK (activate_cb), window);
load_file (gtk_demos[0].name, gtk_demos[0].filename);
listmodel = create_demo_model ();
treemodel = gtk_tree_list_model_new (FALSE,
G_LIST_MODEL (listmodel),
TRUE,
get_child_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_signal_connect (selection, "notify::selected-item", G_CALLBACK (selection_cb), NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview),
G_LIST_MODEL (selection));
populate_model (model);
g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), model);
widget = (GtkWidget *)gtk_builder_get_object (builder, "treeview-selection");
g_signal_connect (widget, "changed", G_CALLBACK (selection_cb), model);
gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)), &iter);
gtk_tree_selection_select_iter (GTK_TREE_SELECTION (widget), &iter);
gtk_tree_view_collapse_all (GTK_TREE_VIEW (treeview));
gtk_widget_show (GTK_WIDGET (window));
g_object_unref (builder);
}
@@ -1062,7 +1063,7 @@ auto_quit (gpointer data)
static void
list_demos (void)
{
DemoData *d, *c;
Demo *d, *c;
d = gtk_demos;
@@ -1089,7 +1090,7 @@ command_line (GApplication *app,
const gchar *name = NULL;
gboolean autoquit = FALSE;
gboolean list = FALSE;
DemoData *d, *c;
Demo *d, *c;
GDoDemoFunc func = 0;
GtkWidget *window, *demo;
@@ -1107,11 +1108,11 @@ command_line (GApplication *app,
return 0;
}
window = gtk_application_get_windows (GTK_APPLICATION (app))->data;
if (name == NULL)
goto out;
window = gtk_application_get_windows (GTK_APPLICATION (app))->data;
d = gtk_demos;
while (d->title)
@@ -1141,11 +1142,7 @@ out:
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
g_signal_connect_swapped (G_OBJECT (demo), "destroy", G_CALLBACK (g_application_quit), app);
}
else
gtk_widget_show (GTK_WIDGET (window));
if (autoquit)
g_timeout_add_seconds (1, auto_quit, app);
@@ -1222,6 +1219,7 @@ main (int argc, char **argv)
g_application_add_main_option (G_APPLICATION (app), "list", 0, 0, G_OPTION_ARG_NONE, "List examples", NULL);
g_application_add_main_option (G_APPLICATION (app), "autoquit", 0, 0, G_OPTION_ARG_NONE, "Quit after a delay", NULL);
g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
g_signal_connect (app, "command-line", G_CALLBACK (command_line), NULL);
g_signal_connect (app, "handle-local-options", G_CALLBACK (local_options), NULL);

View File

@@ -65,12 +65,30 @@
<property name="hscrollbar-policy">never</property>
<property name="min-content-width">150</property>
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/ui/main-listitem.ui</property>
<object class="GtkTreeView" id="treeview">
<property name="model">treestore</property>
<property name="headers-visible">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection">
<property name="mode">browse</property>
</object>
</property>
</child>
<child>
<object class="GtkTreeViewColumn">
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="style">4</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText">
<property name="text"> </property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>

View File

@@ -5,7 +5,7 @@ Text <span color="gray">c<span color="green">o</span>l<span color="tomato">o</sp
Colorful <span underline="low" underline-color="blue"><span underline="double" underline-color="red">under</span>lines</span> and <span background="pink"><span underline="error">mo</span><span underline="error" underline-color="green">re</span></span>
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span> and <span overline="single" overline_color="green">overlines</span>
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span>
Superscripts and subscripts: 𝜀<span rise="-6000" size="x-small" font_desc="italic">0</span> = 𝜔<span rise="8000" size="smaller">𝜔<span rise="14000" size="smaller">𝜔<span rise="20000">.<span rise="23000">.<span rise="26000">.</span></span></span></span></span>

View File

@@ -1,39 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="appmenu">
<section>
<item>
<attribute name="label" translatable="yes">_New</attribute>
<attribute name="action">app.new</attribute>
<attribute name="accel">&lt;Control&gt;n</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open</attribute>
<attribute name="action">app.open</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="action">app.save</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save _As...</attribute>
<attribute name="action">app.save-as</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Control&gt;q</attribute>
</item>
</section>
</menu>
<menu id="menubar">
<submenu>
<attribute name="label" translatable="yes">_Application</attribute>
<section>
<item>
<attribute name="label" translatable="yes">_New</attribute>
<attribute name="action">app.new</attribute>
<attribute name="accel">&lt;Control&gt;n</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open</attribute>
<attribute name="action">app.open</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Save</attribute>
<attribute name="action">app.save</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save _As...</attribute>
<attribute name="action">app.save-as</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Control&gt;q</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_File</attribute>
<attribute name="label" translatable="yes">_Preferences</attribute>
<section>
<item>
<attribute name="label" translatable="yes">_Prefer Dark Theme</attribute>

View File

@@ -18,7 +18,6 @@ demos = files([
'cursors.c',
'dialog.c',
'drawingarea.c',
'dropdown.c',
'dnd.c',
'editable_cells.c',
'entry_completion.c',
@@ -42,13 +41,6 @@ demos = files([
'listbox.c',
'flowbox.c',
'list_store.c',
'listview_applauncher.c',
'listview_clocks.c',
'listview_colors.c',
'listview_filebrowser.c',
'listview_minesweeper.c',
'listview_settings.c',
'listview_weather.c',
'markup.c',
'modelbutton.c',
'overlay.c',
@@ -103,7 +95,7 @@ extra_demo_sources = files(['main.c',
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
extra_demo_sources += files(['script-names.c', 'language-names.c'])
gtkdemo_deps += [ harfbuzz_dep, epoxy_dep ]
gtkdemo_deps += [ harfbuzz_dep, ]
endif
if os_unix

View File

@@ -218,7 +218,7 @@ gtk_nuclear_media_stream_seek (GtkMediaStream *stream,
gtk_media_stream_seek_success (stream);
/* We also have to update our timestamp and tell the
* paintable interface about the seek
* paintable interface abbout the seek
*/
gtk_media_stream_update (stream, nuclear->progress);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (nuclear));
@@ -263,7 +263,7 @@ gtk_nuclear_media_stream_init (GtkNuclearMediaStream *nuclear)
/* This time, we don't have to add a timer here, because media
* streams start paused.
*
* However, media streams need to tell GTK once they are initialized,
* However, media streams need to tell GTK once they are intialized,
* so we do that here.
*/
gtk_media_stream_prepared (GTK_MEDIA_STREAM (nuclear),

View File

@@ -11,7 +11,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *entry;
static GtkWidget *entry2;
static GtkWidget *button;
@@ -28,13 +27,6 @@ update_button (GObject *object,
text[0] != '\0' && g_str_equal (text, text2));
}
static void
button_pressed (GtkButton *widget,
GtkWidget *window)
{
gtk_window_destroy (GTK_WINDOW (window));
}
GtkWidget *
do_password_entry (GtkWidget *do_widget)
{
@@ -82,7 +74,7 @@ do_password_entry (GtkWidget *do_widget)
button = gtk_button_new_with_mnemonic ("_Done");
gtk_widget_add_css_class (button, "suggested-action");
g_signal_connect (button, "clicked", G_CALLBACK (button_pressed), window);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);
gtk_widget_set_sensitive (button, FALSE);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);

View File

@@ -25,12 +25,13 @@ static gboolean
reveal_one (gpointer data)
{
GtkWidget *window = data;
GtkBuilder *builder;
gchar *name;
GtkRevealer *revealer;
builder = GTK_BUILDER (g_object_get_data (G_OBJECT (window), "builder"));
name = g_strdup_printf ("revealer%d", count);
revealer = GTK_REVEALER (g_object_get_data (G_OBJECT (window), name));
g_free (name);
revealer = (GtkRevealer *)gtk_builder_get_object (builder, name);
gtk_revealer_set_reveal_child (revealer, TRUE);
@@ -58,7 +59,6 @@ on_destroy (gpointer data)
g_source_remove (timeout);
timeout = 0;
}
}
GtkWidget *
@@ -67,23 +67,14 @@ do_revealer (GtkWidget *do_widget)
if (!window)
{
GtkBuilder *builder;
int i;
builder = gtk_builder_new_from_resource ("/revealer/revealer.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
for (i = 0; i < 10; i++)
{
char *name = g_strdup_printf ("revealer%d", i);
GtkWidget *revealer = GTK_WIDGET (gtk_builder_get_object (builder, name));
g_object_set_data (G_OBJECT (window), name, revealer);
g_free (name);
}
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (on_destroy), NULL);
g_object_unref (builder);
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))

View File

@@ -1,4 +1,4 @@
/* Sliding Puzzle
/* Sliding puzzle
*
* This demo demonstrates how to use gestures and paintables to create a
* small sliding puzzle game.
@@ -11,7 +11,6 @@
#include "puzzlepiece.h"
#include "paintable.h"
static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
static GtkWidget *choices = NULL;
@@ -241,8 +240,6 @@ puzzle_button_pressed (GtkGestureClick *gesture,
{
gtk_widget_error_bell (grid);
}
check_solved (grid);
}
static void
@@ -283,8 +280,6 @@ start_puzzle (GdkPaintable *paintable)
/* Add shortcuts so people can use the arrow
* keys to move the puzzle */
controller = gtk_shortcut_controller_new ();
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
GTK_SHORTCUT_SCOPE_GLOBAL);
add_move_binding (GTK_SHORTCUT_CONTROLLER (controller),
GDK_KEY_Left, GDK_KEY_KP_Left,
-1, 0);
@@ -345,16 +340,11 @@ reshuffle (void)
{
GtkWidget *grid;
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
if (solved)
{
start_puzzle (puzzle);
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
}
start_puzzle (puzzle);
else
{
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
shuffle_puzzle (grid);
}
shuffle_puzzle (grid);
gtk_widget_grab_focus (grid);
}
@@ -397,18 +387,9 @@ add_choice (GtkWidget *container,
icon = gtk_image_new_from_paintable (paintable);
gtk_image_set_icon_size (GTK_IMAGE (icon), GTK_ICON_SIZE_LARGE);
gtk_flow_box_insert (GTK_FLOW_BOX (container), icon, -1);
gtk_box_append (GTK_BOX (container), icon);
}
static void
widget_destroyed (gpointer data,
GObject *widget)
{
if (data)
*(gpointer *) data = NULL;
}
GtkWidget *
do_sliding_puzzle (GtkWidget *do_widget)
{
@@ -479,7 +460,7 @@ do_sliding_puzzle (GtkWidget *do_widget)
gtk_window_set_title (GTK_WINDOW (window), "Sliding Puzzle");
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_object_weak_ref (G_OBJECT (window), widget_destroyed, &window);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
frame = gtk_aspect_frame_new (0.5, 0.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
gtk_window_set_child (GTK_WINDOW (window), frame);

View File

@@ -92,11 +92,12 @@ static Theme themes[] = {
static int theme;
static gboolean
change_theme (GtkWidget *widget,
change_theme (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer data)
gpointer data)
{
GtkWidget *label = data;
GtkBuilder *builder = data;
GtkWidget *label;
Theme next = themes[theme++ % G_N_ELEMENTS (themes)];
char *name;
@@ -109,6 +110,7 @@ change_theme (GtkWidget *widget,
gtk_window_set_title (GTK_WINDOW (widget), name);
g_free (name);
label = GTK_WIDGET (gtk_builder_get_object (builder, "fps"));
if (frame_clock)
{
char *fps;
@@ -125,10 +127,10 @@ change_theme (GtkWidget *widget,
static void
clicked (GtkGestureClick *gesture,
int n_press,
double x,
double y,
gpointer data)
int n_press,
double x,
double y,
gpointer data)
{
GtkWidget *window;
GdkEvent *event;
@@ -163,29 +165,6 @@ clicked (GtkGestureClick *gesture,
}
}
static void
toggle_cycle (GObject *button,
GParamSpec *pspec,
gpointer data)
{
gboolean active;
GtkWidget *window;
g_object_get (button, "active", &active, NULL);
window = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_WINDOW);
if (active && !tick_cb)
{
tick_cb = gtk_widget_add_tick_callback (window, change_theme, data, NULL);
}
else if (!active && tick_cb)
{
gtk_widget_remove_tick_callback (window, tick_cb);
tick_cb = 0;
}
}
GtkWidget *
do_themes (GtkWidget *do_widget)
{
@@ -195,8 +174,6 @@ do_themes (GtkWidget *do_widget)
{
GtkBuilder *builder;
GtkWidget *header;
GtkWidget *button;
GtkWidget *label;
GtkGesture *gesture;
builder = gtk_builder_new_from_resource ("/themes/themes.ui");
@@ -206,17 +183,11 @@ do_themes (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
header = GTK_WIDGET (gtk_builder_get_object (builder, "header"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "fps"));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), label);
g_signal_connect (gesture, "pressed", G_CALLBACK (clicked), builder);
gtk_widget_add_controller (header, GTK_EVENT_CONTROLLER (gesture));
button = GTK_WIDGET (gtk_builder_get_object (builder, "toggle"));
g_signal_connect (button, "notify::active", G_CALLBACK (toggle_cycle), label);
gtk_widget_realize (window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))

View File

@@ -5,11 +5,6 @@
<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>
</object>
</child>
<child type="end">
<object class="GtkLabel" id="fps"/>
</child>

View File

@@ -641,25 +641,24 @@ static GActionEntry app_entries[] = {
static const gchar ui_info[] =
"<interface>"
" <menu id='appmenu'>"
" <section>"
" <item>"
" <attribute name='label'>_About</attribute>"
" <attribute name='action'>app.about</attribute>"
" <attribute name='accel'>&lt;Primary&gt;a</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label'>_Quit</attribute>"
" <attribute name='action'>app.quit</attribute>"
" <attribute name='accel'>&lt;Primary&gt;q</attribute>"
" </item>"
" </section>"
" </menu>"
" <menu id='menubar'>"
" <submenu>"
" <attribute name='label'>_Application</attribute>"
" <section>"
" <item>"
" <attribute name='label'>_About</attribute>"
" <attribute name='action'>app.about</attribute>"
" <attribute name='accel'>&lt;Primary&gt;a</attribute>"
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label'>_Quit</attribute>"
" <attribute name='action'>app.quit</attribute>"
" <attribute name='accel'>&lt;Primary&gt;q</attribute>"
" </item>"
" </section>"
" </submenu>"
" <submenu>"
" <attribute name='label'>_File</attribute>"
" <section>"
" <item>"
@@ -739,13 +738,16 @@ static void
startup (GApplication *app)
{
GtkBuilder *builder;
GMenuModel *appmenu;
GMenuModel *menubar;
builder = gtk_builder_new ();
gtk_builder_add_from_string (builder, ui_info, -1, NULL);
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder);

View File

@@ -271,7 +271,7 @@ activate_about (GSimpleAction *action,
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
g_string_append_printf (s, "\nA link can appear here: <http://www.gtk.org>");
g_string_append_printf (s, "\nA link can apppear here: <http://www.gtk.org>");
version = g_strdup_printf ("%s\nRunning against GTK %d.%d.%d",
PACKAGE_VERSION,

View File

@@ -2169,7 +2169,7 @@ microphone-sensitivity-medium-symbolic</property>
</child>
<child>
<object class="GtkButton" id="selection_dialog_button">
<property name="label" translatable="yes">S_elect</property>
<property name="label" translatable="yes">_Select</property>
<property name="use-underline">1</property>
</object>
</child>

View File

@@ -30,9 +30,9 @@ gtk/gtkeventcontroller* @carlosg
gtk/gtkgesture*.[ch] @carlosg
# GtkFileChooser
gtk/gtkfilechooser* @federico @ebassi
gtk/gtkfilesystem* @federico @ebassi
gtk/gtkfilefilter* @federico @ebassi
gtk/gtkfilechooser* @federico
gtk/gtkfilesystem* @federico
gtk/gtkfilefilter* @federico
# GtkFontChooser
gtk/gtkfontchooser* @matthiasc
@@ -66,7 +66,3 @@ gtk/themes @lapoc @jimmac
# Inspector
gtk/inspector @otte @matthiasc
# Layout managers
gtk/gtklayout* @ebassi
gtk/gtkconstraint* @ebassi

View File

@@ -3,7 +3,7 @@ GTK Coding Style
This document is intended to be a short description of the preferred
coding style to be used for the GTK source code. It was strongly
inspired by Clutter's `CODING_STYLE`.
inspired by Clutter's CODING_STYLE.
Coding style is a matter of consistency, readability and maintainance;
coding style is also completely arbitrary and a matter of taste. This
@@ -16,24 +16,22 @@ will be clearly identified. Please, don't submit code to GTK that
looks like any of these.
Part of the rationales for these coding style rules are available either
in the kernel CodingStyle document or in Cairo's `CODING_STYLE` one.
in the kernel CodingStyle document or in Cairo's CODING_STYLE one.
When in doubt, check the surrounding code and try to imitate it.
### Line width
+ Line width
The maximum line width for source files is 80 characters, whenever possible.
Longer lines are usually an indication that you either need a function
or a pre-processor macro.
### Indentation
+ Indentation
Each new level is indented 2 or more spaces than the previous level:
```c
if (condition)
single_statement ();
```
This can only be achieved using space characters. It may not be achieved
using tab characters alone, or using a combination of spaces and tabs.
@@ -46,46 +44,39 @@ Even if two spaces for each indentation level allows deeper nesting than
8 spaces, GTK favours self-documenting function names that can take
quite some space. For this reason you should avoid deeply nested code.
### Tab characters
+ Tab characters
The tab character must always be expanded to spaces. If a literal
tab must be used inside the source, the tab must always be interpreted
according to its traditional meaning:
```
Advance to the next column which is a multiple of 8.
[ these two lines should be aligned ]
```
### Braces
+ Braces
Curly braces should not be used for single statement blocks:
```c
if (condition)
single_statement ();
else
another_single_statement (arg1);
```
In case of multiple statements, curly braces should be put on another
indentation level:
```c
if (condition)
{
statement_1 ();
statement_2 ();
statement_3 ();
}
```
The "no block for single statements" rule has only four exceptions:
1. if the single statement covers multiple lines, e.g. for functions with
if the single statement covers multiple lines, e.g. for functions with
many arguments, and it is followed by else or else if:
```c
/* valid */
if (condition)
{
@@ -96,11 +87,9 @@ The "no block for single statements" rule has only four exceptions:
}
else
another_single_statement (arg1, arg2);
```
2. if the condition is composed of many lines:
if the condition is composed of many lines:
```c
/* valid */
if (condition1 ||
(condition2 && condition3) ||
@@ -109,12 +98,10 @@ The "no block for single statements" rule has only four exceptions:
{
a_single_statement ();
}
```
3. Nested if's, in which case the block should be placed on the
Nested if's, in which case the block should be placed on the
outermost if:
```c
/* valid */
if (condition)
{
@@ -130,12 +117,10 @@ The "no block for single statements" rule has only four exceptions:
single_statement ();
else if (yet_another_condition)
another_single_statement ();
```
4. If either side of an if-else statement has braces, both sides
If either side of an if-else statement has braces, both sides
should, to match up indentation:
```c
/* valid */
if (condition)
{
@@ -155,12 +140,10 @@ The "no block for single statements" rule has only four exceptions:
}
else
baz ();
```
In general, new blocks should be placed on a new indentation level,
like:
```c
int retval = 0;
statement_1 ();
@@ -174,12 +157,10 @@ like:
retval = res ? -1 : 1;
}
```
While curly braces for function definitions should rest on a new line
they should not add an indentation level:
```c
/* valid */
static void
my_function (int argument)
@@ -199,23 +180,18 @@ they should not add an indentation level:
{
do_my_things ();
}
```
Curly braces must not be placed on the same line as a condition:
```c
/* invalid */
if (condition) {
statement_1 ();
statement_2 ();
}
```
### Conditions
+ Conditions
Do not check boolean values for equality:
```c
/* invalid */
if (condition == TRUE)
do_foo ();
@@ -223,11 +199,9 @@ Do not check boolean values for equality:
/* valid */
if (another_condition)
do_bar ();
```
Even if C handles NULL equality like a boolean, be explicit:
```c
/* valid */
if (some_pointer == NULL)
do_blah ();
@@ -235,12 +209,10 @@ Even if C handles NULL equality like a boolean, be explicit:
/* invalid */
if (some_other_pointer)
do_blurp ();
```
In case of conditions split over multiple lines, the logical operators should
always go at the end of the line:
```c
/* invalid */
if (condition1
|| condition2
@@ -256,45 +228,37 @@ always go at the end of the line:
{
do_blah ();
}
```
### Functions
+ Functions
Functions should be declared by placing the returned value on a separate
line from the function name:
```c
void
my_function (void)
{
}
```
The arguments list must be broken into a new line for each argument,
with the argument names right aligned, taking into account pointers:
```c
void
my_function (some_type_t type,
another_type_t *a_pointer,
final_type_t another_type)
{
}
```
The alignment also holds when invoking a function without breaking the
80 characters limit:
```c
align_function_arguments (first_argument,
second_argument,
third_argument);
```
To respect the 80 characters limit do not break the function name from
the arguments:
```c
/* invalid */
a_very_long_function_name_with_long_parameters
(argument_the_first, argument_the_second);
@@ -303,13 +267,11 @@ the arguments:
first_a = argument_the_first;
second_a = argument_the_second;
a_very_long_function_name_with_long_parameters (first_a, second_a);
```
### Whitespace
+ Whitespace
Always put a space before a parenthesis but never after:
```c
/* valid */
if (condition)
do_my_things ();
@@ -326,13 +288,11 @@ Always put a space before a parenthesis but never after:
/* invalid */
if ( condition )
do_my_things ( );
```
A `switch()` should open a block on a new indentation level, and each case
A switch() should open a block on a new indentation level, and each case
should start on the same indentation level as the curly braces, with the
case block on a new indentation level:
```c
/* valid */
switch (condition)
{
@@ -370,12 +330,10 @@ case block on a new indentation level:
do_bar ();
break;
}
```
It is preferable, though not mandatory, to separate the various cases with
a newline:
```c
switch (condition)
{
case FOO:
@@ -389,15 +347,13 @@ a newline:
default:
do_default ();
}
```
The `break` statement for the `default:` case is not mandatory.
The 'break' statement for the default: case is not mandatory.
If a case block needs to declare new variables, the same rules as the
inner blocks (see above) apply; the break statement should be placed
outside of the inner block:
```c
switch (condition)
{
case FOO:
@@ -410,12 +366,10 @@ outside of the inner block:
...
}
```
When declaring a structure type use newlines to separate logical sections
of the structure:
```c
struct _GtkWrapBoxPrivate
{
GtkOrientation orientation;
@@ -432,15 +386,13 @@ of the structure:
GList *children;
};
```
Do not eliminate whitespace and newlines just because something would
fit on 80 characters:
```c
/* invalid */
if (condition) foo (); else bar ();
```
Do eliminate trailing whitespace on any line, preferably as a separate
patch or commit. Never use empty lines at the beginning or at the end of
@@ -450,56 +402,45 @@ Do enable the default git pre-commit hook that detect trailing
whitespace for you and help you to avoid corrupting GTK's tree with
it. Do that as follows:
```
chmod a+x .git/hooks/pre-commit
```
You might also find the git-stripspace utility helpful which acts as a
filter to remove trailing whitespace as well as initial, final, and
duplicate blank lines.
### Headers
+ Headers
Headers are special, for GTK, in that they don't have to obey the
80 characters limit. The only major rule for headers is that the function
definitions should be vertically aligned in three columns:
```c
return value function_name (type argument,
type argument,
type argument);
```
The maximum width of each column is given by the longest element in the
column:
```c
void gtk_type_set_property (GtkType *type,
const gchar *value,
GError **error);
const gchar *gtk_type_get_property (GtkType *type);
```
It is also possible to align the columns to the next tab:
```c
void gtk_type_set_prop (GtkType *type,
gfloat value);
gfloat gtk_type_get_prop (GtkType *type);
gint gtk_type_update_foobar (GtkType *type);
```
Public headers should never be included directly:
```c
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
```
Private headers should include the public header first, if one exists:
```c
#ifndef __GTK_FOO_PRIVATE_H__
#define __GTK_FOO_PRIVATE_H__
@@ -508,28 +449,22 @@ Private headers should include the public header first, if one exists:
...
#endif /* __GTK_FOO_PRIVATE_H__ */
```
All headers should have inclusion guards:
```c
#ifndef __GTK_FOO_H__
#define __GTK_FOO_H__
...
#endif /* __GTK_FOO_H__ */
```
You can also use the `once` pragma instead of the classic pre-processor guard:
You can also use the "once" pragma instead of the classic pre-processor guard:
```c
#pragma once
```
Additionally, public headers should use C++ guards around their declarations:
```c
G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
@@ -541,9 +476,8 @@ Additionally, public headers should use C++ guards around their declarations:
...
G_END_DECLS
```
### Includes
+ Includes
GTK source files must never include the global gtk.h header; instead, it
should include the individual headers that are needed.
@@ -552,18 +486,15 @@ Every source file must include config.h first, followed by the header matching
the source file, either the public installed header, or the private header, if
it exists.
```c
#include "config.h"
#include "gtkfoo.h"
```
Source files should then include project headers, in alphabetical order,
starting from headers in the current directory; then headers in
sub-directories; and, finally, in paths relative to the top-level
directory:
```c
#include "config.h"
#include "gtkfooprivate.h"
@@ -574,11 +505,9 @@ directory:
#include "a11y/gtkwidgetaccessible.h"
#include "gdk/gdkwindowprivate.h"
```
Finally, source files should include the system headers last:
```c
#include "config.h"
#include "gtkbarprivate.h"
@@ -592,56 +521,47 @@ Finally, source files should include the system headers last:
#include <graphene.h>
#include <string.h>
```
Cyclic dependencies should be avoided if at all possible; for instance, you
could use additional headers to break cycles.
### GObject
+ GObject
GObject classes definition and implementation require some additional
coding style notices.
Typedef declarations should be placed at the beginning of the file:
```c
typedef struct _GtkFoo GtkFoo;
typedef struct _GtkFooClass GtkFooClass;
```
This includes enumeration types:
```c
typedef enum
{
GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT,
GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH
} GtkSizeRequestMode;
```
And callback types:
```c
typedef void (* GtkCallback) (GtkWidget *widget,
gpointer user_data);
```
Instance structures should only contain the parent type:
```c
struct _GtkFoo
{
GtkWidget parent_instance;
};
```
You should use the `G_DECLARE_DERIVABLE_TYPE()` and `G_DECLARE_FINAL_TYPE()`
You should use the G_DECLARE_DERIVABLE_TYPE() and G_DECLARE_FINAL_TYPE()
macros in newly written headers.
Inside your source file, always use the `G_DEFINE_TYPE()`,
`G_DEFINE_TYPE_WITH_PRIVATE()`, and `G_DEFINE_TYPE_WITH_CODE()` macros, or their
`abstract variants G_DEFINE_ABSTRACT_TYPE()`,
`G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE()`, and `G_DEFINE_ABSTRACT_TYPE_WITH_CODE()`;
Inside your source file, always use the G_DEFINE_TYPE(),
G_DEFINE_TYPE_WITH_PRIVATE(), and G_DEFINE_TYPE_WITH_CODE() macros, or their
abstract variants G_DEFINE_ABSTRACT_TYPE(),
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(), and G_DEFINE_ABSTRACT_TYPE_WITH_CODE();
also, use the similar macros for defining interfaces, quarks, and boxed types.
All the properties should be stored inside the private data structure, which
@@ -652,39 +572,34 @@ installed.
The private data structure should only be accessed internally either using the
pointer inside the instance structure, for legacy code, or the generated
instance private data getter function for your type. You should never use the
`G_TYPE_INSTANCE_GET_PRIVATE()` macro or the `g_type_instance_get_private()`
G_TYPE_INSTANCE_GET_PRIVATE() macro or the g_type_instance_get_private()
function.
Interface types should always have the dummy typedef for cast purposes:
```c
typedef struct _GtkFoo GtkFoo;
```
The interface structure should have "Interface" postfixed to the dummy typedef:
```c
typedef struct _GtkFooInterface GtkFooInterface;
```
Interfaces must have the following macros:
| Macro | Expands to |
|------------------------------|---------------------------------|
| `GTK_TYPE_<iface_name>` | `<iface_name>_get_type` |
| `GTK_<iface_name>` | `G_TYPE_CHECK_INSTANCE_CAST` |
| `GTK_IS_<iface_name>` | `G_TYPE_CHECK_INSTANCE_TYPE` |
| `GTK_<iface_name>_GET_IFACE` | `G_TYPE_INSTANCE_GET_INTERFACE` |
- Macro: - Expands to:
• GTK_TYPE_<iface_name> <iface_name>_get_type
• GTK_<iface_name> G_TYPE_CHECK_INSTANCE_CAST
GTK_IS_<iface_name> G_TYPE_CHECK_INSTANCE_TYPE
• GTK_<iface_name>_GET_IFACE G_TYPE_INSTANCE_GET_INTERFACE
### Memory allocation
+ Memory allocation
When dynamically allocating data on the heap either use `g_new()` or,
if allocating multiple small data structures, `g_slice_new()`.
When dynamically allocating data on the heap either use g_new() or,
if allocating multiple small data structures, g_slice_new().
Public structure types should always be returned after being zero-ed,
either explicitly for each member, or by using `g_new0()` or `g_slice_new0()`.
either explicitly for each member, or by using g_new0() or g_slice_new0().
### Macros
+ Macros
Try to avoid private macros unless strictly necessary. Remember to #undef
them at the end of a block or a series of functions needing them.
@@ -693,9 +608,9 @@ Inline functions are usually preferable to private macros.
Public macros should not be used unless they evaluate to a constant.
### Symbol visibility
+ Symbol visibility
Any symbol that is not explicitly annotated using a `GDK_AVAILABLE_IN_*`
Any symbol that is not explicitly annotated using a GDK_AVAILABLE_IN_*
macro is considered internal, and not exported in the shared library.
Never export variables as public API, since this is cumbersome on some
@@ -707,12 +622,11 @@ should be declared in a private header file.
Non-exported functions that are only needed in one source file
should be declared static.
### Documentation
+ Documentation
All public APIs must have gtk-doc comments. For functions, these should
be placed in the source file, directly above the function.
```c
/* valid */
/**
* gtk_get_flow:
@@ -731,7 +645,6 @@ be placed in the source file, directly above the function.
...
}
```
Doc comments for macros, function types, class structs, etc should be
placed next to the definitions, typically in headers.
@@ -739,7 +652,6 @@ placed next to the definitions, typically in headers.
Section introductions should be placed in the source file they describe,
after the license header:
```c
/* valid */
/**
* SECTION:gtksizerequest
@@ -750,19 +662,15 @@ after the license header:
* width-for-height) geometry management system.
* ...
*/
```
To properly document a new function, macro, function type or struct,
it needs to be listed in the `sections.txt` file.
it needs to be listed in the gtk3-sections.txt file.
To properly document a new class, it needs to be given its own section
in the sections.txt, needs to be included in the `docs.xml` file, and the
`get_type` function needs to listed in the `.types` file.
in gtk3-sections.txt, needs to be included in gtk-docs.sgml, and the
get_type function needs to listed in gtk3.types.
For more information on the documentation style and contribution guidelines,
please [follow the corresponding contribution guide](./reference/README.md).
### Old code
+ Old code
New code that is being added to GTK should adhere to the style
explained above. Existing GTK code does largely follow these

View File

@@ -118,3 +118,9 @@ $ ssh matthiasc@master.gnome.org ftpadmin install gtk-4.2.0.tar.xz
create a new message in the same form, replacing version numbers,
commentary at the top about "what this release is about" and the
summary of changes.
17. Send it to gnome-announce-list, gtk-list, gtk-app-devel-list and
gtk-devel-list. Set reply-to to desktop-devel-list.
18. Add a link to the release announcement to www.gtk.org which lives
in the gtk-web git module.

View File

@@ -1,211 +0,0 @@
# How to contribute to GTK's documentation
The GTK documentation is divided in two major components:
- the API reference, which is generated from special comments in the GTK
source code
- static pages that provide an overview of specific sections of the API
In both cases, the contents are parsed, converted into DocBook format, and
cross-linked in order to match types, functions, signals, and properties.
From the DocBook output, we generate HTML, which can be used to read the
documentation both offline and online.
In both cases, contributing to the GTK documentation requires modifying
files tracked in the source control repository, and follows the same steps
as any other code contribution as outlined in the GTK [contribution
guide][contributing]. Please, refer to that document for any further
question on the mechanics of contributing to GTK.
GTK uses [gtk-doc][gtkdoc] to generate its documentation. Please, visit the
gtk-doc website to read the project's documentation.
[contributing]: ../../CONTRIBUTING.md
[gtkdoc]: https://wiki.gnome.org/DocumentationProject/GtkDoc
## Contributing to the API reference
Whenever you need to add or modify the documentation of a type or a
function, you will need to edit a `gtk-doc` comment stanza, typically right
above the type or function declaration. For instance:
```c
/**
* gtk_foo_set_bar:
* @self: a #GtkFoo
* @bar: a #GtkBar
*
* Sets the given #GtkBar instance on a #GtkFoo widget.
*/
void
gtk_foo_set_bar (GtkFoo *self,
GtkBar *bar)
{
...
```
Or, for types:
```c
/**
* GtkFoo:
*
* A foo widget instance.
*
* The contents of this structure are private and should never
* be accessed directly.
*/
struct _GtkFoo
{
GtkWidget parent_instance;
};
```
Each public function and type in the GTK API reference must be listed in the
`sections.txt` file for the specific namespace to which it belongs: GDK,
GSK, or GTK. For instance, if you add a function named `gtk_foo_set_bar()`,
you will need to:
1. open `docs/reference/gtk/gtk4-sections.txt`
1. find the section that lists the symbols of the `GtkFoo` type
1. add `gtk_foo_set_bar` to the list
New classes require:
1. a new section in the `sections.txt` file
1. the `get_type` function added to the `.types` file
1. an `xinclude` element in the `docs.xml` file
The GTK documentation also contains a number of 'freestanding' chapters
for which the source is in .md files in docs/reference/gtk.
## Style guide
Like the [coding style][coding], these rules try to formalize the existing
documentation style; in general, you should only ever modify existing code
that does not match the rules if you're already changing that code for
unrelated reasons.
[coding]: ../CODING-STYLE.md
### Syntax
The input syntax for GTK documentation is markdown, in a flavor that is
similar to what you see on gitlab or github. The markdown support for
fragments that are extracted from sources is more limited than for
freestanding chapters. As an exception, man pages for tools are currently
maintained in docbook, since the conversion from markdown to docbook is
losing too much of the expected formatting.
In addition to typical markdown formatting such as \*emphasis\* or \_italics\_,
gtk-doc supports a few abbreviations for cross-references and formatting:
`#ClassName`
: Creates a link to the docs for a class
`function()`
: Creates a link to the docs for a function
`%constant`
: Generates suitable markup for enum values or constants
### Sections
- The "section" of each type must contain a name, to be referenced in the
`sections.txt` file; a title; and a short description. For instance:
```c
/**
* SECTION:gtkshortcut
* @Title: GtkShortcut
* @Short_desc: A key shortcut
*
* ...
```
For classes, the title should be the name of the class. While it's
possible to add section titles directly to the `sections.txt` file, this
is considered deprecated, and should not be done for newly written code.
- For classes, the long description should contain an overview of the type;
what it does; typical use cases; and idiomatic examples of its use.
- For widget classes, the long description of a section should also contain:
- special XML elements and attributes parsed by the class, in case of a
custom GtkBuildable implementation
- the CSS element name to be used by selectors
- the CSS selector hierarchy for children, in case of a composite widget
### Functions
- The argument names must match in the declaration, definition, and
documentation stanza.
- The description should refer to the function as the subject, e.g.:
```
Adds a shortcut to the shortcuts controller.
```
Or:
```
Checks whether the widget is set to be visible or not.
```
### Methods
- Methods are special functions whose first argument is always the instance
of a certain class. The instance argument for newly written code should be
called `self`.
- If a method is a setter or a getter for an object property, link the
property in the methods's description.
- If a method changes one or more properties as side effect, link those
properties in the method's description
- If a method is a signal emitter, link the signal in the method's
description.
### Signals
- While GObject can introspect argument and return types for signals,
you should *always* document them with an explicit gtk-doc stanza.
- The syntax for signal stanzas is similar to functions:
```c
/**
* GtkFoo::signal-name:
* @arg1: ...
* @arg2: ...
*
* ...
```
### Properties
- While GObject properties contain text that can be extracted
programmatically in order to build their documentation, you should
*always* document them with an explicit gtk-doc stanza. The text
associated to the property is short and meant to be used when
programmatically building user interfaces, and not for documentation
purposes.
- Always note if setting a property has side effects, like causing another
property to change state.
- The syntax for property documentation is:
```c
/**
* GtkFoo:property-name:
*
* ...
```
### Actions
- Actions are new in GTK 4, and gtk-doc had to learn a new syntax
to document them:
```
/**c
* GtkFoo|action-name:
* @arg1: ...
* @arg2: ...
*
* ...
```

View File

@@ -79,6 +79,10 @@ gdk_display_sync
gdk_display_flush
gdk_display_close
gdk_display_is_closed
gdk_display_get_event
gdk_display_peek_event
gdk_display_put_event
gdk_display_has_pending
gdk_display_is_rgba
gdk_display_is_composited
gdk_display_get_default_group
@@ -93,14 +97,11 @@ gdk_display_get_clipboard
gdk_display_get_primary_clipboard
gdk_display_get_setting
gdk_display_get_startup_notification_id
<SUBSECTION>
gdk_display_put_event
gdk_display_setup_window_visual
<SUBSECTION>
gdk_display_map_keyval
gdk_display_map_keycode
gdk_display_translate_key
<SUBSECTION Standard>
GDK_DISPLAY
@@ -173,6 +174,7 @@ gdk_rgba_get_type
GdkSurface
GdkGravity
GdkSurfaceEdge
GdkSurfaceTypeHint
GdkSurfaceState
gdk_surface_new_toplevel
gdk_surface_new_popup
@@ -382,6 +384,8 @@ gdk_device_has_bidi_layouts
<SUBSECTION>
gdk_device_get_state
gdk_device_get_surface_at_position
gdk_device_get_history
gdk_device_free_history
GdkTimeCoord
gdk_device_get_axis
gdk_device_get_axis_names
@@ -466,6 +470,7 @@ gdk_seat_capabilities_get_type
<FILE>events</FILE>
GdkEvent
GdkEventType
GdkEventMask
GdkKeyMatch
GdkTouchpadGesturePhase
GdkScrollDirection
@@ -499,7 +504,6 @@ gdk_event_get_position
gdk_event_get_axes
gdk_event_get_axis
gdk_event_get_pointer_emulated
gdk_event_triggers_context_menu
gdk_button_event_get_button
gdk_scroll_event_get_direction
gdk_scroll_event_get_deltas
@@ -518,7 +522,6 @@ gdk_crossing_event_get_mode
gdk_crossing_event_get_detail
gdk_crossing_event_get_focus
gdk_grab_broken_event_get_grab_surface
gdk_grab_broken_event_get_implicit
gdk_dnd_event_get_drop
gdk_configure_event_get_size
gdk_touchpad_event_get_gesture_phase
@@ -544,23 +547,8 @@ GDK_TYPE_CROSSING_MODE
GDK_TYPE_SCROLL_DIRECTION
GDK_TYPE_NOTIFY_TYPE
GDK_IS_EVENT
gdk_event_get_type
gdk_event_sequence_get_type
gdk_button_event_get_type
gdk_configure_event_get_type
gdk_crossing_event_get_type
gdk_delete_event_get_type
gdk_dnd_event_get_type
gdk_focus_event_get_type
gdk_grab_broken_event_get_type
gdk_key_event_get_type
gdk_motion_event_get_type
gdk_pad_event_get_type
gdk_proximity_event_get_type
gdk_scroll_event_get_type
gdk_touch_event_get_type
gdk_touchpad_event_get_type
</SECTION>
<SECTION>

View File

@@ -27,19 +27,15 @@ private_headers = [
'gdkmonitorprivate.h',
'gdkmemorytextureprivate.h',
'gdkpipeiostreamprivate.h',
'gdkpopupprivate.h',
'gdkprofilerprivate.h',
'gdkscreenprivate.h',
'gdkseatdefaultprivate.h',
'gdkseatprivate.h',
'gdksnapshotprivate.h',
'gdksurfaceimpl.h',
'gdksurfaceprivate.h',
'gdktextureprivate.h',
'gdktoplevelprivate.h',
'gdkvulkancontextprivate.h',
'keyname-table.h',
'x11/gdkprivate-x11.h',
'gdkprivate-x11.h',
'x11/gdkeventsource.h',
'gtk-primary-selection-client-protocol.h',
'gtk-shell-client-protocol.h',

View File

@@ -236,6 +236,7 @@ gsk_transform_to_translate
gsk_transform_transform
gsk_transform_invert
gsk_transform_matrix
gsk_transform_matrix_with_category
gsk_transform_translate
gsk_transform_translate_3d
gsk_transform_rotate

View File

@@ -9,11 +9,9 @@ private_headers = [
'gskprofilerprivate.h',
'gskrendererprivate.h',
'gskrendernodeprivate.h',
'gskrendernodeparserprivate.h',
'gskroundedrectprivate.h',
'gskshaderbuilderprivate.h',
'gsktextureprivate.h',
'gsktransformprivate.h',
'gskvulkanblendpipelineprivate.h',
'gskvulkanborderpipelineprivate.h',
'gskvulkanboxshadowpipelineprivate.h',

View File

@@ -1,222 +0,0 @@
# Overview of actions in GTK {#actions-overview}
This chapter describes in detail how GTK uses actions to connect
activatable UI elements to callbacks. GTK inherits the underlying
architecture of GAction and GMe:u for describing abstract actions
and menus from the GIO library.
## Basics about actions
A GAction is essentially a way to tell the toolkit about a piece of
functionality in your program, and to give it a name.
Actions are purely functional. They do not contain any presentational
information.
An action has four pieces of information associated with it:
- a name as an identifier (usually all-lowercase, untranslated
English string)
- an enabled flag indicating if the action can be activated or not
(like the "sensitive" property on widgets)
- an optional state value, for stateful actions (like a boolean for
toggles)
- an optional parameter type, used when activating the action
An action supports two operations. You can activate it, which requires
passing a parameter of the correct type And you can request to change
the actions state (for stateful actions) to a new state value of the
correct type.
Here are some rules about an action:
- the name is immutable (in the sense that it will never change) and
it is never %NULL
- the enabled flag can change
- the parameter type is immutable
- the parameter type is optional: it can be %NULL
- if the parameter type is %NULL then action activation must be done
without a parameter (ie: a %NULL GVariant pointer)
- if the parameter type is non-%NULL then the parameter must have this
type
- the state can change, but it cannot change type
- if the action was stateful when it was created, it will always have a
state and it will always have exactly the same type (such as boolean
or string)
- if the action was stateless when it was created, it can never have a
state
- you can only request state changes on stateful actions and it is only
possible to request that the state change to a value of the same type
as the existing state
An action does not have any sort of presentational information such as
a label, an icon or a way of creating a widget from it.
## Action state and parameters
Most actions in your application will be stateless actions with no
parameters. These typically appear as menu items with no special
decoration. An example is "quit".
Stateful actions are used to represent an action which has a
closely-associated state of some kind. A good example is a "fullscreen"
action. For this case, you would expect to see a checkmark next to the
menu item when the fullscreen option is active. This is usually called
a toggle action, and it has a boolean state. By convention, toggle actions
have no parameter type for activation: activating the action always toggles
the state.
Another common case is to have an action representing a enumeration of
possible values of a given type (typically string). This is often called
a radio action and is usually represented in the user interface with radio
buttons or radio menu items, or sometimes a combobox. A good example is
"text-justify" with possible values "left", "center", and "right". By
convention, these types of actions have a parameter type equal to their
state type, and activating them with a particular parameter value is
equivalent to changing their state to that value.
This approach to handling radio buttons is different than many other
action systems such as GtkAction. With GAction, there is only one action
for "text-justify" and "left", "center" and "right" are possible states on
that action. There are not three separate "justify-left", "justify-center"
and "justify-right" actions.
The final common type of action is a stateless action with a parameter.
This is typically used for actions like "open-bookmark" where the parameter
to the action would be the identifier of the bookmark to open.
Because some types of actions cannot be invoked without a parameter, it is
often important to specify a parameter when referring to the action from
a place where it will be invoked (such as from a radio button that sets
the state to a particular value or from a menu item that opens a specific
bookmark). In these contexts, the value used for the action parameter is
typically called the target of the action.
Even though toggle actions have a state, they do not have a parameter.
Therefore, a target value is not needed when referring to them — they
will always be toggled on activation.
Most APIs that allow using a GAction (such as GMenuModel and GtkActionable)
allow use of detailed action names. This is a convenient way of specifying
an action name and an action target with a single string.
In the case that the action target is a string with no unusual characters
(ie: only alpha-numeric, plus '-' and '.') then you can use a detailed
action name of the form "justify::left" to specify the justify action with
a target of left.
In the case that the action target is not a string, or contains unusual
characters, you can use the more general format "action-name(5)", where the
"5" here is any valid text-format GVariant (ie: a string that can be parsed
by g_variant_parse()). Another example is "open-bookmark('http://gnome.org/')".
You can convert between detailed action names and split-out action names
and target values using g_action_parse_detailed_name() and
g_action_print_detailed_name() but usually you will not need to. Most APIs
will provide both ways of specifying actions with targets.
## Action scopes
Actions are always scoped to a particular object on which they operate.
In GTK, actions are typically scoped to either an application or a window,
but any widget can have actions associated with it.
Actions scoped to windows should be the actions that specifically impact
that window. These are actions like "fullscreen" and "close", or in the
case that a window contains a document, "save" and "print".
Actions that impact the application as a whole rather than one specific
window are scoped to the application. These are actions like "about" and
"preferences".
If a particular action is scoped to a window then it is scoped to a
specific window. Another way of saying this: if your application has a
"fullscreen" action that applies to windows and it has three windows,
then it will have three fullscreen actions: one for each window.
Having a separate action per-window allows for each window to have a
separate state for each instance of the action as well as being able to
control the enabled state of the action on a per-window basis.
Actions are added to their relevant scope (application, window or widget)
either using the GActionMap interface, or by using
gtk_widget_insert_action_group(). Actions that will be the same for all
instances of a widget class can be added globally using
gtk_widget_class_install_action().
## Action groups and action maps
Actions rarely occurs in isolation. It is common to have groups
of related actions, which are represented by instances of the
GActionGroup interface.
Action maps are a variant of action groups that allow to change
the name of the action as it is looked up. In GTK, the convention
is to add a prefix to the action name to indicate the scope of
the actions, such as "app." for the actions with application scope
or "win." for those with window scope.
When referring to actions on a GActionMap only the name of the
action itself is used (ie: "quit", not "app.quit"). The
"app.quit" form is only used when referring to actions from
places like a GMenu or GtkActionable widget where the scope
of the action is not already known.
GtkApplication and GtkApplicationWindow implement the GActionMap
interface, so you can just add actions directly to them. For
other widgets, use gtk_widget_insert_action_group() to add
actions to it.
If you want to insert several actions at the same time, it is
typically faster and easier to use GActionEntry.
## Connecting actions to widgets
Any widget that implements the GtkActionable interface can
be connected to an action just by setting the ::action-name
property. If the action has a parameter, you will also need
to set the ::action-target property.
Widgets that implement GtkActionable include GtkSwitch, GtkButton,
and their respective subclasses.
Another way of obtaining widgets that are connected to actions
is to create a menu using a GMenu menu model. GMenu provides an
abstract way to describe typical menus: nested groups of items
where each item can have a label, and icon, and an action.
Typical uses of GMenu inside GTK are to set up an application
menu or menubar with gtk_application_set_app_menu() or
gtk_application_set_menubar(). Another, maybe more common use
is to create a popover for a menubutton, using
gtk_menu_button_set_menu_model().
Unlike traditional menus, those created from menu models don't
have keyboard accelerators associated with menu items. Instead,
GtkApplication offers the gtk_application_set_accels_for_action()
API to associate keyboard shortcuts with actions.
## Activation
When a widget with a connected action is activated, GTK finds
the action to activate by walking up the widget hierarchy,
looking for a matching action, ending up at the GtkApplication.
## Built-in Actions
GTK uses actions for its own purposes in a number places. These
built-in actions can sometimes be activated by applications, and
you should avoid naming conflicts with them when creating your
own actions.
default.activate
: Activates the default widget in a context (typically a GtkWindow,
GtkDialog or GtkPopover)
clipboard.cut, clipboard.copy, clipboard.paste
: Clipboard operations on entries, text view and labels, typically
used in the context menu
selection.delete, selection.select-all
: Selection operations on entries, text view and labels
color.select, color.customize:
: Operate on colors in a #GtkColorChooserWidget. These actions are
unusual in that they have the non-trivial parameter type (dddd):

View File

@@ -0,0 +1,394 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="chap-actions">
<refmeta>
<refentrytitle>The GTK Action Model</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>The GTK Action Model</refname>
<refpurpose>
How actions are used in GTK
</refpurpose>
</refnamediv>
<refsect1 id="actions-overview">
<title>Overview of actions in GTK</title>
<para>
This chapter describes in detail how GTK uses actions to connect
activatable UI elements to callbacks. GTK inherits the underlying
architecture of GAction and GMenu for describing abstract actions
and menus from the GIO library.
</para>
<refsect2>
<title>Basics about actions</title>
<para>
A GAction is essentially a way to tell the toolkit about a
piece of functionality in your program, and to give it a name.
</para>
<para>
Actions are purely functional. They do not contain any
presentational information.
</para>
<para>
An action has four pieces of information associated with it:
<itemizedlist>
<listitem><para>
a name as an identifier (usually all-lowercase, untranslated
English string)
</para></listitem>
<listitem><para>
an enabled flag indicating if the action can be activated or
not (like the "sensitive" property on widgets)
</para></listitem>
<listitem><para>
an optional state value, for stateful actions (like a boolean
for toggles)
</para></listitem>
<listitem><para>
an optional parameter type, used when activating the action
</para></listitem>
</itemizedlist>
</para>
<para>
An action supports two operations. You can activate it, which
requires passing a parameter of the correct type
And you can request to change the actions state (for stateful
actions) to a new state value of the correct type.
</para>
<para>
Here are some rules about an action:
<itemizedlist>
<listitem><para>
the name is immutable (in the sense that it will never
change) and it is never %NULL
</para></listitem>
<listitem><para>
the enabled flag can change
</para></listitem>
<listitem><para>
the parameter type is immutable
</para></listitem>
<listitem><para>
the parameter type is optional: it can be %NULL
</para></listitem>
<listitem><para>
if the parameter type is %NULL then action activation must
be done without a parameter (ie: a %NULL GVariant pointer)
</para></listitem>
<listitem><para>
if the parameter type is non-%NULL then the parameter must
have this type
</para></listitem>
<listitem><para>
the state can change, but it cannot change type
</para></listitem>
<listitem><para>
if the action was stateful when it was created, it will
always have a state and it will always have exactly the same
type (such as boolean or string)
</para></listitem>
<listitem><para>
if the action was stateless when it was created, it can never
have a state
</para></listitem>
<listitem><para>
you can only request state changes on stateful actions and it
is only possible to request that the state change to a value
of the same type as the existing state
</para></listitem>
</itemizedlist>
</para>
<para>
An action does not have any sort of presentational information
such as a label, an icon or a way of creating a widget from it.
</para>
</refsect2>
<refsect2>
<title>Action state and parameters</title>
<para>
Most actions in your application will be stateless actions with
no parameters. These typically appear as menu items with no
special decoration. An example is "quit".
</para>
<para>
Stateful actions are used to represent an action which has a
closely-associated state of some kind. A good example is a
"fullscreen" action. For this case, you'd expect to see a
checkmark next to the menu item when the fullscreen option
is active. This is usually called a toggle action, and it has
a boolean state. By convention, toggle actions have no parameter
type for activation: activating the action always toggles the
state.
</para>
<para>
Another common case is to have an action representing a
enumeration of possible values of a given type (typically
string). This is often called a radio action and is usually
represented in the user interface with radio buttons or radio
menu items, or sometimes a combobox. A good example is
"text-justify" with possible values "left", "center", and
"right". By convention, these types of actions have a parameter
type equal to their state type, and activating them with a
particular parameter value is equivalent to changing their
state to that value.
</para>
<para>
This approach to handling radio buttons is different than many
other action systems such as GtkAction. With GAction, there is
only one action for "text-justify" and "left", "center" and
"right" are possible states on that action. There are not three
separate "justify-left", "justify-center" and "justify-right"
actions.
</para>
<para>
The final common type of action is a stateless action with a
parameter. This is typically used for actions like
"open-bookmark" where the parameter to the action would be
the identifier of the bookmark to open.
</para>
<para>
Because some types of actions cannot be invoked without a
parameter, it is often important to specify a parameter when
referring to the action from a place where it will be invoked
(such as from a radio button that sets the state to a particular
value or from a menu item that opens a specific bookmark). In
these contexts, the value used for the action parameter is
typically called the target of the action.
</para>
<para>
Even though toggle actions have a state, they do not have a
parameter. Therefore, a target value is not needed when
referring to them — they will always be toggled on activation.
</para>
<para>
Most APIs that allow using a GAction (such as GMenuModel and
GtkActionable) allow use of detailed action names. This is a
convenient way of specifying an action name and an action target
with a single string.
</para>
<para>
In the case that the action target is a string with no unusual
characters (ie: only alpha-numeric, plus '-' and '.') then you
can use a detailed action name of the form "justify::left" to
specify the justify action with a target of left.
</para>
<para>
In the case that the action target is not a string, or contains
unusual characters, you can use the more general format
"action-name(5)", where the "5" here is any valid text-format
GVariant (ie: a string that can be parsed by g_variant_parse()).
Another example is "open-bookmark('http://gnome.org/')".
</para>
<para>
You can convert between detailed action names and split-out
action names and target values using g_action_parse_detailed_name()
and g_action_print_detailed_name() but usually you will
not need to. Most APIs will provide both ways of specifying
actions with targets.
</para>
</refsect2>
<refsect2>
<title>Action scopes</title>
<para>
Actions are always scoped to a particular object on which they
operate.
</para>
<para>
In GTK, actions are typically scoped to either an application
or a window, but any widget can have actions associated with it.
</para>
<para>
Actions scoped to windows should be the actions that
specifically impact that window. These are actions like
"fullscreen" and "close", or in the case that a window contains
a document, "save" and "print".
</para>
<para>
Actions that impact the application as a whole rather than one
specific window are scoped to the application. These are actions
like "about" and "preferences".
</para>
<para>
If a particular action is scoped to a window then it is scoped
to a specific window. Another way of saying this: if your
application has a "fullscreen" action that applies to windows
and it has three windows, then it will have three fullscreen
actions: one for each window.
</para>
<para>
Having a separate action per-window allows for each window to
have a separate state for each instance of the action as well
as being able to control the enabled state of the action on a
per-window basis.
</para>
<para>
Actions are added to their relevant scope (application,
window or widget) either using the GActionMap interface,
or by using gtk_widget_insert_action_group(). Actions that
will be the same for all instances of a widget class can
be added globally using gtk_widget_class_install_action().
</para>
</refsect2>
<refsect2>
<title>Action groups and action maps</title>
<para>
Actions rarely occurs in isolation. It is common to have groups
of related actions, which are represented by instances of the
GActionGroup interface.
</para>
<para>
Action maps are a variant of action groups that allow to change
the name of the action as it is looked up. In GTK, the convention
is to add a prefix to the action name to indicate the scope of
the actions, such as "app." for the actions with application scope
or "win." for those with window scope.
</para>
<para>
When referring to actions on a GActionMap only the name of the
action itself is used (ie: "quit", not "app.quit"). The
"app.quit" form is only used when referring to actions from
places like a GMenu or GtkActionable widget where the scope
of the action is not already known.
</para>
<para>
GtkApplication and GtkApplicationWindow implement the GActionMap
interface, so you can just add actions directly to them. For
other widgets, use gtk_widget_insert_action_group() to add
actions to it.
</para>
<para>
If you want to insert several actions at the same time, it is
typically faster and easier to use GActionEntry.
</para>
</refsect2>
<refsect2>
<title>Connecting actions to widgets</title>
<para>
Any widget that implements the GtkActionable interface can
be connected to an action just by setting the ::action-name
property. If the action has a parameter, you will also need
to set the ::action-target property.
Widgets that implement GtkActionable include GtkSwitch, GtkButton,
and their respective subclasses.
</para>
<para>
Another way of obtaining widgets that are connected to actions
is to create a menu using a GMenu menu model. GMenu provides an
abstract way to describe typical menus: nested groups of items
where each item can have a label, and icon, and an action.
</para>
<para>
Typical uses of GMenu inside GTK are to set up an application
menu or menubar with gtk_application_set_app_menu() or
gtk_application_set_menubar(). Another, maybe more common use
is to create a popover for a menubutton, using
gtk_menu_button_set_menu_model().
</para>
<para>
Unlike traditional menus, those created from menu models don't
have keyboard accelerators associated with menu items. Instead,
GtkApplication offers the gtk_application_set_accels_for_action()
API to associate keyboard shortcuts with actions.
</para>
</refsect2>
<refsect2>
<title>Activation</title>
<para>
When a widget with a connected action is activated, GTK finds
the action to activate by walking up the widget hierarchy,
looking for a matching action, ending up at the GtkApplication.
</para>
</refsect2>
<refsect2>
<title>Built-in Actions</title>
<para>
GTK uses actions for its own purposes in a number places. These
built-in actions can sometimes be activated by applications, and
you should avoid naming conflicts with them when creating your
own actions.
<variablelist>
<varlistentry>
<term>default.activate</term>
<listitem><para>Activates the default widget in a context
(typically a GtkWindow, GtkDialog or GtkPopover)
</para></listitem>
</varlistentry>
<varlistentry>
<term>clipboard.cut, clipboard.copy, clipboard.paste</term>
<listitem><para>Clipboard operations on entries, text view
and labels, typically used in the context menu
</para></listitem>
</varlistentry>
<varlistentry>
<term>selection.delete, selection.select-all</term>
<listitem><para>Selection operations on entries, text view
and labels
</para></listitem>
</varlistentry>
<varlistentry>
<term>color.select, color.customize</term>
<listitem><para>Operations on colors in GtkColorChooserWidget.
These actions are unusual in that they have the non-trivial
parameter type (dddd).
</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
</refsect1>
</refentry>

View File

@@ -1,36 +0,0 @@
# Using GTK with Broadway {#gtk-broadway}
The GDK Broadway backend provides support for displaying GTK
applications in a web browser, using HTML5 and web sockets. To run
your application in this way, select the Broadway backend by setting
`GDK_BACKEND=broadway`. Then you can make your application appear in
a web browser by pointing it at `http://127.0.0.1:8080`. Note that
you need to enable web sockets in your web browser.
You can choose a different port from the default 8080 by setting
the `BROADWAY_DISPLAY` environment variable to the port that you
want to use.
It is also possible to use multiple GTK applications in the same
web browser window, by using the Broadway server, `broadwayd`, that
ships with GTK. To use broadwayd, start it like this:
```
broadwayd :5
```
Then point your web browser at `http://127.0.0.1:8085`.
Start your applications like this:
```
GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 gtk4-demo
```
## Broadway-specific environment variables {#broadway-envar}
### BROADWAY_DISPLAY
Specifies the Broadway display number. The default display is 0.
The display number determines the port to use when connecting
to a Broadway application via the following formula:
`port = 8080 + display`

View File

@@ -0,0 +1,71 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="gtk-broadway">
<refmeta>
<refentrytitle>Using GTK with Broadway</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Using GTK with Broadway</refname>
<refpurpose>
HTML-specific aspects of using GTK
</refpurpose>
</refnamediv>
<refsect1>
<title>Using GTK with Broadway</title>
<para>
The GDK Broadway backend provides support for displaying GTK
applications in a web browser, using HTML5 and web sockets. To run
your application in this way, select the Broadway backend by setting
<literal>GDK_BACKEND=broadway</literal>. Then you can make
your application appear in a web browser by pointing it at
<literal>http://127.0.0.1:8080</literal>. Note that you need
to enable web sockets in your web browser.
</para>
<para>
You can choose a different port from the default 8080 by setting
the <envar>BROADWAY_DISPLAY</envar> environment variable to the
port that you want to use.
</para>
<para>
It is also possible to use multiple GTK applications in the same
web browser window, by using the Broadway server,
<command>broadwayd</command>, that ships with GTK.
To use broadwayd, start it like this:
<programlisting>
broadwayd :5
</programlisting>
Then point your web browser at <literal>http://127.0.0.1:8085</literal>.
Start your applications like this:
<programlisting>
GDK_BACKEND=broadway BROADWAY_DISPLAY=:5 gtk4-demo
</programlisting>
</para>
<refsect2 id="broadway-envar">
<title>Broadway-specific environment variables</title>
</refsect2>
<formalpara>
<title><envar>BROADWAY_DISPLAY</envar></title>
<para>
Specifies the Broadway display number. The default display is 0.
The display number determines the port to use when connecting
to a Broadway application via the following formula:
<programlisting>
<replaceable>port</replaceable> = 8080 + <replaceable>display</replaceable>
</programlisting>
</para>
</formalpara>
</refsect1>
</refentry>

View File

@@ -1,270 +0,0 @@
# Compiling the GTK Libraries {#gtk-building}
## Building GTK
Before we get into the details of how to compile GTK, we should
mention that in many cases, binary packages of GTK prebuilt for
your operating system will be available, either from your
operating system vendor or from independent sources. If such a
set of packages is available, installing it will get you
programming with GTK much faster than building it yourself. In
fact, you may well already have GTK installed on your system already.
In order to build GTK, you will need *meson* installed on your
system. On Linux, and other UNIX-like operating systems, you will
also need *ninja*. This guide does not cover how to install these
two requirements, but you can refer to the
[Meson website](http://mesonbuild.com) for more information. The
[Ninja](https://ninja-build.org) build tool is also usable on
various operating systems, so we will refer to it in the examples.
If you are building GTK from a source distribution or from a Git
clone, you will need to use *meson* to configure the project. The
most commonly useful argument is the `--prefix` one, which determines
where the files will go once installed. To install GTK under a prefix
like `/opt/gtk` you would run Meson as:
```
meson setup --prefix /opt/gtk builddir
```
Meson will create the `builddir` directory and place all the build
artefacts there.
You can get a list of all available options for the build by
running `meson configure`.
After Meson successfully configured the build directory, you then
can run the build, using Ninja:
```
cd builddir
ninja
ninja install
```
If you don't have permission to write to the directory you are
installing in, you may have to change to root temporarily before
running `ninja install`.
Several environment variables are useful to pass to set before
running *meson*. `CPPFLAGS` contains options to pass to the C
compiler, and is used to tell the compiler where to look for
include files. The `LDFLAGS` variable is used in a similar fashion
for the linker. Finally the `PKG_CONFIG_PATH` environment variable
contains a search path that `pkg-config` (see below) uses when
looking for files describing how to compile programs using different
libraries. If you were installing GTK and it's dependencies into
`/opt/gtk`, you might want to set these variables as:
```
CPPFLAGS="-I/opt/gtk/include"
LDFLAGS="-L/opt/gtk/lib"
PKG_CONFIG_PATH="/opt/gtk/lib/pkgconfig"
export CPPFLAGS LDFLAGS PKG_CONFIG_PATH
```
You may also need to set the `LD_LIBRARY_PATH` environment variable
so the systems dynamic linker can find the newly installed libraries,
and the `PATH` environment program so that utility binaries installed
by the various libraries will be found.
```
LD_LIBRARY_PATH="/opt/gtk/lib"
PATH="/opt/gtk/bin:$PATH"
export LD_LIBRARY_PATH PATH
```
## Build types {#build-types}
Meson has different build types, exposed by the `buildtype`
configuration option. GTK enables and disables functionality
depending on the build type used when calling *meson* to
configure the build.
### Debug builds
GTK will enable debugging code paths in both the `debug` and
`debugoptimized` build types. Builds with `buildtype` set to
`debug` will additionally enable consistency checks on the
internal state of the toolkit.
It is recommended to use the `debug` or `debugoptimized` build
types when developing GTK itself. Additionally, `debug` builds of
GTK are recommended for profiling and debugging GTK applications,
as they include additional validation of the internal state.
The `debugoptimized` build type is the default for GTK if no build
type is specified when calling *meson*.
### Release builds
The `release` build type will disable debugging code paths and
additional run time safeties, like checked casts for object
instances.
The `plain` build type provided by Meson should only be used when
packaging GTK, and it's expected that packagers will provide their
own compiler flags when building GTK. See the previous section for
the list of environment variables to be used to define compiler and
linker flags.
## Dependencies {#dependencies}
Before you can compile the GTK widget toolkit, you need to have
various other tools and libraries installed on your
system. Dependencies of GTK have their own build systems, so
you will need to refer to their own installation instructions.
A particular important tool used by GTK to find its dependencies
is `pkg-config`.
[pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/)
is a tool for tracking the compilation flags needed for libraries
that are used by the GTK libraries. (For each library, a small `.pc`
text file is installed in a standard location that contains the
compilation flags needed for that library along with version number
information.)
Some of the libraries that GTK depends on are maintained by the
GTK team: GLib, GdkPixbuf, Pango, ATK and GObject Introspection.
Other libraries are maintained separately.
- The GLib library provides core non-graphical functionality
such as high level data types, Unicode manipulation, and
an object and type system to C programs. It is available
from [here](https://download.gnome.org/sources/glib/).
- The [GdkPixbuf](https://git.gnome.org/browse/gdk-pixbuf/)
library provides facilities for loading images in a variety of
file formats. It is available [here](ttps://download.gnome.org/sources/gdk-pixbuf/).
- [Pango](http://www.pango.org) is a library for internationalized
text handling. It is available [here](https://download.gnome.org/sources/pango/).
- ATK is the Accessibility Toolkit. It provides a set of generic
interfaces allowing accessibility technologies such as
screen readers to interact with a graphical user interface.
It is available [here](https://download.gnome.org/sources/atk/).
- [GObject Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection)
is a framework for making introspection data available to language
bindings. It is available [here](https://download.gnome.org/sources/gobject-introspection/).
- The [GNU libiconv](https://www.gnu.org/software/libiconv/) library
is needed to build GLib if your system doesn't have the iconv()
function for doing conversion between character encodings. Most
modern systems should have iconv().
- The libintl library from the [GNU gettext](https://www.gnu.org/software/gettext/)
package is needed if your system doesn't have the gettext()
functionality for handling message translation databases.
- The libraries from the X window system are needed to build
Pango and GTK. You should already have these installed on
your system, but it's possible that you'll need to install
the development environment for these libraries that your
operating system vendor provides.
- The [fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/)
library provides Pango with a standard way of locating
fonts and matching them against font names.
- [Cairo](https://www.cairographics.org) is a graphics library that
supports vector graphics and image compositing. Both Pango and GTK
use Cairo for drawing.
- [libepoxy](https://github.com/anholt/libepoxy) is a library that
abstracts the differences between different OpenGL libraries. GTK
uses it for cross-platform GL support and for its own drawing.
- [Graphene](http://ebassi.github.io/graphene/) is a library that
provides vector and matrix types for 2D and 3D transformations.
GTK uses it internally for drawing.
- The [Wayland](https://wayland.freedesktop.org) libraries are needed
to build GTK with the Wayland backend.
- The [shared-mime-info](https://www.freedesktop.org/wiki/Software/shared-mime-info)
package is not a hard dependency of GTK, but it contains definitions
for mime types that are used by GIO and, indirectly, by GTK.
gdk-pixbuf will use GIO for mime type detection if possible.
For this to work, shared-mime-info needs to be installed and
`XDG_DATA_DIRS` set accordingly at configure time. Otherwise,
gdk-pixbuf falls back to its built-in mime type detection.
## Building and testing GTK {#building}
First make sure that you have the necessary external
dependencies installed: `pkg-config`, Meson, Ninja,
the JPEG, PNG, and TIFF libraries, FreeType, and, if necessary,
libiconv and libintl. To get detailed information about building
these packages, see the documentation provided with the
individual packages. On any average Linux system, it's quite likely
you'll have all of these installed already, or they will be easily
accessible through your operating system package repositories.
Then build and install the GTK libraries in the order:
GLib, Cairo, Pango, ATK, then GTK. For each library, follow the
instructions they provide, and make sure to share common settings
between them and the GTK build; if you are using a separate prefix
for GTK, for instance, you will need to use the same prefix for
all its dependencies you build. If you're lucky, this will all go
smoothly, and you'll be ready to [start compiling your own GTK
applications](#gtk-compiling). You can test your GTK installation
by running the `gtk4-demo` program that GTK installs.
If one of the projects you're configuring or building fails, look
closely at the error messages printed; these will often provide useful
information as to what went wrong. Every build system has its own
log that can help you understand the issue you're encountering. If
all else fails, you can ask for help on the
[GTK forums](#gtk-resources).
## Extra Configuration Options {#extra-configuration-options}
In addition to the normal options provided by Meson,
GTK defines various arguments that modify what should
be built. All of these options are passed to `meson`
as `-Doption=value`. Most of the time, the value can
be `true` or `false`. To see a summary of all supported
options and their allowed values, run
```
meson configure builddir
```
### `xinerama`
By default GTK will try to link against the Xinerama libraries
if they are found. This option can be used to explicitly control
whether Xinerama should be used.
### `gtk_doc` and `man-pages`
The *gtk-doc* package is used to generate the reference documentation
included with GTK. By default support for *gtk-doc* is disabled
because it requires various extra dependencies to be installed.
If you have *gtk-doc* and *pandoc* installed and are modifying GTK,
you may want to enable *gtk-doc* support by passing in `-Dgtk_doc=true`.
Additionally, some tools provided by GTK have their own
manual pages generated using a similar set of dependencies;
if you have *xsltproc* then you can generate manual pages by
passing `-Dman-pages=true` when configuring the build.
### `print-backends`
By default, GTK will try to build various print backends
if their dependencies are found. This option can be used
to explicitly control which print backends should be built.
### `x11-backend`, `win32-backend`, `broadway-backend`, `wayland-backend` and `quartz-backend`
Enable specific backends for GDK. If none of these options
are given, the Wayland backend will be enabled by default,
if the platform is Linux; the X11 backend will also be enabled
by default, unless the platform is Windows, in which case the
default is win32, or the platform is macOS, in which case the
default is quartz. If any backend is explicitly enabled or disabled,
no other platform will be enabled automatically.
### `introspection`
Allows to disable building introspection support. This is option
is mainly useful for shortening turnaround times on developer
systems. Installed builds of GTK should always have introspection
support.
### `build-tests`, `install-tests`, `demos`
By default, GTK will build quite a few tests and demos.
While these are useful on a developer system, they are not
needed when GTK is built e.g. for a flatpak runtime. These
options allow to disable building tests and demos.

View File

@@ -0,0 +1,518 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="gtk-building">
<refmeta>
<refentrytitle>Compiling the GTK libraries</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Compiling the GTK Libraries</refname>
<refpurpose>
How to compile GTK itself
</refpurpose>
</refnamediv>
<refsect1 id="overview">
<title>Building GTK</title>
<para>
Before we get into the details of how to compile GTK, we should
mention that in many cases, binary packages of GTK prebuilt for
your operating system will be available, either from your
operating system vendor or from independent sources. If such a
set of packages is available, installing it will get you
programming with GTK much faster than building it yourself. In
fact, you may well already have GTK installed on your system
already.
</para>
<para>
In order to build GTK, you will need <application>meson</application>
installed on your system. On Linux, and other UNIX-like operating
systems, you will also need <application>ninja</application>. This
guide does not cover how to install these two requirements, but you
can refer to the <ulink url="http://mesonbuild.com">Meson website</ulink>
for more information. The <ulink url="https://ninja-build.org">Ninja</ulink>
build tool is also usable on various operating systems, so we will
refer to it in the examples.
</para>
<para>
If you are building GTK from a source distribution or from a Git
clone, you will need to use <application>meson</application> to
configure the project. The most commonly useful argument is the
<systemitem>--prefix</systemitem> one, which determines where the
files will go once installed. To install GTK under a prefix
like <filename>/opt/gtk</filename> you would run Meson as:
</para>
<informalexample>
<programlisting>
meson --prefix /opt/gtk builddir
</programlisting>
</informalexample>
<para>
Meson will create the <filename>builddir</filename> directory and
place all the build artefacts there.
</para>
<para>
You can get a list of all available options for the build by
running <application>meson configure</application>.
</para>
<para>
After Meson successfully configured the build directory, you then
can run the build, using Ninja:
</para>
<informalexample>
<programlisting>
cd builddir
ninja
ninja install
</programlisting>
</informalexample>
<para>
If you don't have permission to write to the directory you are
installing in, you may have to change to root temporarily before
running <literal>ninja install</literal>.
</para>
<para>
Several environment variables are useful to pass to set before
running <application>meson</application>. <envar>CPPFLAGS</envar>
contains options to pass to the C compiler, and is used to tell
the compiler where to look for include files. The <envar>LDFLAGS</envar>
variable is used in a similar fashion for the linker. Finally the
<envar>PKG_CONFIG_PATH</envar> environment variable contains
a search path that <command>pkg-config</command> (see below)
uses when looking for files describing how to compile
programs using different libraries. If you were installing GTK
and it's dependencies into <filename>/opt/gtk</filename>, you
might want to set these variables as:
</para>
<programlisting>
CPPFLAGS="-I/opt/gtk/include"
LDFLAGS="-L/opt/gtk/lib"
PKG_CONFIG_PATH="/opt/gtk/lib/pkgconfig"
export CPPFLAGS LDFLAGS PKG_CONFIG_PATH
</programlisting>
<para>
You may also need to set the <envar>LD_LIBRARY_PATH</envar>
environment variable so the systems dynamic linker can find
the newly installed libraries, and the <envar>PATH</envar>
environment program so that utility binaries installed by
the various libraries will be found.
</para>
<programlisting>
LD_LIBRARY_PATH="/opt/gtk/lib"
PATH="/opt/gtk/bin:$PATH"
export LD_LIBRARY_PATH PATH
</programlisting>
</refsect1>
<refsect1 id="build-types">
<title>Build types</title>
<para>Meson has different build types, exposed by the <literal>buildtype</literal>
configuration option. GTK enables and disables functionality depending on
the build type used when calling <application>meson</application> to
configure the build.</para>
<formalpara>
<title><systemitem>debug</systemitem> and <systemitem>debugoptimized</systemitem></title>
<para>
GTK will enable debugging code paths in both the
<literal>debug</literal> and <literal>debugoptimized</literal>
build types. Builds with <literal>buildtype</literal> set
to <literal>debug</literal> will additionally enable
consistency checks on the internal state of the toolkit.
</para>
<para>
It is recommended to use the <literal>debug</literal> or
<literal>debugoptimized</literal> build types when developing
GTK itself. Additionally, <literal>debug</literal> builds of
GTK are recommended for profiling and debugging GTK applications,
as they include additional validation of the internal state.
</para>
<para>
The <literal>debugoptimized</literal> build type is the
default for GTK if no build type is specified when calling
<application>meson</application>
</para>
</formalpara>
<formalpara>
<title><systemitem>release</systemitem></title>
<para>
The <literal>release</literal> build type will disable
debugging code paths and additional run time safeties, like
checked casts for object instances.
</para>
</formalpara>
<para>
The <literal>plain</literal> build type provided by Meson
should only be used when packaging GTK, and it's expected
that packagers will provide their own compiler flags when
building GTK. See the previous section for the list of
environment variables to be used to define compiler and
linker flags.
</para>
</refsect1>
<refsect1 id="dependencies">
<title>Dependencies</title>
<para>
Before you can compile the GTK widget toolkit, you need to have
various other tools and libraries installed on your
system. Dependencies of GTK have their own build systems, so
you will need to refer to their own installation instructions.
</para>
<para>
A particular important tool used by GTK to find its dependencies
is <application>pkg-config</application>.
</para>
<para>
<ulink url="https://www.freedesktop.org/wiki/Software/pkg-config/">pkg-config</ulink>
is a tool for tracking the compilation flags needed for
libraries that are used by the GTK libraries. (For each
library, a small <literal>.pc</literal> text file is installed
in a standard location that contains the compilation flags
needed for that library along with version number information.)
</para>
<para>
Some of the libraries that GTK depends on are maintained by
by the GTK team: GLib, GdkPixbuf, Pango, ATK and GObject Introspection.
Other libraries are maintained separately.
</para>
<itemizedlist>
<listitem>
<para>
The GLib library provides core non-graphical functionality
such as high level data types, Unicode manipulation, and
an object and type system to C programs. It is available
from <ulink url="https://download.gnome.org/sources/glib/">here</ulink>.
</para>
</listitem>
<listitem>
<para>
The <ulink url="https://git.gnome.org/browse/gdk-pixbuf/">GdkPixbuf library</ulink>
provides facilities for loading images in a variety of file formats.
It is available <ulink url="https://download.gnome.org/sources/gdk-pixbuf/">here</ulink>.
</para>
</listitem>
<listitem>
<para>
<ulink url="http://www.pango.org">Pango</ulink> is a library
for internationalized text handling. It is available
<ulink url="https://download.gnome.org/sources/pango/">here</ulink>.
</para>
</listitem>
<listitem>
<para>
ATK is the Accessibility Toolkit. It provides a set of generic
interfaces allowing accessibility technologies such as
screen readers to interact with a graphical user interface.
It is available
<ulink url="https://download.gnome.org/sources/atk/">here</ulink>.
</para>
</listitem>
<listitem>
<para>
<ulink url="https://wiki.gnome.org/Projects/GObjectIntrospection">Gobject Introspection</ulink>
is a framework for making introspection data available to
language bindings. It is available
<ulink url="https://download.gnome.org/sources/gobject-introspection/">here</ulink>.
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<title>External dependencies</title>
<listitem>
<para>
The <ulink url="https://www.gnu.org/software/libiconv/">GNU
libiconv library</ulink> is needed to build GLib if your
system doesn't have the <function>iconv()</function>
function for doing conversion between character
encodings. Most modern systems should have
<function>iconv()</function>.
</para>
</listitem>
<listitem>
<para>
The libintl library from the <ulink
url="https://www.gnu.org/software/gettext/">GNU gettext
package</ulink> is needed if your system doesn't have the
<function>gettext()</function> functionality for handling
message translation databases.
</para>
</listitem>
<listitem>
<para>
The libraries from the X window system are needed to build
Pango and GTK. You should already have these installed on
your system, but it's possible that you'll need to install
the development environment for these libraries that your
operating system vendor provides.
</para>
</listitem>
<listitem>
<para>
The <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">fontconfig</ulink>
library provides Pango with a standard way of locating
fonts and matching them against font names.
</para>
</listitem>
<listitem>
<para>
<ulink url="https://www.cairographics.org">Cairo</ulink>
is a graphics library that supports vector graphics and image
compositing. Both Pango and GTK use Cairo for drawing.
</para>
</listitem>
<listitem>
<para>
<ulink url="https://github.com/anholt/libepoxy">libepoxy</ulink>
is a library that abstracts the differences between different
OpenGL libraries. GTK uses it for cross-platform GL support
and for its own drawing.
</para>
</listitem>
<listitem>
<para>
<ulink url="https://github.com/anholt/libepoxy">Graphene</ulink>
is a library that provides vector and matrix types for 2D and
3D transformations. GTK uses it internally for drawing.
</para>
</listitem>
<listitem>
<para>
The <ulink url="https://wayland.freedesktop.org">Wayland</ulink> libraries
are needed to build GTK with the Wayland backend.
</para>
</listitem>
<listitem>
<para>
The <ulink url="https://www.freedesktop.org/wiki/Software/shared-mime-info">shared-mime-info</ulink>
package is not a hard dependency of GTK, but it contains definitions
for mime types that are used by GIO and, indirectly, by GTK.
gdk-pixbuf will use GIO for mime type detection if possible. For this
to work, shared-mime-info needs to be installed and
<envar>XDG_DATA_DIRS</envar> set accordingly at configure time.
Otherwise, gdk-pixbuf falls back to its built-in mime type detection.
</para>
</listitem>
</itemizedlist>
</refsect1>
<refsect1 id="building">
<title>Building and testing GTK</title>
<para>
First make sure that you have the necessary external
dependencies installed: <command>pkg-config</command>, Meson, Ninja,
the JPEG, PNG, and TIFF libraries, FreeType, and, if necessary,
libiconv and libintl. To get detailed information about building
these packages, see the documentation provided with the
individual packages. On any average Linux system, it's quite likely
you'll have all of these installed already, or they will be easily
accessible through your operating system package repositories.
</para>
<para>
Then build and install the GTK libraries in the order:
GLib, Cairo, Pango, ATK, then GTK. For each library, follow the
instructions they provide, and make sure to share common settings
between them and the GTK build; if you are using a separate prefix
for GTK, for instance, you will need to use the same prefix for all
its dependencies you build. If you're lucky, this will all go smoothly,
and you'll be ready to <link linkend="gtk-compiling">start compiling
your own GTK applications</link>. You can test your GTK installation
by running the <command>gtk4-demo</command> program that
GTK installs.
</para>
<para>
If one of the projects you're configuring or building fails, look
closely at the error messages printed; these will often provide useful
information as to what went wrong. Every build system has its own
log that can help you understand the issue you're encountering. If all
else fails, you can ask for help on the gtk-list mailing list.
See <xref linkend="gtk-resources"/> for more information.
</para>
</refsect1>
<refsect1 id="extra-configuration-options">
<title>Extra Configuration Options</title>
<para>
In addition to the normal options provided by Meson, GTK defines
various arguments that modify what should be built.
<cmdsynopsis>
<command>meson</command>
<sbr/>
<group>
<arg choice="plain">-Dx11-backend=true</arg>
<arg choice="plain">-Dx11-backend=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dwayland-backend=true</arg>
<arg choice="plain">-Dwayland-backend=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dbroadway-backend=true</arg>
<arg choice="plain">-Dbroadway-backend=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dwin32-backend=true</arg>
<arg choice="plain">-Dwin32-backend=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dquartz-backend=true</arg>
<arg choice="plain">-Dquartz-backend=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dmedia=gstreamer</arg>
<arg choice="plain">-Dmedia=ffmpeg</arg>
<arg choice="plain">-Dmedia=all</arg>
<arg choice="plain">-Dmedia=none</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dvulkan=yes</arg>
<arg choice="plain">-Dvulkan=no</arg>
<arg choice="plain">-Dvulkan=auto</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dxinerama=yes</arg>
<arg choice="plain">-Dxinerama=no</arg>
<arg choice="plain">-Dxinerama=auto</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dcloudproviders=true</arg>
<arg choice="plain">-Dcloudproviders=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dprint-backends=all</arg>
<arg choice="plain">-Dprint-backends=none</arg>
<arg choice="plain">-Dprint-backends=cups,lpr,...</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dcolord=yes</arg>
<arg choice="plain">-Dcolord=no</arg>
<arg choice="plain">-Dcolord=auto</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dgtk_doc=true</arg>
<arg choice="plain">-Dgtk_doc=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dman-pages=true</arg>
<arg choice="plain">-Dman-pages=false</arg>
</group>
<sbr/>
<group>
<arg choice="plain">-Dintrospection=true</arg>
<arg choice="plain">-Dintrospection=false</arg>
</group>
</cmdsynopsis>
</para>
<formalpara>
<title><systemitem>xinerama</systemitem></title>
<para>
By default GTK will try to link against the Xinerama libraries
if they are found. This options can be used to explicitly control
whether Xinerama should be used.
</para>
</formalpara>
<formalpara>
<title><systemitem>gtk_doc</systemitem> and
<systemitem>man-pages</systemitem></title>
<para>
The <application>gtk-doc</application> package is
used to generate the reference documentation included
with GTK. By default support for <application>gtk-doc</application>
is disabled because it requires various extra dependencies
to be installed. If you have
<application>gtk-doc</application> installed and
are modifying GTK, you may want to enable
<application>gtk-doc</application> support by passing
in <systemitem>gtk_doc</systemitem>.
</para>
<para>
Additionally, some tools provided by GTK have their own
manual pages generated using a similar set of dependencies;
if you have <application>xsltproc</application> then you
can generate manual pages by passing <systemitem>man-pages</systemitem>
when configuring the build.
</para>
</formalpara>
<formalpara>
<title><systemitem>print-backends</systemitem></title>
<para>
By default, GTK will try to build various print backends if
their dependencies are found. This option can be used to
explicitly control which print backends should be built.
</para>
</formalpara>
<formalpara>
<title><systemitem>x11-backend</systemitem>,
<systemitem>win32-backend</systemitem>,
<systemitem>quartz-backend</systemitem>,
<systemitem>broadway-backend</systemitem> and
<systemitem>wayland-backend</systemitem></title>
<para>
Enable specific backends for GDK. If none of these options
are given, the Wayland backend will be enabled by default,
if the platform is Linux; the X11 backend will also be enabled
by default, unless the platform is Windows, in which case the
default is win32, or the platform is macOS, in which case the
default is quartz. If any backend is explicitly enabled or disabled,
no other platform will be enabled automatically.
</para>
</formalpara>
<formalpara>
<title><systemitem>introspection</systemitem></title>
<para>
Allows to disable building introspection support. This is option
is mainly useful for shortening turnaround times on developer
systems. Installed builds of GTK should always have introspection
support.
</para>
</formalpara>
<formalpara>
<title><systemitem>build-tests</systemitem>,
<systemitem>install-tests</systemitem>,
<systemitem>demos</systemitem></title>
<para>
By default, GTK will build quite a few tests and demos.
While these are useful on a developer system, they are not
needed when GTK is built e.g. for a flatpak runtime. These
options allow to disable building tests and demos.
</para>
</formalpara>
</refsect1>
</refentry>

View File

@@ -1,55 +1,94 @@
# Compiling GTK Applications on UNIX {#gtk-compiling}
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="gtk-compiling">
<refmeta>
<refentrytitle>Compiling GTK Applications</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Compiling GTK Applications</refname>
<refpurpose>
How to compile your GTK application
</refpurpose>
</refnamediv>
<refsect1>
<title>Compiling GTK Applications on UNIX</title>
<para>
To compile a GTK application, you need to tell the compiler where to
find the GTK header files and libraries. This is done with the
`pkg-config` utility.
The following interactive shell session demonstrates how `pkg-config`
is used (the actual output on your system may be different):
```
<literal>pkg-config</literal> utility.
</para>
<para>
The following interactive shell session demonstrates how
<literal>pkg-config</literal> is used (the actual output on
your system may be different):
<programlisting>
$ pkg-config --cflags gtk4
-pthread -I/usr/include/gtk-4.0 -I/usr/lib64/gtk-4.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12
$ pkg-config --libs gtk4
-pthread -lgtk-4 -lgdk-4 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lrt -lglib-2.0
```
</programlisting>
</para>
<para>
The simplest way to compile a program is to use the "backticks"
feature of the shell. If you enclose a command in backticks
(*not single quotes*), then its output will be substituted into the
command line before execution. So to compile a GTK Hello, World, you
would type the following:
```
(<emphasis>not single quotes</emphasis>), then its output will be
substituted into the command line before execution. So to compile
a GTK Hello, World, you would type the following:
<programlisting>
$ cc `pkg-config --cflags gtk4` hello.c -o hello `pkg-config --libs gtk4`
```
</programlisting>
</para>
<para>
Deprecated GTK functions are annotated to make the compiler
emit warnings when they are used (e.g. with gcc, you need to use
the -Wdeprecated-declarations option). If these warnings are
problematic, they can be turned off by defining the preprocessor
symbol %GDK_DISABLE_DEPRECATION_WARNINGS by using the commandline
option `-DGDK_DISABLE_DEPRECATION_WARNINGS`.
option <literal>-DGDK_DISABLE_DEPRECATION_WARNINGS</literal>
</para>
<para>
GTK deprecation annotations are versioned; by defining the
macros %GDK_VERSION_MIN_REQUIRED and %GDK_VERSION_MAX_ALLOWED,
you can specify the range of GTK versions whose API you want
to use. APIs that were deprecated before or introduced after
this range will trigger compiler warnings.
</para>
<para>
Here is how you would compile hello.c if you want to allow it
to use symbols that were not deprecated in 4.2:
```
$ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_4_2 hello.c -o hello `pkg-config --libs gtk4`
```
<programlisting>
$ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MIN_REQIRED=GDK_VERSION_4_2 hello.c -o hello `pkg-config --libs gtk4`
</programlisting>
</para>
<para>
And here is how you would compile hello.c if you don't want
it to use any symbols that were introduced after 4.2:
```
<programlisting>
$ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_4_2 hello.c -o hello `pkg-config --libs gtk4`
```
</programlisting>
</para>
<para>
The older deprecation mechanism of hiding deprecated interfaces
entirely from the compiler by using the preprocessor symbol
GTK_DISABLE_DEPRECATED is still used for deprecated macros,
enumeration values, etc. To detect uses of these in your code,
use the commandline option `-DGTK_DISABLE_DEPRECATED`.
use the commandline option <literal>-DGTK_DISABLE_DEPRECATED</literal>.
There are similar symbols GDK_DISABLE_DEPRECATED,
GDK_PIXBUF_DISABLE_DEPRECATED and G_DISABLE_DEPRECATED for GDK,
GdkPixbuf and GLib.
GDK_PIXBUF_DISABLE_DEPRECATED and G_DISABLE_DEPRECATED for GDK, GdkPixbuf and
GLib.
</para>
</refsect1>
</refentry>

View File

@@ -1,79 +0,0 @@
# CSS in GTK {#css}
This chapter describes how GTK uses CSS for styling and layout.
It is not meant to be an explanation of CSS from first principles,
but focuses on listing supported CSS features and differences
between Web CSS and GTK.
There is plenty of introductory documentation available that
can be used to learn about CSS in general. In the tables below
we include links to the official specs that can be used to look
up the definition of individual selectors and properties.
## CSS nodes
GTK applies the style information found in style sheets by matching
the selectors against a tree of nodes. Each node in the tree has a
name, a state and possibly style classes. The children of each node
are linearly ordered.
Every widget has one or more of these CSS nodes, and determines their
name, state, style classes and how they are layed out as children and
siblings in the overall node tree. The documentation for each widget
explains what CSS nodes it has.
### The CSS nodes of a GtkScale
```
scale[.fine-tune]
├── marks.top
│ ├── mark
┊ ┊
│ ╰── mark
├── trough
│ ├── slider
│ ├── [highlight]
│ ╰── [fill]
╰── marks.bottom
├── mark
╰── mark
```
## Selectors
Selectors work very similar to the way they do on the web.
All widgets have one or more CSS nodes with element names and style
classes. When style classes are used in selectors, they have to be prefixed
with a period. Widget names can be used in selectors like IDs. When used
in a selector, widget names must be prefixed with a &num; character.
### GTK CSS Selectors
| Pattern | Reference | Notes |
|:--------|:----------|:------|
| * | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#universal-selector) | |
| E | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#type-selectors) | |
| E.class | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#class-html) | |
| E#id | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#id-selectors) | |
| E:nth-child(n) | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#structural-pseudos) | |
| E:nth-last-child(n) | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#structural-pseudos) | |
| E:first-child | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#structural-pseudos) | |
| E:last-child | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#structural-pseudos) | |
| E:only-child | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#structural-pseudos) | |
| E:link, E:visited | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#link) | Corresponds to GTK_STATE_FLAG_LINK and GTK_STATE_FLAGS_VISITED |
| E:active, E:hover, E:focus | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#useraction-pseudos) | Correspond to GTK_STATE_FLAG_ACTIVE, GTK_STATE_FLAG_PRELIGHT, GTK_STATE_FLAGS_FOCUSED |
| E:focus-within | [CSS Selector Level 4](https://drafts.csswg.org/selectors/#focus-within-pseudo) | Set on all ancestors of the focus widget, unlike CSS |
| E:focus-visible | [CSS Selector Level 4](https://drafts.csswg.org/selectors/#focus-within-pseudo) | Set on focus widget and all ancestors, unlike CSS |
| E:disabled | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#UIstates) | Corresponds to GTK_STATE_FLAG_INSENSITIVE |
| E:disabled | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#UIstates) | Corresponds to GTK_STATE_FLAG_CHECKED |
| E:indeterminate | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#indeterminate) | Corresponds to GTK_STATE_FLAG_INCONSISTENT |
| E:backdrop, E:selected | | Corresponds to GTK_STATE_FLAG_BACKDROP, GTK_STATE_FLAG_SELECTED |
| E:not(selector) | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#negation) | |
| E:dir(ltr), E:dir(rtl) | [CSS Selector Level 4](https://drafts.csswg.org/selectors/#the-dir-pseudo) | |
| E:drop(active) | [CSS Selector Level 4](https://drafts.csswg.org/selectors/#drag-pseudos) | |
| E F | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#descendent-combinators) | |
| E > F | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#child-combinators) | |
| E ~ F | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#general-sibling-combinators) | |
| E + F | [CSS Selector Level 3](https://www.w3.org/TR/css3-selectors/#adjacent-sibling-combinators) | |

File diff suppressed because it is too large Load Diff

View File

@@ -1,238 +0,0 @@
# GTK CSS Properties
GTK supports CSS properties and shorthands as far as they can be applied
in the context of widgets, and adds its own properties only when needed.
All GTK-specific properties have a -gtk prefix.
## Basic types
All properties support the following keywords: inherit, initial, unset,
with the same meaning as defined in the
[CSS Cascading and Inheritance](https://www.w3.org/TR/css3-cascade/#defaulting-keywords)
spec.
The following units are supported for basic datatypes:
Length
: px, pt, em, ex, rem, pc, in, cm, mm, calc()
Percentage
: %, calc()
Angle
: deg | grad | turn, calc()
Time
: s | ms, calc()
Length values with the em or ex units are resolved using the font
size value, unless they occur in setting the font-size itself, in
which case they are resolved using the inherited font size value.
The rem unit is resolved using the initial font size value, which is
not quite the same as the CSS definition of rem.
The calc() notation adds considerable expressive power. There are limits
on what types can be combined in such an expression (e.g. it does not make
sense to add a number and a time). For the full details, see the
[CSS3 VAlues and Units](https://www.w3.org/TR/css3-values/#calc-notation)
spec.
A common pattern among shorthand properties (called 'four sides') is one
where one to four values can be specified, to determine a value for each
side of an area. In this case, the specified values are interpreted as
follows:
4 values:
: top right bottom left
3 values:
: top horizontal bottom
2 values:
: vertical horizontal
1 value:
: all
## Colors
GTK extends the CSS syntax with several additional ways to specify colors.
The first is a reference to a color defined via a @define-color rule in CSS.
The syntax for @define-color rules is as follows:
```
@define-color Name Color
```
To refer to the color defined by a @define-color rule, prefix the name with @.
GTK also supports color expressions, which allow colors to be transformed to
new ones. Color expressions can be nested, providing a rich language to
define colors. Color expressions resemble functions, taking 1 or more colors
and in some cases a number as arguments.
`lighter(Color)`
: produces a brigher variant of Color
`darker(Color)`
: produces a darker variant of Color
`shade(Color, Number)`
: changes the lightness of Color. The number ranges from 0 for black to 2 for white.
`alpha(Color, Number)`
: replaces the alpha value of color with number (between 0 and 1)
`mix(Color1, Color2, Number)`
: interpolates between the two colors
## Images
GTK extends the CSS syntax for images and also uses it for specifying icons.
To load a themed icon, use
```
-gtk-icontheme(Name)
```
The specified icon name is used to look up a themed icon, while taking into
account the values of the -gtk-icon-palette property. This kind of image is
mainly used as value of the -gtk-icon-source property.
Symbolic icons from the icon theme are recolored according to the
-gtk-icon-palette property, which defines a list of named colors.
The recognized names for colors in symbolic icons are error, warning
and success. The default palette maps these three names to symbolic
colors with the names @error_color, @warning_color and @success_color
respectively. The syntax for defining a custom palette is a comma-separated
list of name-color pairs, e.g.
```
success blue, warning #fc3, error magenta
```
Recoloring is sometimes needed for images that are not part of an icon theme,
and the
```
-gtk-recolor(uri, palette)
```
syntax makes this available. -gtk-recolor requires a url as first argument.
The remaining arguments specify the color palette to use. If the palette is
not explicitly specified, the current value of the -gtk-icon-palette property
is used.
GTK supports scaled rendering on hi-resolution displays. This works best if
images can specify normal and hi-resolution variants. From CSS, this can be
done with
```
-gtk-scaled(Image1, Image2)
```
## GTK CSS Properties
| Property | Reference | Notes |
|:-----------|:----------|:------|
|color | [CSS Color Level 3](https://www.w3.org/TR/css3-color/#foreground) | |
|opacity | [CSS Color Level 3](https://www.w3.org/TR/css3-color/#opacity) | |
|filter | [CSS Filter Effect Level 1](https://drafts.fxtf.org/filters/#FilterProperty) | |
|font-family | [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-family-prop) | defaults to gtk-font-name setting |
|font-size | [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-size-prop) | defaults to gtk-font-name setting |
|font-style | [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-style-prop) | |
|font-variant| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#descdef-font-variant) | only CSS2 values supported |
|font-weight | [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-weight-prop) | |
|font-stretch| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-stretch-prop) | |
|font-kerning| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-kerning-prop) | |
|font-variant-ligatures| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-ligatures-prop) | |
|font-variant-position| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-position-prop) | |
|font-variant-caps| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-position-prop) | |
|font-variant-numeric| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-numeric-prop) | |
|font-variant-alternates| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-alternates-prop) | |
|font-variant-east-asian| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-east-asian-prop) | |
|font-feature-settings| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-feature-settings-prop) | |
|font-variation-settings| [CSS Fonts Level 4](https://www.w3.org/TR/css-fonts-4/#font-variation-settings-def) | |
|-gtk-dpi|[Number](https://www.w3.org/TR/css3-values/#number-value) | defaults to screen resolution |
|font| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-prop) | CSS allows line-height, etc |
|font-variant| [CSS Fonts Level 3](https://www.w3.org/TR/css3-fonts/#font-variant-prop) | |
|caret-color|[CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#caret-color) | CSS allows an auto value |
|-gtk-secondary-caret-color|[Color](https://www.w3.org/TR/css-color-3/#valuea-def-color) | used for the secondary caret in bidirectional text |
|letter-spacing| [CSS Text Level 3](https://www.w3.org/TR/css3-text/#letter-spacing) | |
|text-decoration-line| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-line-property) | CSS allows overline |
|text-decoration-color| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-color-property) | |
|text-decoration-style| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-style-property) | CSS allows dashed and dotted |
|text-shadow| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-shadow-property) | |
|text-decoration| [CSS Text Decoration Level 3](https://www.w3.org/TR/css-text-decor-3/#text-decoration-property) | |
|-gtk-icon-source| [Image](https://www.w3.org/TR/css-backgrounds-3/#typedef-image), `builtin` or `none` | used for builtin icons in buttons and expanders |
|-gtk-icon-size| [Length](https://www.w3.org/TR/css3-values/#length-value) | size used for builtin icons in buttons and expanders |
|-gtk-icon-style| `requested`, `regular` or `symbolic` | preferred style for application-loaded icons |
|-gtk-icon-transform| [Transform list](https://drafts.csswg.org/css-transforms-1/#typedef-transform-list) or `none` | applied to builtin and application-loaded icons |
|-gtk-icon-palette| Color palette, as explained above | used to recolor symbolic icons |
|-gtk-icon-shadow| [Shadow](https://www.w3.org/TR/css-backgrounds-3/#typedef-shadow) or `none` | applied to builtin and application-loaded icons |
|-gtk-icon-filter| [Filter value list](https://www.w3.org/TR/filter-effects-1/#typedef-filter-value-list) or `none` | applied to builtin and application-loaded icons |
|transform| [CSS Transforms Level 2](https://drafts.csswg.org/css-transforms-2/) | |
|min-width| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#min-width) | CSS allows percentages |
|min-height| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#min-height) | CSS allows percentages |
|margin-top| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin-top) | CSS allows percentages or auto |
|margin-right| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin-right) | CSS allows percentages or auto |
|margin-bottom| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin-bottom) | CSS allows percentages or auto |
|margin-left| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin-left) | CSS allows percentages or auto |
|padding-top| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#padding-top) | CSS allows percentages |
|padding-right| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#padding-right) | CSS allows percentages |
|padding-bottom| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#padding-bottom) | CSS allows percentages |
|padding-left| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#padding-left) | CSS allows percentages |
|margin| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#margin) | a 'four sides' property |
|padding| [CSS Box Model Level 3](https://www.w3.org/TR/css3-box/#padding) | a 'four sides' property |
|border-top-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-width) | CSS allows other values |
|border-right-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-width) | CSS allows other values |
|border-bottom-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-width) | CSS allows other values |
|border-left-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-width) | CSS allows other values |
|border-top-style| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-style) | |
|border-right-style| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-style) | |
|border-bottom-style| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-style) | |
|border-left-style| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-style) | |
|border-top-right-radius| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-radius) | |
|border-bottom-right-radius| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-radius) | |
|border-bottom-left-radius| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-radius) | |
|border-top-left-radius| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-radius) | |
|border-top-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-color) | |
|border-right-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-color) | |
|border-bottom-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-color) | |
|border-left-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-color) | |
|border-image-source| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-image-source) | |
|border-image-repeat| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-image-repeat) | |
|border-image-slice| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-image-slice) | a 'four sides' property |
|border-image-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-image-width) | a 'four sides' property |
|border-width| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-width) | a 'four sides' property |
|border-style| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#the-border-style) | a 'four sides' property |
|border-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-color) | a 'four sides' property |
|border-top| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-top) | |
|border-right| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-right) | |
|border-bottom| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-bottom) | |
|border-left| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-left) | |
|border| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border) | |
|border-radius| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-radius) | |
|border-image| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#border-image) | |
|outline-style| [CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#outline-style) | initial value is none, auto is not supported |
|outline-width| [CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#outline-width) | |
|outline-color| [CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#outline-color) | initial value is currentColor, invert is not supported |
|outline-offset| [CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#outline-offset) | |
|outline| [CSS Basic User Interface Level 3](https://www.w3.org/TR/css3-ui/#propdef-outline) | |
|background-color| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-color) | |
|background-clip| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-clip) | |
|background-origin| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-origin) | |
|background-size| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-size) | |
|background-position| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-position) | |
|background-repeat| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-repeat) | |
|background-image| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background-image) | not supported: urls without quotes, colors in crossfades |
|box-shadow| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#box-shadow) | |
|background-blend-mode| [CSS Compositing and Blending Level 1](https://www.w3.org/TR/compositing-1/#propdef-background-blend-mode) | only affects multiple backgrounds |
|background| [CSS Backgrounds and Borders Level 3](https://www.w3.org/TR/css3-background/#background) | |
|transition-property| [CSS Transitions](https://www.w3.org/TR/css3-transitions/#transition-property) | |
|transition-duration| [CSS Transitions](https://www.w3.org/TR/css3-transitions/#transition-duration) | |
|transition-timing-function| [CSS Transitions](https://www.w3.org/TR/css3-transitions/#transition-timing-function) | |
|transition-delay| [CSS Transitions](https://www.w3.org/TR/css3-transitions/#transition-delay) | |
|transition| [CSS Transitions](https://www.w3.org/TR/css3-transitions/#transition) | |
|animation-name| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-name) | |
|animation-duration| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-duration) | |
|animation-timing-function| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-timing-function) | |
|animation-iteration-count| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-iteration-count) | |
|animation-direction| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-direction) | |
|animation-play-state| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-play-state) | |
|animation-delay| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-delay) | |
|animation-fill-mode| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation-fill-mode) | |
|animation| [CSS Animations Level 1](https://www.w3.org/TR/css3-animations/#animation) | |
|border-spacing| [CSS Table Level 3](https://www.w3.org/TR/css-tables-3/#border-spacing-property) | respected by GtkBox and GtkGrid |

View File

@@ -1,157 +0,0 @@
# Overview of the drawing model {#drawing-overview}
This chapter describes the GTK drawing model in detail. If you
are interested in the procedure which GTK follows to draw its
widgets and windows, you should read this chapter; this will be
useful to know if you decide to implement your own widgets. This
chapter will also clarify the reasons behind the ways certain
things are done in GTK.
## Windows and events {#drawing-windows}
Applications that use a windowing system generally create
rectangular regions in the screen called _surfaces_ (GTK is
following the Wayland terminology, other windowing systems
such as X11 may call these _windows_). Traditional windowing
systems do not automatically save the graphical content of
surfaces, and instead ask applications to provide new content
whenever it is needed. For example, if a window that is stacked
below other windows gets raised to the top, then the application
has to repaint it, so the previously obscured area can be shown.
When the windowing system asks an application to redraw a window,
it sends a _frame event_ (_expose event_ in X11 terminology)
for that window.
Each GTK toplevel window or dialog is associated with a
windowing system surface. Child widgets such as buttons or
entries don't have their own surface; they use the surface
of their toplevel.
Generally, the drawing cycle begins when GTK receives
a frame event from the underlying windowing system: if the
user drags a window over another one, the windowing system will
tell the underlying surface that it needs to repaint itself. The
drawing cycle can also be initiated when a widget itself decides
that it needs to update its display. For example, when the user
types a character in an entry widget, the entry asks GTK to queue
a redraw operation for itself.
The windowing system generates frame events for surfaces. The GDK
interface to the windowing system translates such events into
emissions of the ::render signal on the affected surfaces. The GTK
toplevel window connects to that signal, and reacts appropriately.
The following sections describe how GTK decides which widgets
need to be repainted in response to such events, and how widgets
work internally in terms of the resources they use from the
windowing system.
## The frame clock {#frameclock}
All GTK applications are mainloop-driven, which means that most
of the time the app is idle inside a loop that just waits for
something to happen and then calls out to the right place when
it does. On top of this GTK has a frame clock that gives a
“pulse” to the application. This clock beats at a steady rate,
which is tied to the framerate of the output (this is synced to
the monitor via the window manager/compositor). A typical
refresh rate is 60 frames per second, so a new “pulse” happens
roughly every 16 milliseconds.
The clock has several phases:
- Events
- Update
- Layout
- Paint
The phases happens in this order and we will always run each
phase through before going back to the start.
The Events phase is a stretch of time between each redraw where
GTK processes input events from the user and other events
(like e.g. network I/O). Some events, like mouse motion are
compressed so that only a single mouse motion event per clock
cycle needs to be handled.
Once the Events phase is over, external events are paused and
the redraw loop is run. First is the Update phase, where all
animations are run to calculate the new state based on the
estimated time the next frame will be visible (available via
the frame clock). This often involves geometry changes which
drive the next phase, Layout. If there are any changes in
widget size requirements the new layout is calculated for the
widget hierarchy (i.e. sizes and positions for all widgets are
determined). Then comes the Paint phase, where we redraw the
regions of the window that need redrawing.
If nothing requires the Update/Layout/Paint phases we will
stay in the Events phase forever, as we dont want to redraw
if nothing changes. Each phase can request further processing
in the following phases (e.g. the Update phase will cause there
to be layout work, and layout changes cause repaints).
There are multiple ways to drive the clock, at the lowest level you
can request a particular phase with gdk_frame_clock_request_phase()
which will schedule a clock beat as needed so that it eventually
reaches the requested phase. However, in practice most things
happen at higher levels:
- If you are doing an animation, you can use
gtk_widget_add_tick_callback() which will cause a regular
beating of the clock with a callback in the Update phase
until you stop the tick.
- If some state changes that causes the size of your widget to
change you call gtk_widget_queue_resize() which will request
a Layout phase and mark your widget as needing relayout.
- If some state changes so you need to redraw some area of
your widget you use the normal gtk_widget_queue_draw()
set of functions. These will request a Paint phase and
mark the region as needing redraw.
There are also a lot of implicit triggers of these from the
CSS layer (which does animations, resizes and repaints as needed).
## The scene graph {#scene-graph}
The first step in “drawing” a window is that GTK creates
_render nodes_ for all the widgets in the window. The render
nodes are combined into a tree that you can think of as a
_scene graph_ describing your window contents.
Render nodes belong to the GSK layer, and there are various kinds
of them, for the various kinds of drawing primitives you are likely
to need when translating widget content and CSS styling. Typical
examples are text nodes, gradient nodes, texture nodes or clip nodes.
In the past, all drawing in GTK happened via cairo. It is still possible
to use cairo for drawing your custom widget contents, by using a cairo
render node.
A GSK _renderer_ takes these render nodes, transforms them into
rendering commands for the drawing API it targets, and arranges
for the resulting drawing to be associated with the right surface.
GSK has renderers for OpenGL, Vulkan and cairo.
## Hierarchical drawing {#hierarchical-drawing}
During the Paint phase GTK receives a single #GdkSurface::render
signal on the toplevel surface. The signal handler will create a
snapshot object (which is a helper for creating a scene graph) and
call the #GtkWidget::snapshot() vfunc, which will propagate down
the widget hierarchy. This lets each widget snapshot its content
at the right place and time, correctly handling things like partial
transparencies and overlapping widgets.
During the snapshotting of each widget, GTK automatically handles
the CSS rendering according to the CSS box model. It snapshots first
the background, then the border, then the widget content itself, and
finally the outline.
To avoid excessive work when generating scene graphs, GTK caches render
nodes. Each widget keeps a reference to its render node (which in turn,
will refer to the render nodes of children, and grandchildren, and so
on), and will reuse that node during the Paint phase. Invalidating a
widget (by calling gtk_widget_queue_draw()) discards the cached render
node, forcing the widget to regenerate it the next time it needs to
produce a snapshot.

View File

@@ -0,0 +1,232 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="chap-drawing-model">
<refmeta>
<refentrytitle>The GTK Drawing Model</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>The GTK Drawing Model</refname>
<refpurpose>
How widgets draw
</refpurpose>
</refnamediv>
<refsect1 id="drawing-overview">
<title>Overview of the drawing model</title>
<para>
This chapter describes the GTK drawing model in detail. If you
are interested in the procedure which GTK follows to draw its
widgets and windows, you should read this chapter; this will be
useful to know if you decide to implement your own widgets. This
chapter will also clarify the reasons behind the ways certain
things are done in GTK.
</para>
<refsect2 id="drawing model windows">
<title>Windows and events</title>
<para>
Applications that use a windowing system generally create
rectangular regions in the screen called <firstterm>surfaces</firstterm>
(GTK is following the Wayland terminology, other windowing systems
such as X11 may call these <firstterm>windows</firstterm>).
Traditional windowing systems do not automatically save the
graphical content of surfaces, and instead ask applications to
provide new content whenever it is needed.
For example, if a window that is stacked below other
windows gets raised to the top, then the application has to
repaint it, so the previously obscured area can be shown.
When the windowing system asks an application to redraw
a window, it sends a <firstterm>frame event</firstterm>
(<firstterm>expose event</firstterm> in X11 terminology)
for that window.
</para>
<para>
Each GTK toplevel window or dialog is associated with a
windowing system surface. Child widgets such as buttons or
entries don't have their own surface; they use the surface
of their toplevel.
</para>
<para>
Generally, the drawing cycle begins when GTK receives
a frame event from the underlying windowing system: if the
user drags a window over another one, the windowing system will
tell the underlying surface that it needs to repaint itself. The
drawing cycle can also be initiated when a widget itself decides
that it needs to update its display. For example, when the user
types a character in an entry widget, the entry asks GTK to queue
a redraw operation for itself.
</para>
<para>
The windowing system generates frame events for surfaces. The GDK
interface to the windowing system translates such events into
emissions of the ::render signal on the affected surfaces.
The GTK toplevel window connects to that signal, and reacts appropriately.
</para>
<para>
The following sections describe how GTK decides which widgets
need to be repainted in response to such events, and how widgets
work internally in terms of the resources they use from the
windowing system.
</para>
</refsect2>
<refsect2 id="frameclock">
<title>The frame clock</title>
<para>
All GTK applications are mainloop-driven, which means that most
of the time the app is idle inside a loop that just waits for
something to happen and then calls out to the right place when
it does. On top of this GTK has a frame clock that gives a
“pulse” to the application. This clock beats at a steady rate,
which is tied to the framerate of the output (this is synced to
the monitor via the window manager/compositor). A typical
refresh rate is 60 frames per second, so a new “pulse” happens
roughly every 16 milliseconds.
</para>
<para>
The clock has several phases:
<itemizedlist>
<listitem><para>Events</para></listitem>
<listitem><para>Update</para></listitem>
<listitem><para>Layout</para></listitem>
<listitem><para>Paint</para></listitem>
</itemizedlist>
The phases happens in this order and we will always run each
phase through before going back to the start.
</para>
<para>
The Events phase is a stretch of time between each redraw where
GTK processes input events from the user and other events
(like e.g. network I/O). Some events, like mouse motion are
compressed so that only a single mouse motion event per clock
cycle needs to be handled.
</para>
<para>
Once the Events phase is over, external events are paused and
the redraw loop is run. First is the Update phase, where all
animations are run to calculate the new state based on the
estimated time the next frame will be visible (available via
the frame clock). This often involves geometry changes which
drive the next phase, Layout. If there are any changes in
widget size requirements the new layout is calculated for the
widget hierarchy (i.e. sizes and positions for all widgets are
determined). Then comes the Paint phase, where we redraw the
regions of the window that need redrawing.
</para>
<para>
If nothing requires the Update/Layout/Paint phases we will
stay in the Events phase forever, as we dont want to redraw
if nothing changes. Each phase can request further processing
in the following phases (e.g. the Update phase will cause there
to be layout work, and layout changes cause repaints).
</para>
<para>
There are multiple ways to drive the clock, at the lowest level
you can request a particular phase with
gdk_frame_clock_request_phase() which will schedule a clock beat
as needed so that it eventually reaches the requested phase.
However, in practice most things happen at higher levels:
<itemizedlist>
<listitem><para>
If you are doing an animation, you can use
gtk_widget_add_tick_callback() which will cause a regular
beating of the clock with a callback in the Update phase
until you stop the tick.
</para></listitem>
<listitem><para>
If some state changes that causes the size of your widget
to change you call gtk_widget_queue_resize() which will
request a Layout phase and mark your widget as needing
relayout.
</para></listitem>
<listitem><para>
If some state changes so you need to redraw some area of
your widget you use the normal gtk_widget_queue_draw()
set of functions. These will request a Paint phase and
mark the region as needing redraw.
</para></listitem>
</itemizedlist>
There are also a lot of implicit triggers of these from the
CSS layer (which does animations, resizes and repaints as needed).
</para>
</refsect2>
<refsect2 id="scene-graph">
<title>The scene graph</title>
<para>
The first step in “drawing” a window is that GTK creates
<firstterm>render nodes</firstterm> for all the widgets
in the window. The render nodes are combined into a tree
that you can think of as a <firstterm>scene graph</firstterm>
describing your window contents.
</para>
<para>
Render nodes belong to the GSK layer, and there are various kinds
of them, for the various kinds of drawing primitives you are likely
to need when translating widget content and CSS styling. Typical
examples are text nodes, gradient nodes, texture nodes or clip nodes.
<para>
<para>
In the past, all drawing in GTK happened via cairo. It is still possible
to use cairo for drawing your custom widget contents, by using a cairo
render node.
</para>
</para>
A GSK <firstterm>renderer</firstterm> takes these render nodes, transforms
them into rendering commands for the drawing API it targets, and arranges
for the resulting drawing to be associated with the right surface. GSK has
renderers for OpenGL, Vulkan and cairo.
</para>
</refsect2>
<refsect2 id="hierarchical-drawing">
<title>Hierarchical drawing</title>
<para>
During the Paint phase GTK receives a single #GdkSurface::render signal on
the toplevel surface. The signal handler will create a snapshot object
(which is a helper for creating a scene graph) and call the
#GtkWidget::snapshot() vfunc, which will propagate down the widget hierarchy.
This lets each widget snapshot its content at the right place and time,
correctly handling things like partial transparencies and overlapping widgets.
</para>
<para>
During the snapshotting of each widget, GTK automatically handles the CSS
rendering according to the CSS box model. It snapshots first the background,
then the border, then the widget content itself, and finally the outline.
</para>
<para>
To avoid excessive work when generating scene graphs, GTK caches render nodes.
Each widget keeps a reference to its render node (which in turn, will refer to
the render nodes of children, and grandchildren, and so on), and will reuse
that node during the Paint phase. Invalidating a widget (by calling
gtk_widget_queue_draw()) discards the cached render node, forcing the widget
to regenerate it the next time it needs to produce a snapshot.
</para>
</refsect2>
</refsect1>
</refentry>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,366 @@
<?xml version="1.0"?>
<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<glossary id="glossary">
<title>Glossary</title>
<glossentry id="allocation">
<glossterm>allocation</glossterm>
<glossdef>
<para>
The final size of a <glossterm
linkend="widget">widget</glossterm> within its <glossterm
linkend="parent">parent</glossterm>. For example, a widget
may request a minimum size of 20&times;20 pixels, but its
parent may decide to allocate 50&times;20 pixels for it
instead.
</para>
<glossseealso>
<glossterm linkend="requisition">requisition</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="bin">
<glossterm>bin</glossterm>
<glossdef>
<para>
A <glossterm linkend="container">container</glossterm> that
can hold at most one child widget. The base class for bins is
#GtkBin.
</para>
<glossseealso>
<glossterm linkend="container">container</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="child">
<glossterm>child</glossterm>
<glossdef>
<para>
A <glossterm linkend="container">container's</glossterm> child
is a <glossterm linkend="widget">widget</glossterm> contained
inside it.
</para>
</glossdef>
</glossentry>
<glossentry id="column">
<glossterm>column</glossterm>
<glossdef>
<para>
GTK contains several widgets which display data in columns,
e.g. the #GtkTreeView.
These <glossterm linkend="view-column">view columns</glossterm> in
the tree view are represented by #GtkTreeViewColumn
objects inside GTK. They should not be confused with
<glossterm linkend="model-column">model columns</glossterm> which
are used to organize the data in tree models.
</para>
<glossseealso>model-view widget</glossseealso>
</glossdef>
</glossentry>
<glossentry id="container">
<glossterm>container</glossterm>
<glossdef>
<para>
A <glossterm linkend="widget">widget</glossterm> that contains
other widgets; in that case, the container is the
<emphasis>parent</emphasis> of the <emphasis>child</emphasis>
widgets. Some containers don't draw anything on their own,
but rather just organize their children's <glossterm
linkend="geometry">geometry</glossterm>; for example, #GtkVBox lays out
its children vertically without painting anything on its own. Other
containers include decorative elements; for example, #GtkFrame contains
the frame's child and a label in addition to the shaded frame it draws.
The base class for containers is #GtkContainer.
</para>
<glossseealso>
<glossterm linkend="container">widget</glossterm>
<glossterm linkend="container">geometry</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="display">
<glossterm>display</glossterm>
<glossdef>
<para>
GDK inherited the concept of display from the X window system,
which considers a display to be the combination
of a keyboard, a pointing device and one or more
<glossterm linkend="screen">screens</glossterm>.
Applications open a display to show windows and interact with the user.
In GDK, a display is represented by a #GdkDisplay.
</para>
</glossdef>
</glossentry>
<glossentry id="ellipsization">
<glossdef>
<para>
Ellipsization is the process of replacing some part
of a text by an ellipsis (usually "...") to make the
text fit in a smaller space. Pango can ellipsize text
at the beginning, at the end or in the middle.
</para>
</glossdef>
</glossentry>
<glossentry id="event">
<glossterm>event</glossterm>
<glossdef>
<para>
Events are the way in which GDK informs GTK about external events
like pointer motion, button clicks, key presses, etc.
</para>
</glossdef>
</glossentry>
<glossentry id="geometry">
<glossterm>geometry</glossterm>
<glossdef>
<para>
A <glossterm linkend="widget">widget's</glossterm> position
and size. Within its parent, this is called the widget's
<glossterm linkend="allocation">allocation</glossterm>.
</para>
</glossdef>
</glossentry>
<glossentry id="mapping">
<glossterm>mapping</glossterm>
<glossdef>
<para>
This is the step in a <glossterm
linkend="widget">widget's</glossterm> life cycle where it
actually shows the GdkSurfaces it created when it was
<glossterm linkend="realization">realized</glossterm>. When a
widget is mapped, it must turn on its
%GTK_MAPPED <link linkend="GtkWidgetFlags">flag</link>.
</para>
<para>
Note that due to the asynchronous nature of the X window
system, a widget's window may not appear on the screen
immediatly after one calls gdk_surface_show():
you must wait for the corresponding map <glossterm
linkend="event">event</glossterm> to be received. You can do
this with the <link
linkend="GtkWidget-map-event"><methodname>GtkWidget::map-event</methodname>
signal</link>.
</para>
</glossdef>
</glossentry>
<glossentry id="model-column">
<glossterm>model column</glossterm>
<glossdef>
<para>
A column in a tree model, holding data of a certain type.
The types which can be stored in the columns of a model
have to be specified when the model is constructed, see
e.g. gtk_list_store_new().
</para>
<glossseealso>
<glossterm linkend="view-column">view column</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="model-view">
<glossterm>model-view widget</glossterm>
<glossdef>
<para>
These widgets follow the well-known model-view pattern, which separates
the data (the model) to be displayed from the component which does the
actual visualization (the view). Examples of this pattern in GTK are
the #GtkTreeView/#GtkTreeModel and #GtkTextView/#GtkTextBuffer
</para>
<para>
One important advantage of this pattern is that it is possible to
display the same model in multiple views; another one that the
separation of the model allows a great deal of flexibility, as
demonstrated by e.g. #GtkTreeModelSort or #GtkTreeModelFilter.
</para>
</glossdef>
</glossentry>
<glossentry id="no-window">
<glossterm>no-window widget</glossterm>
<glossdef>
<para>
A widget that does not have a GdkSurface of its own on which to
draw its contents, but rather shares its <glossterm
linkend="parent">parent's</glossterm>. This can be tested with
the gtk_widget_get_has_surface() function.
</para>
</glossdef>
</glossentry>
<glossentry id="parent">
<glossterm>parent</glossterm>
<glossdef>
<para>
A <glossterm linkend="widget">widget's</glossterm> parent is
the <glossterm linkend="container">container</glossterm>
inside which it resides.
</para>
</glossdef>
</glossentry>
<glossentry id="realization">
<glossterm>realization</glossterm>
<glossdef>
<para>
This is the step in a <glossterm
linkend="widget">widget's</glossterm> life cycle where it
creates its own GdkSurface, or otherwise associates itself with
its <glossterm linkend="parent">parent's</glossterm>
GdkSurface. If the widget has its own window, then it must
also attach a <glossterm linkend="style">style</glossterm> to
it. A widget becomes unrealized by destroying its associated
GdkSurface. When a widget is realized, it must turn on its
%GTK_REALIZED <link linkend="GtkWidgetFlags">flag</link>.
</para>
<para>
Widgets that don't own the GdkSurface on which they draw are
called <glossterm linkend="no-window">no-window widgets</glossterm>.
This can be tested with the gtk_widget_get_has_surface() function. Normally,
these widgets draw on their parent's GdkSurface.
</para>
<para>
Note that when a #GtkWidget creates a window in its #GtkWidget::realize
handler, it does not actually show the window. That is, the
window's structure is just created in memory. The widget
actually shows the window when it gets <glossterm
linkend="mapping">mapped</glossterm>.
</para>
</glossdef>
</glossentry>
<glossentry id="requisition">
<glossterm>requisition</glossterm>
<glossdef>
<para>
The size requisition of a <glossterm
linkend="widget">widget</glossterm> is the minimum amount of
space it requests from its <glossterm
linkend="parent">parent</glossterm>. Once the parent computes
the widget's final size, it gives it its <glossterm
linkend="allocation">size allocation</glossterm>.
</para>
<glossseealso>
<glossterm linkend="allocation">allocation</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="screen">
<glossterm>screen</glossterm>
<glossdef>
<para>
GDK inherited the concept of screen from the X window system,
which considers a screen to be a rectangular area, on which
applications may place their windows. Screens under X may have
quite dissimilar <glossterm linkend="visual">visuals</glossterm>.
Each screen can stretch across multiple physical monitors.
</para>
<para>
In GDK, screens are represented by #GdkScreen objects.
</para>
</glossdef>
</glossentry>
<glossentry id="style">
<glossterm>style</glossterm>
<glossdef>
<para>
A style encapsulates what GTK needs to know in order to draw
a widget. Styles can be modified with
<link linkend="gtk3-Resource-Files">resource files</link>.
</para>
</glossdef>
</glossentry>
<glossentry id="toplevel">
<glossterm>toplevel</glossterm>
<glossdef>
<para>
A <glossterm linkend="widget">widget</glossterm> that does not
require a <glossterm linkend="parent">parent</glossterm> container.
The only toplevel widgets in GTK are #GtkWindow and widgets derived from it.
</para>
<glossseealso>
<glossterm linkend="container">container</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="unmap">
<glossterm>unmap</glossterm>
<glosssee><glossterm linkend="mapping">mapping</glossterm></glosssee>
</glossentry>
<glossentry id="unrealize">
<glossterm>unrealize</glossterm>
<glosssee><glossterm linkend="realization">realization</glossterm></glosssee>
</glossentry>
<glossentry id="view-column">
<glossterm>view column</glossterm>
<glossdef>
<para>
A displayed column in a tree view, represented by a
#GtkTreeViewColumn object.
</para>
<glossseealso>
<glossterm linkend="model-column">model column</glossterm>
</glossseealso>
</glossdef>
</glossentry>
<glossentry id="visual">
<glossterm>visual</glossterm>
<glossdef>
<para>
A visual describes how color information is stored in pixels.
A <glossterm linkend="screen">screen</glossterm> may support
multiple visuals. On modern hardware, the most common visuals
are truecolor visuals, which store a fixed number of bits
(typically 8) for the red, green and blue components of a color.
</para>
<para>
On ancient hardware, one may still meet indexed visuals, which
store color information as an index into a color map, or even
monochrome visuals.
</para>
</glossdef>
</glossentry>
<glossentry id="widget">
<glossterm>widget</glossterm>
<glossdef>
<para>
A control in a graphical user interface. Widgets can draw
themselves and process events from the mouse and keyboard.
Widget types include buttons, menus, text entry lines, and
lists. Widgets can be arranged into <glossterm
linkend="container">containers</glossterm>, and these take
care of assigning the <glossterm
linkend="geometry">geometry</glossterm> of the widgets: every
widget thus has a parent except those widgets which are
<glossterm linkend="toplevel">toplevels</glossterm>. The base
class for widgets is #GtkWidget.
</para>
<glossseealso>
<glossterm linkend="container">container</glossterm>
</glossseealso>
</glossdef>
</glossentry>
</glossary>

View File

@@ -1,192 +0,0 @@
#!/usr/bin/python3
#
# Call pandoc to convert markdown to docbook, then expand gtk-doc
# abbreviations (|[ ]|, function(), #object, %constant, etc)
import sys
import re
import tempfile
import os.path
import subprocess
# The following code is taken from gtk-doc
def ExpandAbbreviations(symbol, text):
# Convert '@param()'
text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)', r'\1<parameter>\2()</parameter>', text)
# Convert 'function()' or 'macro()'.
# if there is abc_*_def() we don't want to make a link to _def()
# FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
def f1(m):
return m.group(1) + MakeXRef(m.group(2), tagify(m.group(2) + "()", "function"))
text = re.sub(r'([^\*.\w])(\w+)\s*\(\)', f1, text)
# handle #Object.func()
text = re.sub(r'(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)', f1, text)
# Convert '@param', but not '\@param'.
text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)', r'\1<parameter>\2</parameter>', text)
text = re.sub(r'/\\\@', r'\@', text)
# Convert '%constant', but not '\%constant'.
# Also allow negative numbers, e.g. %-1.
def f2(m):
return m.group(1) + MakeXRef(m.group(2), tagify(m.group(2), "literal"))
text = re.sub(r'(\A|[^\\])\%(-?\w+)', f2, text)
text = re.sub(r'\\\%', r'\%', text)
# Convert '#symbol', but not '\#symbol'.
# Only convert #foo after a space to avoid interfering with
# fragment identifiers in urls
def f3(m):
return m.group(1) + MakeHashXRef(m.group(2), "type")
text = re.sub(r'(\A|[ ])#([\w\-:\.]+[\w]+)', f3, text)
text = re.sub(r'\\#', '#', text)
return text
# Standard C preprocessor directives, which we ignore for '#' abbreviations.
PreProcessorDirectives = {
'assert', 'define', 'elif', 'else', 'endif', 'error', 'if', 'ifdef', 'ifndef',
'include', 'line', 'pragma', 'unassert', 'undef', 'warning'
}
def MakeHashXRef(symbol, tag):
text = symbol
# Check for things like '#include', '#define', and skip them.
if symbol in PreProcessorDirectives:
return "#%s" % symbol
# Get rid of special suffixes ('-struct','-enum').
text = re.sub(r'-struct$', '', text)
text = re.sub(r'-enum$', '', text)
# If the symbol is in the form "Object::signal", then change the symbol to
# "Object-signal" and use "signal" as the text.
if '::' in symbol:
o, s = symbol.split('::', 1)
symbol = '%s-%s' % (o, s)
text = u'“' + s + u'”'
# If the symbol is in the form "Object:property", then change the symbol to
# "Object--property" and use "property" as the text.
if ':' in symbol:
o, p = symbol.split(':', 1)
symbol = '%s--%s' % (o, p)
text = u'“' + p + u'”'
if tag != '':
text = tagify(text, tag)
return MakeXRef(symbol, text)
def MakeXRef(symbol, text=None):
"""This returns a cross-reference link to the given symbol.
Though it doesn't try to do this for a few standard C types that it knows
won't be in the documentation.
Args:
symbol (str): the symbol to try to create a XRef to.
text (str): text to put inside the XRef, defaults to symbol
Returns:
str: a docbook link
"""
symbol = symbol.strip()
if not text:
text = symbol
# Get rid of special suffixes ('-struct','-enum').
text = re.sub(r'-struct$', '', text)
text = re.sub(r'-enum$', '', text)
if ' ' in symbol:
return text
symbol_id = CreateValidSGMLID(symbol)
return "<link linkend=\"%s\">%s</link>" % (symbol_id, text)
def CreateValidSGMLID(xml_id):
"""Creates a valid SGML 'id' from the given string.
According to http://www.w3.org/TR/html4/types.html#type-id "ID and NAME
tokens must begin with a letter ([A-Za-z]) and may be followed by any number
of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"),
and periods (".")."
When creating SGML IDS, we append ":CAPS" to all all-caps identifiers to
prevent name clashes (SGML ids are case-insensitive). (It basically never is
the case that mixed-case identifiers would collide.)
Args:
id (str): The text to be converted into a valid SGML id.
Returns:
str: The converted id.
"""
# Special case, '_' would end up as '' so we use 'gettext-macro' instead.
if xml_id == '_':
return "gettext-macro"
xml_id = re.sub(r'[,;]', '', xml_id)
xml_id = re.sub(r'[_ ]', '-', xml_id)
xml_id = re.sub(r'^-+', '', xml_id)
xml_id = xml_id.replace('::', '-')
xml_id = xml_id.replace(':', '--')
# Append ":CAPS" to all all-caps identifiers
# FIXME: there are some inconsistencies here, we have index files containing e.g. TRUE--CAPS
if xml_id.isupper() and not xml_id.endswith('-CAPS'):
xml_id += ':CAPS'
return xml_id
def tagify(text, elem):
# Adds a tag around some text.
# e.g tagify("Text", "literal") => "<literal>Text</literal>".
return '<' + elem + '>' + text + '</' + elem + '>'
# End of gtk-doc excerpts
MarkdownExtensions = {
'-auto_identifiers', # we use explicit identifiers where needed
'+header_attributes', # for explicit identifiers
'+blank_before_header', # helps with gtk-doc #Object abbreviations
'+compact_definition_lists', # to replace <variablelist>
'+pipe_tables',
'+backtick_code_blocks', # to replace |[ ]|
'+fenced_code_attributes', # to add language annotations
'-raw_html', # to escape literal tags like <child> in input
'+startnum', # to have interrupted lists in the q&a part
}
def ConvertToDocbook(infile, outfile):
basename = os.path.basename(infile)
if basename.startswith('section'):
division='section'
else:
division='chapter'
input_format = "markdown" + "".join(MarkdownExtensions)
output_format = "docbook"
subprocess.check_call(["pandoc", infile, "-o", outfile,
"--from=" + input_format,
"--to=" + output_format,
"--top-level-division=" + division])
def ExpandGtkDocAbbreviations(infile, outfile):
contents = open(infile, 'r', encoding='utf-8').read()
with open(outfile, 'w', encoding='utf-8') as out:
out.write(ExpandAbbreviations("file", contents))
if __name__ == '__main__':
tmp = tempfile.mktemp()
ConvertToDocbook(sys.argv[1], tmp)
ExpandGtkDocAbbreviations(tmp, sys.argv[2])
os.remove(tmp)

View File

@@ -6,7 +6,7 @@
<!ENTITY pi "&#960;">
<!ENTITY solidus "&#8260;">
]>
<book xmlns="http://docbook.org/ns/docbook" id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
<bookinfo>
<title>GTK 4 Reference Manual</title>
<releaseinfo>
@@ -21,16 +21,16 @@
<part id="gtk">
<title>Introduction</title>
<xi:include href="overview.xml"/>
<xi:include href="getting_started.xml"/>
<xi:include href="xml/getting_started.xml"/>
<xi:include href="resources.xml" />
<xi:include href="question_index.xml" />
<xi:include href="xml/question_index.xml" />
</part>
<part id="concepts">
<title>GTK Concepts</title>
<xi:include href="drawing-model.xml" />
<xi:include href="input-handling.xml" />
<xi:include href="actions.xml" />
<xi:include href="xml/drawing-model.xml" />
<xi:include href="xml/input-handling.xml" />
<xi:include href="xml/actions.xml" />
</part>
<part id="gtkobjects">
@@ -48,59 +48,19 @@
<chapter id="Lists">
<title>GListModel support</title>
<xi:include href="xml/gtkexpression.xml" />
<xi:include href="xml/gtkfilterlistmodel.xml" />
<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" />
</section>
<xi:include href="xml/gtkflattenlistmodel.xml" />
<xi:include href="xml/gtkmaplistmodel.xml" />
<xi:include href="xml/gtkslicelistmodel.xml" />
<xi:include href="xml/gtksortlistmodel.xml" />
<section>
<xi:include href="xml/gtksorter.xml" />
<xi:include href="xml/gtkcustomsorter.xml" />
<xi:include href="xml/gtkstringsorter.xml" />
<xi:include href="xml/gtknumericsorter.xml" />
<xi:include href="xml/gtkmultisorter.xml" />
</section>
<xi:include href="xml/gtkselectionmodel.xml" />
<section>
<xi:include href="xml/gtknoselection.xml" />
<xi:include href="xml/gtksingleselection.xml" />
<xi:include href="xml/gtkmultiselection.xml" />
<xi:include href="xml/gtkpropertyselection.xml" />
</section>
<xi:include href="xml/gtkdirectorylist.xml" />
</chapter>
<chapter id="ListContainers">
<title>List-based Widgets</title>
<xi:include href="section-list-widget.xml"/>
<xi:include href="xml/gtklistitem.xml" />
<xi:include href="xml/gtklistitemfactory.xml" />
<section>
<xi:include href="xml/gtksignallistitemfactory.xml" />
<xi:include href="xml/gtkbuilderlistitemfactory.xml" />
</section>
<xi:include href="xml/gtklistview.xml" />
<xi:include href="xml/gtkgridview.xml" />
<xi:include href="xml/gtkcolumnview.xml" />
<xi:include href="xml/gtkcolumnviewcolumn.xml" />
<xi:include href="xml/gtkdropdown.xml" />
<xi:include href="xml/gtknoselection.xml" />
<xi:include href="xml/gtksingleselection.xml" />
</chapter>
<chapter id="Trees">
<title>Tree support</title>
<xi:include href="xml/gtktreelistrow.xml" />
<xi:include href="xml/gtktreelistmodel.xml" />
<section>
<xi:include href="xml/gtktreelistrow.xml" />
</section>
<xi:include href="xml/gtktreelistrowsorter.xml" />
<xi:include href="xml/gtktreeexpander.xml" />
</chapter>
<chapter id="Application">
@@ -127,7 +87,6 @@
<xi:include href="xml/gtkaboutdialog.xml" />
<xi:include href="xml/gtkassistant.xml" />
<xi:include href="xml/gtkwindowgroup.xml" />
<xi:include href="xml/gtknativedialog.xml" />
</chapter>
<chapter id="LayoutContainers">
@@ -161,7 +120,6 @@
<xi:include href="xml/gtkcenterlayout.xml" />
<xi:include href="xml/gtkfixedlayout.xml" />
<xi:include href="xml/gtkgridlayout.xml" />
<xi:include href="xml/gtkoverlaylayout.xml" />
<xi:include href="xml/gtkcustomlayout.xml" />
<xi:include href="xml/gtkconstraintlayout.xml" />
<xi:include href="xml/gtkconstraint.xml" />
@@ -220,7 +178,7 @@
<chapter id="TextWidgetObjects">
<title>Multiline Text Editor</title>
<xi:include href="section-text-widget.xml" />
<xi:include href="xml/text_widget.xml" />
<xi:include href="xml/gtktextiter.xml" />
<xi:include href="xml/gtktextmark.xml" />
<xi:include href="xml/gtktextbuffer.xml" />
@@ -231,7 +189,7 @@
<chapter id="TreeWidgetObjects">
<title>Tree, List and Icon Grid Widgets</title>
<xi:include href="section-tree-widget.xml" />
<xi:include href="xml/tree_widget.xml" />
<xi:include href="xml/gtktreemodel.xml" />
<xi:include href="xml/gtktreeselection.xml" />
<xi:include href="xml/gtktreeviewcolumn.xml" />
@@ -267,7 +225,6 @@
<xi:include href="xml/gtkpopover.xml" />
<xi:include href="xml/gtkpopovermenu.xml" />
<xi:include href="xml/gtkpopovermenubar.xml" />
<xi:include href="xml/gtkdropdown.xml" />
</chapter>
<chapter id="SelectorWidgets">
@@ -421,7 +378,6 @@
<part id="theming">
<title>Theming in GTK</title>
<xi:include href="css-overview.xml" />
<xi:include href="css-properties.xml" />
<xi:include href="xml/gtkstylecontext.xml" />
<xi:include href="xml/gtkcssprovider.xml" />
<xi:include href="xml/gtkstyleprovider.xml" />
@@ -441,8 +397,8 @@
</para>
</partintro>
<xi:include href="migrating-2to4.xml" />
<xi:include href="migrating-3to4.xml" />
<xi:include href="xml/migrating-2to4.xml" />
<xi:include href="xml/migrating-3to4.xml" />
</part>
<part>
@@ -462,7 +418,7 @@
<part id="platform-support">
<title>GTK Platform Support</title>
<xi:include href="building.xml" />
<xi:include href="compiling.xml" />
<xi:include href="xml/compiling.xml" />
<xi:include href="running.xml" />
<xi:include href="x11.xml" />
<xi:include href="windows.xml" />
@@ -471,6 +427,8 @@
<xi:include href="wayland.xml" />
</part>
<xi:include href="glossary.xml" />
<index id="api-index-full">
<title>Index of all symbols</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>

View File

@@ -350,9 +350,6 @@ gtk_selection_model_select_range
gtk_selection_model_unselect_range
gtk_selection_model_select_all
gtk_selection_model_unselect_all
GtkSelectionCallback
gtk_selection_model_select_callback
gtk_selection_model_unselect_callback
gtk_selection_model_query_range
<SUBSECTION>
gtk_selection_model_selection_changed
@@ -395,219 +392,6 @@ gtk_single_selection_set_can_unselect
gtk_single_selection_get_type
</SECTION>
<SECTION>
<FILE>gtkmultiselection</FILE>
<TITLE>GtkMultiSeledction</TITLE>
GtkMultiSelection
gtk_multi_selection_new
<SUBSECTION Private>
gtk_multi_selection_get_type
</SECTION>
<SECTION>
<FILE>gtkpropertyselection</FILE>
<TITLE>GtkPropertySelection</TITLE>
GtkPropertySelection
gtk_property_selection_new
<SUBSECTION Private>
gtk_property_selection_get_type
</SECTION>
<SECTION>
<FILE>gtklistitem</FILE>
<TITLE>GtkListItem</TITLE>
GtkListItem
gtk_list_item_get_item
gtk_list_item_get_position
gtk_list_item_get_child
gtk_list_item_set_child
gtk_list_item_get_selected
gtk_list_item_get_selectable
gtk_list_item_set_selectable
<SUBSECTION Standard>
GTK_LIST_ITEM
GTK_LIST_ITEM_CLASS
GTK_LIST_ITEM_GET_CLASS
GTK_IS_LIST_ITEM
GTK_IS_LIST_ITEM_CLASS
GTK_TYPE_LIST_ITEM
<SUBSECTION Private>
gtk_list_item_get_type
</SECTION>
<SECTION>
<FILE>gtklistitemfactory</FILE>
<TITLE>GtkListItemFactory</TITLE>
GtkListItemFactory
<SUBSECTION Standard>
GTK_LIST_ITEM_FACTORY
GTK_LIST_ITEM_FACTORY_CLASS
GTK_LIST_ITEM_FACTORY_GET_CLASS
GTK_IS_LIST_ITEM_FACTORY
GTK_IS_LIST_ITEM_FACTORY_CLASS
GTK_TYPE_LIST_ITEM_FACTORY
<SUBSECTION Private>
gtk_list_item_factory_get_type
</SECTION>
<SECTION>
<FILE>gtkbuilderlistitemfactory</FILE>
<TITLE>GtkBuilderListItemFactory</TITLE>
GtkBuilderListItemFactory
gtk_builder_list_item_factory_new_from_bytes
gtk_builder_list_item_factory_new_from_resource
gtk_builder_list_item_factory_get_bytes
gtk_builder_list_item_factory_get_resource
gtk_builder_list_item_factory_get_scope
<SUBSECTION Standard>
GTK_BUILDER_LIST_ITEM_FACTORY
GTK_BUILDER_LIST_ITEM_FACTORY_CLASS
GTK_BUILDER_LIST_ITEM_FACTORY_GET_CLASS
GTK_IS_BUILDER_LIST_ITEM_FACTORY
GTK_IS_BUILDER_LIST_ITEM_FACTORY_CLASS
GTK_TYPE_BUILDER_LIST_ITEM_FACTORY
<SUBSECTION Private>
gtk_builder_list_item_factory_get_type
</SECTION>
<SECTION>
<FILE>gtksignallistitemfactory</FILE>
<TITLE>GtkSignalListItemFactory</TITLE>
GtkSignalListItemFactory
gtk_signal_list_item_factory_new
<SUBSECTION Standard>
GTK_SIGNAL_LIST_ITEM_FACTORY
GTK_SIGNAL_LIST_ITEM_FACTORY_CLASS
GTK_SIGNAL_LIST_ITEM_FACTORY_GET_CLASS
GTK_IS_SIGNAL_LIST_ITEM_FACTORY
GTK_IS_SIGNAL_LIST_ITEM_FACTORY_CLASS
GTK_TYPE_SIGNAL_LIST_ITEM_FACTORY
<SUBSECTION Private>
gtk_signal_list_item_factory_get_type
</SECTION>
<SECTION>
<FILE>gtklistview</FILE>
<TITLE>GtkListView</TITLE>
GtkListView
gtk_list_view_new
gtk_list_view_new_with_factory
gtk_list_view_set_factory
gtk_list_view_get_factory
gtk_list_view_set_model
gtk_list_view_get_model
gtk_list_view_set_show_separators
gtk_list_view_get_show_separators
gtk_list_view_set_single_click_activate
gtk_list_view_get_single_click_activate
gtk_list_view_set_enable_rubberband
gtk_list_view_get_enable_rubberband
<SUBSECTION Standard>
GTK_LIST_VIEW
GTK_LIST_VIEW_CLASS
GTK_LIST_VIEW_GET_CLASS
GTK_IS_LIST_VIEW
GTK_IS_LIST_VIEW_CLASS
GTK_TYPE_LIST_VIEW
<SUBSECTION Private>
gtk_list_view_get_type
</SECTION>
<SECTION>
<FILE>gtkcolumnview</FILE>
<TITLE>GtkColumnView</TITLE>
GtkColumnView
gtk_column_view_new
gtk_column_view_append_column
gtk_column_view_insert_column
gtk_column_view_remove_column
gtk_column_view_get_columns
gtk_column_view_get_model
gtk_column_view_set_model
gtk_column_view_get_sorter
gtk_column_view_get_show_row_separators
gtk_column_view_set_show_row_separators
gtk_column_view_get_show_column_separators
gtk_column_view_set_show_column_separators
gtk_column_view_sort_by_column
gtk_column_view_set_single_click_activate
gtk_column_view_get_single_click_activate
gtk_column_view_set_reorderable
gtk_column_view_get_reorderable
gtk_column_view_set_enable_rubberband
gtk_column_view_get_enable_rubberband
<SUBSECTION Standard>
GTK_COLUMN_VIEW
GTK_COLUMN_VIEW_CLASS
GTK_COLUMN_VIEW_GET_CLASS
GTK_IS_COLUMN_VIEW
GTK_IS_COLUMN_VIEW_CLASS
GTK_TYPE_COLUMN_VIEW
<SUBSECTION Private>
gtk_column_view_get_type
</SECTION>
<SECTION>
<FILE>gtkcolumnviewcolumn</FILE>
<TITLE>GtkColumnViewColumn</TITLE>
GtkColumnViewColumn
gtk_column_view_column_new
gtk_column_view_column_new_with_factory
gtk_column_view_column_get_column_view
gtk_column_view_column_set_factory
gtk_column_view_column_get_factory
gtk_column_view_column_set_title
gtk_column_view_column_get_title
gtk_column_view_column_set_sorter
gtk_column_view_column_get_sorter
gtk_column_view_column_set_visible
gtk_column_view_column_get_visible
gtk_column_view_column_set_resizable
gtk_column_view_column_get_resizable
gtk_column_view_column_set_header_menu
gtk_column_view_column_get_header_menu
gtk_column_view_column_set_fixed_width
gtk_column_view_column_get_fixed_width
gtk_column_view_column_set_expand
gtk_column_view_column_get_expand
<SUBSECTION Standard>
GTK_COLUMN_VIEW_COLUMN
GTK_COLUMN_VIEW_COLUMN_CLASS
GTK_COLUMN_VIEW_COLUMN_GET_CLASS
GTK_IS_COLUMN_VIEW_COLUMN
GTK_IS_COLUMN_VIEW_COLUMN_CLASS
GTK_TYPE_COLUMN_VIEW_COLUMN
<SUBSECTION Private>
gtk_column_view_column_get_type
</SECTION>
<SECTION>
<FILE>gtkgridview</FILE>
<TITLE>GtkGridView</TITLE>
GtkGridView
gtk_grid_view_new
gtk_grid_view_set_model
gtk_grid_view_get_model
gtk_grid_view_set_max_columns
gtk_grid_view_get_max_columns
gtk_grid_view_set_min_columns
gtk_grid_view_get_min_columns
gtk_grid_view_set_single_click_activate
gtk_grid_view_get_single_click_activate
gtk_grid_view_set_enable_rubberband
gtk_grid_view_get_enable_rubberband
<SUBSECTION Standard>
GTK_GRID_VIEW
GTK_GRID_VIEW_CLASS
GTK_GRID_VIEW_GET_CLASS
GTK_IS_GRID_VIEW
GTK_IS_GRID_VIEW_CLASS
GTK_TYPE_GRID_VIEW
<SUBSECTION Private>
gtk_grid_view_get_type
</SECTION>
<SECTION>
<FILE>gtkbuildable</FILE>
GtkBuildable
@@ -1376,102 +1160,18 @@ GTK_TYPE_FILE_FILTER
gtk_file_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkdirectorylist</FILE>
<TITLE>GtkDirectoryList</TITLE>
GtkDirectoryList
gtk_directory_list_new
gtk_directory_list_get_attributes
gtk_directory_list_set_attributes
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_is_loading
gtk_directory_list_get_error
<SUBSECTION Standard>
GTK_DIRECTORY_LIST
GTK_IS_DIRECTORY_LIST
GTK_TYPE_DIRECTORY_LIST
GTK_DIRECTORY_LIST_CLASS
GTK_IS_DIRECTORY_LIST_CLASS
GTK_DIRECTORY_LIST_GET_CLASS
<SUBSECTION Private>
gtk_directory_list_get_type
</SECTION>
<SECTION>
<FILE>gtkfilter</FILE>
<TITLE>GtkFilter</TITLE>
GtkFilter
gtk_filter_match
gtk_filter_get_strictness
<SUBSECTION>
GtkFilterChange
gtk_filter_changed
<SUBSECTION>
gtk_custom_filter_new
<SUBSECTION Standard>
GTK_FILTER
GTK_IS_FILTER
GTK_TYPE_FILTER
GTK_FILTER_CLASS
GTK_IS_FILTER_CLASS
GTK_FILTER_GET_CLASS
<SUBSECTION Private>
gtk_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkcustomfilter</FILE>
<TITLE>GtkCustomFilter</TITLE>
GtkCustomFilter
GtkCustomFilterFunc
gtk_custom_filter_new
<SUBSECTION Standard>
GTK_CUSTOM_FILTER
GTK_IS_CUSTOM_FILTER
GTK_TYPE_CUSTOM_FILTER
GTK_CUSTOM_FILTER_CLASS
GTK_IS_CUSTOM_FILTER_CLASS
GTK_CUSTOM_FILTER_GET_CLASS
<SUBSECTION Private>
gtk_custom_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkmultifilter</FILE>
<TITLE>GtkMultiFilter</TITLE>
GtkMultiFilter
gtk_multi_filter_append
gtk_multi_filter_remove
<SUBSECTION>
GtkAnyFilter
gtk_any_filter_new
<SUBSECTION>
GtkEveryFilter
gtk_every_filter_new
<SUBSECTION Standard>
GTK_CUSTOM_FILTER
GTK_IS_CUSTOM_FILTER
GTK_TYPE_CUSTOM_FILTER
GTK_CUSTOM_FILTER_CLASS
GTK_IS_CUSTOM_FILTER_CLASS
GTK_CUSTOM_FILTER_GET_CLASS
<SUBSECTION Private>
gtk_custom_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkfilterlistmodel</FILE>
<TITLE>GtkFilterListModel</TITLE>
GtkFilterListModel
GtkFilterListModelFilterFunc
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_filter_func
gtk_filter_list_model_has_filter
gtk_filter_list_model_refilter
<SUBSECTION Standard>
GTK_FILTER_LIST_MODEL
GTK_IS_FILTER_LIST_MODEL
@@ -1786,7 +1486,6 @@ GtkIMContext
GtkIMContextClass
gtk_im_context_get_preedit_string
gtk_im_context_filter_keypress
gtk_im_context_filter_key
gtk_im_context_focus_in
gtk_im_context_focus_out
gtk_im_context_reset
@@ -2055,7 +1754,7 @@ gtk_info_bar_get_type
<SECTION>
<FILE>gtknativedialog</FILE>
<TITLE>GtkNativeDialog</TITLE>
GtkNativeDialog
GTK_TYPE_NATIVE_DIALOG
GtkNativeDialogClass
gtk_native_dialog_show
gtk_native_dialog_hide
@@ -2067,8 +1766,9 @@ gtk_native_dialog_set_title
gtk_native_dialog_get_title
gtk_native_dialog_set_transient_for
gtk_native_dialog_get_transient_for
<SUBSECTION Standard>
GtkNativeDialog
<SUBSECTION Private>
GTK_TYPE_NATIVE_DIALOG
gtk_native_dialog_get_type
</SECTION>
@@ -2142,18 +1842,12 @@ GtkNotebookPrivate
<TITLE>GtkPaned</TITLE>
GtkPaned
gtk_paned_new
gtk_paned_set_start_child
gtk_paned_get_start_child
gtk_paned_set_end_child
gtk_paned_get_end_child
gtk_paned_set_resize_start_child
gtk_paned_get_resize_start_child
gtk_paned_set_resize_end_child
gtk_paned_get_resize_end_child
gtk_paned_set_shrink_start_child
gtk_paned_get_shrink_start_child
gtk_paned_set_shrink_end_child
gtk_paned_get_shrink_end_child
gtk_paned_add1
gtk_paned_add2
gtk_paned_pack1
gtk_paned_pack2
gtk_paned_get_child1
gtk_paned_get_child2
gtk_paned_set_position
gtk_paned_get_position
gtk_paned_set_wide_handle
@@ -2641,123 +2335,17 @@ GTK_SLICE_LIST_MODEL_GET_CLASS
gtk_slice_list_model_get_type
</SECTION>
<SECTION>
<FILE>gtksorter</FILE>
<TITLE>GtkSorter</TITLE>
GtkSorter
GtkSorterOrder
GtkSorterChange
gtk_sorter_compare
gtk_sorter_get_order
gtk_sorter_changed
<SUBSECTION Standard>
GTK_SORTER
GTK_IS_SORTER
GTK_TYPE_SORTER
GTK_SORTER_CLASS
GTK_IS_SORTER_CLASS
GTK_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtkstringsorter</FILE>
<TITLE>GtkStringSorter</TITLE>
GtkStringSorter
gtk_string_sorter_new
gtk_string_sorter_get_expression
gtk_string_sorter_set_expression
gtk_string_sorter_get_ignore_case
gtk_string_sorter_set_ignore_case
<SUBSECTION Standard>
GTK_STRING_SORTER
GTK_IS_STRING_SORTER
GTK_TYPE_STRING_SORTER
GTK_IS_STRING_SORTER_CLASS
GTK_STRING_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_string_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtknumericsorter</FILE>
<TITLE>GtkNumericSorter</TITLE>
GtkNumericSorter
gtk_numeric_sorter_new
gtk_numeric_sorter_get_expression
gtk_numeric_sorter_set_expression
gtk_numeric_sorter_get_sort_order
gtk_numeric_sorter_set_sort_order
<SUBSECTION Standard>
GTK_NUMERIC_SORTER
GTK_IS_NUMERIC_SORTER
GTK_TYPE_NUMERIC_SORTER
GTK_IS_NUMERIC_SORTER_CLASS
GTK_NUMERIC_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_numeric_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtkcustomsorter</FILE>
<TITLE>GtkCustomSorter</TITLE>
GtkCustomSorter
gtk_custom_sorter_new
<SUBSECTION Standard>
GTK_CUSTOM_SORTER
GTK_IS_CUSTOM_SORTER
GTK_TYPE_CUSTOM_SORTER
GTK_IS_CUSTOM_SORTER_CLASS
GTK_CUSTOM_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_custom_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtkmultisorter</FILE>
<TITLE>GtkMultiSorter</TITLE>
GtkMultiSorter
gtk_multi_sorter_new
gtk_multi_sorter_append
gtk_multi_sorter_remove
<SUBSECTION Standard>
GTK_MULTI_SORTER
GTK_IS_MULTI_SORTER
GTK_TYPE_MULTI_SORTER
GTK_IS_MULTI_SORTER_CLASS
GTK_MULTI_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_multi_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtktreelistrowsorter</FILE>
<TITLE>GtkTreeListRowSorter</TITLE>
GtkTreeListRowSorter
gtk_tree_list_row_sorter_new
gtk_tree_list_row_sorter_get_sorter
gtk_tree_list_row_sorter_set_sorter
<SUBSECTION Standard>
GTK_TREE_LIST_ROW_SORTER
GTK_IS_TREE_LIST_ROW_SORTER
GTK_TYPE_TREE_LIST_ROW_SORTER
GTK_IS_TREE_LIST_ROW_SORTER_CLASS
GTK_TREE_LIST_ROW_SORTER_GET_CLASS
<SUBSECTION Private>
gtk_tree_list_row_sorter_get_type
</SECTION>
<SECTION>
<FILE>gtksortlistmodel</FILE>
<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_sort_func
gtk_sort_list_model_has_sort
gtk_sort_list_model_set_model
gtk_sort_list_model_get_model
gtk_sort_list_model_resort
<SUBSECTION Standard>
GTK_SORT_LIST_MODEL
GTK_IS_SORT_LIST_MODEL
@@ -3343,26 +2931,6 @@ GTK_TREE_LIST_MODEL_GET_CLASS
gtk_tree_list_row_get_type
</SECTION>
<SECTION>
<FILE>gtktreeexpander</FILE>
<TITLE>GtkTreeExpander</TITLE>
gtk_tree_expander_new
gtk_tree_expander_get_child
gtk_tree_expander_set_child
gtk_tree_expander_get_item
gtk_tree_expander_get_list_row
gtk_tree_expander_set_list_row
<SUBSECTION Standard>
GTK_TREE_EXPANDER
GTK_IS_TREE_EXPANDER
GTK_TYPE_TREE_EXPANDER
GTK_TREE_EXPANDER_CLASS
GTK_IS_TREE_EXPANDER_CLASS
GTK_TREE_EXPANDER_GET_CLASS
<SUBSECTION Private>
gtk_tree_expander_get_type
</SECTION>
<SECTION>
<FILE>gtktreemodel</FILE>
<TITLE>GtkTreeModel</TITLE>
@@ -4442,7 +4010,6 @@ gtk_widget_get_allocation
gtk_widget_get_allocated_baseline
gtk_widget_get_width
gtk_widget_get_height
gtk_widget_get_size
gtk_widget_compute_bounds
gtk_widget_compute_transform
gtk_widget_compute_point
@@ -4984,8 +4551,6 @@ GtkDeleteType
GtkDirectionType
GtkJustification
GtkMovementStep
GtkOrdering
gtk_ordering_from_cmpfunc
GtkOrientation
GtkPackType
GtkPositionType
@@ -5615,6 +5180,9 @@ gtk_application_inhibit
gtk_application_uninhibit
<SUBSECTION>
gtk_application_prefers_app_menu
gtk_application_get_app_menu
gtk_application_set_app_menu
gtk_application_get_menubar
gtk_application_set_menubar
gtk_application_get_menu_by_id
@@ -7418,99 +6986,3 @@ GTK_EMOJI_CHOOSER_GET_CLASS
<SUBSECTION Private>
gtk_emoji_chooser_get_type
</SECTION>
<SECTION>
<FILE>gtkoverlaylayout</FILE>
GtkOverlayLayout
gtk_overlay_layout_new
<SUBSECTION>
GtkOverlayLayoutChild
gtk_overlay_layout_child_set_measure
gtk_overlay_layout_child_get_measure
gtk_overlay_layout_child_set_clip_overlay
gtk_overlay_layout_child_get_clip_overlay
<SUBSECTION Private>
GTK_TYPE_OVERLAY_LAYOUT
gtk_overlay_layout_get_type
GTK_TYPE_OVERLAY_LAYOUT_CHLD
gtk_overlay_layout_child_get_type
</SECTION>
<SECTION>
<FILE>gtkexpression</FILE>
GtkExpression
GtkExpressionWatch
GtkExpressionNotify
gtk_expression_ref
gtk_expression_unref
gtk_expression_get_value_type
gtk_expression_is_static
gtk_expression_evaluate
gtk_expression_watch
gtk_expression_bind
gtk_expression_watch_ref
gtk_expression_watch_unref
gtk_expression_watch_evaluate
gtk_expression_watch_unwatch
<SUBSECTION>
gtk_property_expression_new
gtk_property_expression_new_for_pspec
gtk_constant_expression_new
gtk_constant_expression_new_for_value
gtk_object_expression_new
gtk_closure_expression_new
gtk_cclosure_expression_new
<SUBSECTION Standard>
GTK_IS_EXPRESSION
GTK_TYPE_EXPRESSION
<SUBSECTION Private>
gtk_expression_get_type
</SECTION>
<SECTION>
<FILE>gtkstringfilter</FILE>
GtkStringFilter
GtkStringFilterMatchMode
gtk_string_filter_new
gtk_string_filter_get_search
gtk_string_filter_set_search
gtk_string_filter_get_expression
gtk_string_filter_set_expression
gtk_string_filter_get_ignore_case
gtk_string_filter_set_ignore_case
gtk_string_filter_get_match_mode
gtk_string_filter_set_match_mode
<SUBSECTION Private>
gtk_string_filter_get_type
</SECTION>
<SECTION>
<FILE>gtkdropdown</FILE>
<TITLE>GtkDropDown</TITLE>
GtkDropDown
gtk_drop_down_new
gtk_drop_down_set_from_strings
gtk_drop_down_set_model
gtk_drop_down_get_model
gtk_drop_down_set_selected
gtk_drop_down_get_selected
gtk_drop_down_set_factory
gtk_drop_down_get_factory
gtk_drop_down_set_list_factory
gtk_drop_down_get_list_factory
gtk_drop_down_set_expression
gtk_drop_down_get_expression
gtk_drop_down_set_enable_search
gtk_drop_down_get_enable_search
<SUBSECTION Standard>
GTK_TYPE_DROP_DOWN
<SUBSECTION Private>
gtk_drop_down_get_type
</SECTION>

View File

@@ -7,7 +7,6 @@ gtk_accessible_get_type
gtk_actionable_get_type
gtk_action_bar_get_type
gtk_adjustment_get_type
gtk_any_filter_get_type
gtk_app_chooser_get_type
gtk_app_chooser_button_get_type
gtk_app_chooser_dialog_get_type
@@ -20,11 +19,10 @@ gtk_assistant_page_get_type
gtk_bin_layout_get_type
gtk_box_get_type
gtk_box_layout_get_type
gtk_buildable_get_type
gtk_builder_cscope_get_type
gtk_builder_get_type
gtk_builder_list_item_factory_get_type
gtk_builder_scope_get_type
gtk_buildable_get_type
gtk_button_get_type
gtk_calendar_get_type
gtk_cell_area_get_type
@@ -48,8 +46,6 @@ gtk_color_button_get_type
gtk_color_chooser_get_type
gtk_color_chooser_dialog_get_type
gtk_color_chooser_widget_get_type
gtk_column_view_get_type
gtk_column_view_column_get_type
gtk_combo_box_get_type
gtk_combo_box_text_get_type
gtk_constraint_get_type
@@ -57,16 +53,12 @@ gtk_constraint_guide_get_type
gtk_constraint_layout_get_type
gtk_constraint_target_get_type
gtk_css_provider_get_type
gtk_custom_filter_get_type
gtk_custom_sorter_get_type
gtk_dialog_get_type
gtk_directory_list_get_type
gtk_drag_icon_get_type
gtk_drag_source_get_type
gtk_drawing_area_get_type
gtk_drop_target_get_type
gtk_drop_target_async_get_type
gtk_drop_down_get_type
gtk_editable_get_type
gtk_emoji_chooser_get_type
gtk_entry_buffer_get_type
@@ -78,14 +70,12 @@ gtk_event_controller_focus_get_type
gtk_event_controller_legacy_get_type
gtk_event_controller_motion_get_type
gtk_event_controller_scroll_get_type
gtk_every_filter_get_type
gtk_expander_get_type
gtk_file_chooser_button_get_type
gtk_file_chooser_dialog_get_type
gtk_file_chooser_get_type
gtk_file_chooser_widget_get_type
gtk_file_filter_get_type
gtk_filter_get_type
gtk_filter_list_model_get_type
gtk_fixed_get_type
gtk_fixed_layout_get_type
@@ -111,7 +101,6 @@ gtk_gl_area_get_type
gtk_grid_get_type
gtk_grid_layout_child_get_type
gtk_grid_layout_get_type
gtk_grid_view_get_type
gtk_header_bar_get_type
gtk_icon_theme_get_type
gtk_icon_view_get_type
@@ -124,12 +113,9 @@ gtk_label_get_type
gtk_layout_child_get_type
gtk_layout_manager_get_type
gtk_link_button_get_type
gtk_list_item_get_type
gtk_list_item_factory_get_type
gtk_list_store_get_type
gtk_list_box_get_type
gtk_list_box_row_get_type
gtk_list_view_get_type
gtk_lock_button_get_type
gtk_map_list_model_get_type
gtk_media_controls_get_type
@@ -138,19 +124,13 @@ gtk_media_stream_get_type
gtk_menu_button_get_type
gtk_message_dialog_get_type
gtk_mount_operation_get_type
gtk_multi_filter_get_type
gtk_multi_selection_get_type
gtk_multi_sorter_get_type
gtk_native_get_type
gtk_native_dialog_get_type
gtk_no_selection_get_type
gtk_notebook_get_type
gtk_notebook_page_get_type
gtk_numeric_sorter_get_type
gtk_orientable_get_type
gtk_overlay_get_type
gtk_overlay_layout_get_type
gtk_overlay_layout_child_get_type
gtk_pad_controller_get_type
gtk_page_setup_get_type
@DISABLE_ON_W32@gtk_page_setup_unix_dialog_get_type
@@ -169,7 +149,6 @@ gtk_print_operation_preview_get_type
gtk_print_settings_get_type
@DISABLE_ON_W32@gtk_print_unix_dialog_get_type
gtk_progress_bar_get_type
gtk_property_selection_get_type
gtk_radio_button_get_type
gtk_range_get_type
gtk_recent_manager_get_type
@@ -193,13 +172,11 @@ gtk_shortcuts_window_get_type
gtk_shortcuts_section_get_type
gtk_shortcuts_group_get_type
gtk_shortcuts_shortcut_get_type
gtk_signal_list_item_factory_get_type
gtk_single_selection_get_type
gtk_size_group_get_type
gtk_slice_list_model_get_type
gtk_snapshot_get_type
gtk_sort_list_model_get_type
gtk_sorter_get_type
gtk_spin_button_get_type
gtk_spinner_get_type
gtk_stack_get_type
@@ -207,8 +184,6 @@ gtk_stack_page_get_type
gtk_stack_sidebar_get_type
gtk_stack_switcher_get_type
gtk_statusbar_get_type
gtk_string_filter_get_type
gtk_string_sorter_get_type
gtk_switch_get_type
gtk_level_bar_get_type
gtk_style_context_get_type
@@ -226,7 +201,6 @@ gtk_tree_drag_dest_get_type
gtk_tree_drag_source_get_type
gtk_tree_list_model_get_type
gtk_tree_list_row_get_type
gtk_tree_list_row_sorter_get_type
gtk_tree_model_filter_get_type
gtk_tree_model_get_type
gtk_tree_model_sort_get_type

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -1,206 +0,0 @@
# Overview of GTK input and event handling {#input-overview}
This chapter describes in detail how GTK handles input. If you are interested
in what happens to translate a key press or mouse motion of the users into a
change of a GTK widget, you should read this chapter. This knowledge will also
be useful if you decide to implement your own widgets.
Devices and events
The most basic input devices that every computer user has interacted with are
keyboards and mice; beyond these, GTK supports touchpads, touchscreens and
more exotic input devices such as graphics tablets. Inside GTK, every such
input device is represented by a #GdkDevice object.
To simplify dealing with the variability between these input devices, GTK
has a concept of master and slave devices. The concrete physical devices that
have many different characteristics (mice may have 2 or 3 or 8 buttons,
keyboards have different layouts and may or may not have a separate number
block, etc) are represented as slave devices. Each slave device is
associated with a virtual master device. Master devices always come in
pointer/keyboard pairs - you can think of such a pair as a 'seat'.
GTK widgets generally deal with the master devices, and thus can be used
with any pointing device or keyboard.
When a user interacts with an input device (e.g. moves a mouse or presses
a key on the keyboard), GTK receives events from the windowing system.
These are typically directed at a specific surface - for pointer events,
the surface under the pointer (grabs complicate this), for keyboard events,
the surface with the keyboard focus.
GDK translates these raw windowing system events into #GdkEvents.
Typical input events are button clicks, pointer motion, key presses
or touch events. These are all represented as #GdkEvents, but you can
differentiate between different events by looking at their type, using
gdk_event_get_event_type().
Some events, such as touch events or button press-release pairs,
are connected in to each other in an “event sequence” that
univocally identifies events that are related to the same
interaction.
When GTK creates a GdkSurface, it connects to the #GdkSurface::event
signal on it, which receives all of these input events. Surfaces have
have signals and properties, e.g. to deal with window management
related events.
## Event propagation {#event-propagation}
The function which initially receives input events on the GTK
side is responsible for a number of tasks.
1. Find the widget which got the event.
2. Generate crossing (i.e. enter and leave) events when the focus or
hover location change from one widget to another.
3. Send the event to widgets.
An event is propagated down and up the widget hierarchy in three phases
(see #GtkPropagationPhase) towards a target widget.
![Event propagation phases](capture-bubble.png)
For key events, the top-level window gets a first shot at activating
mnemonics and accelerators. If that does not consume the events,
the target widget for event propagation is window's current focus
widget (see gtk_window_get_focus()).
For pointer events, the target widget is determined by picking
the widget at the events coordinates (see gtk_window_pick()).
In the first phase (the “capture” phase) the event is delivered to
each widget from the top-most (the top-level #GtkWindow or grab widget)
down to the target #GtkWidget.
[Event controllers](event-controllers-and-gestures) that are attached
with %GTK_PHASE_CAPTURE get a chance to react to the event.
After the “capture” phase, the widget that was intended to be the
destination of the event will run event controllers attached to
it with %GTK_PHASE_TARGET. This is known as the “target” phase,
and only happens on that widget.
In the last phase (the “bubble” phase), the event is delivered
to each widget from the target to the top-most, and event
controllers attached with %GTK_PHASE_BUBBLE are run.
Events are not delivered to a widget which is insensitive or unmapped.
Any time during the propagation phase, a controller may indicate
that a received event was consumed and propagation should
therefore be stopped. If gestures are used, this may happen
when the gesture claims the event touch sequence (or the
pointer events) for its own. See the “gesture states” section
below to learn more about gestures and sequences.
## Keyboard input
Every #GtkWindow maintains a single focus location (in
the #GtkWindow:focus-widget property). The focus widget is the
target widget for key events sent to the window. Only widgets which
have #GtkWidget:can-focus set to %TRUE can become the focus. Typically
these are input controls such as entries or text fields, but e.g.
buttons can take the focus too.
Input widgets can be given the focus by clicking on them, but focus
can also be moved around with certain key events (this is known as
“keyboard navigation”). GTK reserves the Tab key to move the focus
to the next location, and Shift-Tab to move it back to the previous
one. In addition many containers allow “directional navigation” with
the arrow keys.
Many widgets can be “activated” to trigger and action. E.g., you can
activate a button or switch by clicking on them, but you can also
activate them with the keyboard, by using the Enter or Space keys.
Apart from keyboard navigation, activation and directly typing into
entries or text views, GTK widgets can use key events for activating
“shortcuts”. Shortcuts generally act as a quick way to move the focus
around or to activate a widget that does not currently have the focus.
GTK has traditionally supported different kinds of shortcuts:
Accelerators
: Accelerators are any other shortcuts that can be activated regardless
of where the focus is, and typically trigger global actions, such as
Ctrl-Q to quit an application.
Mnmemonics
: Mnemonics are usually triggered using Alt as a modifier for a letter.
They are used in places where a label is associated with a control,
and are indicated by underlining the letter in the label. As a special
case, inside menus (i.e. inside #GtkPopoverMenu), mnemonics can be
trigered without the modifier.
Key bindings
: Key bindings are specific to individual widgets, such as Ctrl-C or
Ctrl-V in an entry copy to or paste from the clipboard. They are only
triggered when the widget has focus.
GTK handles accelerators and mnemonics in a global scope, during the
capture phase, and key bindings locally, during the target phase.
Under the hood, all shortcuts are represented as instances of #GtkShortcut,
and they are managed by #GtkShortcutController.
## Event controllers and gestures {#event-controllers-and-gestures}
Event controllers are standalone objects that can perform
specific actions upon received #GdkEvents. These are tied
to a #GtkWidget, and can be told of the event propagation
phase at which they will manage the events.
Gestures are a set of specific controllers that are prepared
to handle pointer and/or touch events, each gesture
implementation attempts to recognize specific actions out the
received events, notifying of the state/progress accordingly to
let the widget react to those. On multi-touch gestures, every
interacting touch sequence will be tracked independently.
Since gestures are “simple” units, it is not uncommon to tie
several together to perform higher level actions, grouped
gestures handle the same event sequences simultaneously, and
those sequences share a same state across all grouped
gestures. Some examples of grouping may be:
- A “drag” and a “swipe” gestures may want grouping.
The former will report events as the dragging happens,
the latter will tell the swipe X/Y velocities only after
recognition has finished.
- Grouping a “drag” gesture with a “pan” gesture will only
effectively allow dragging in the panning orientation, as
both gestures share state.
- If “press” and “long press” are wanted simultaneously,
those would need grouping.
Shortcuts are handled by #GtkShortcutController, which is
a complex event handler that can either activate shortcuts
itself, or propagate them to another controller, depending
on its #GtkShortcutController:scope.
## Gesture states
Gestures have a notion of “state” for each individual touch
sequence. When events from a touch sequence are first received,
the touch sequence will have “none” state, this means the touch
sequence is being handled by the gesture to possibly trigger
actions, but the event propagation will not be stopped.
When the gesture enters recognition, or at a later point in time,
the widget may choose to claim the touch sequences (individually
or as a group), hence stopping event propagation after the event
is run through every gesture in that widget and propagation phase.
Anytime this happens, the touch sequences are cancelled downwards
the propagation chain, to let these know that no further events
will be sent.
Alternatively, or at a later point in time, the widget may choose
to deny the touch sequences, thus letting those go through again
in event propagation. When this happens in the capture phase, and
if there are no other claiming gestures in the widget,
a %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS event will be emulated and
propagated downwards, in order to preserve consistency.
Grouped gestures always share the same state for a given touch
sequence, so setting the state on one does transfer the state to
the others. They also are mutually exclusive, within a widget
where may be only one gesture group claiming a given sequence.
If another gesture group claims later that same sequence, the
first group will deny the sequence:

View File

@@ -0,0 +1,332 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="chap-input-handling">
<refmeta>
<refentrytitle>The GTK Input Model</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>The GTK Input Model</refname>
<refpurpose>
input and event handling in detail
</refpurpose>
</refnamediv>
<refsect1 id="input-overview">
<title>Overview of GTK input and event handling</title>
<para>
This chapter describes in detail how GTK handles input. If you are interested
in what happens to translate a key press or mouse motion of the users into a
change of a GTK widget, you should read this chapter. This knowledge will also
be useful if you decide to implement your own widgets.
</para>
<refsect2>
<title>Devices and events</title>
<!-- input devices: master/slave, keyboard/pointer/touch -->
<para>
The most basic input devices that every computer user has interacted with are
keyboards and mice; beyond these, GTK supports touchpads, touchscreens and
more exotic input devices such as graphics tablets. Inside GTK, every such
input device is represented by a #GdkDevice object.
</para>
<para>
To simplify dealing with the variability between these input devices, GTK
has a concept of master and slave devices. The concrete physical devices that
have many different characteristics (mice may have 2 or 3 or 8 buttons,
keyboards have different layouts and may or may not have a separate number
block, etc) are represented as slave devices. Each slave device is
associated with a virtual master device. Master devices always come in
pointer/keyboard pairs - you can think of such a pair as a 'seat'.
</para>
<para>
GTK widgets generally deal with the master devices, and thus can be used
with any pointing device or keyboard.
</para>
<para>
When a user interacts with an input device (e.g. moves a mouse or presses
a key on the keyboard), GTK receives events from the windowing system.
These are typically directed at a specific surface - for pointer events,
the surface under the pointer (grabs complicate this), for keyboard events,
the surface with the keyboard focus.
</para>
<para>
GDK translates these raw windowing system events into #GdkEvents.
Typical input events are button clicks, pointer motion, key presses
or touch events. These are all represented as #GdkEvents, but you can
differentiate between different events by looking at their type, using
gdk_event_get_event_type().
</para>
<para>
Some events, such as touch events or button press-release pairs,
are connected in to each other in an “event sequence” that
univocally identifies events that are related to the same
interaction.
</para>
<para>
When GTK creates a GdkSurface, it connects to the #GdkSurface::event
signal on it, which receives all of these input events. Surfaces have
have signals and properties, e.g. to deal with window management
related events.
</para>
</refsect2>
<refsect2 id="event-propagation">
<title>Event propagation</title>
<para>
The function which initially receives input events on the GTK
side is responsible for a number of tasks.
</para>
<orderedlist>
<listitem><para>
Find the widget which got the event.
</para></listitem>
<listitem><para>
Generate crossing (i.e. enter and leave) events when the focus or hover
location change from one widget to another.
</para></listitem>
<listitem><para>
The event is sent to widgets.
</para></listitem>
</orderedlist>
<para>
An event is propagated down and up the widget hierarchy in three phases
(see #GtkPropagationPhase) towards a target widget.
</para>
<informalfigure>
<mediaobject>
<imageobject>
<imagedata fileref="capture-bubble.png" format="PNG"/>
</imageobject>
</mediaobject>
</informalfigure>
<para>
For key events, the top-level window gets a first shot at activating
mnemonics and accelerators. If that does not consume the events,
the target widget for event propagation is window's current focus
widget (see gtk_window_get_focus()).
</para>
<para>
For pointer events, the target widget is determined by picking
the widget at the events coordinates (see gtk_window_pick()).
</para>
<para>In the first phase (the “capture” phase) the event is
delivered to each widget from the top-most (the top-level
#GtkWindow or grab widget) down to the target #GtkWidget.
<link linkend="event-controllers-and-gestures">Event
controllers</link> that are attached with %GTK_PHASE_CAPTURE
get a chance to react to the event.
</para>
<para>
After the “capture” phase, the widget that was intended to be the
destination of the event will run event controllers attached to
it with %GTK_PHASE_TARGET. This is known as the “target” phase,
and only happens on that widget.
</para>
<para>
In the last phase (the “bubble” phase), the event is delivered
to each widget from the target to the top-most, and event
controllers attached with %GTK_PHASE_BUBBLE are run.
</para>
<para>
Events are not delivered to a widget which is insensitive or
unmapped.
</para>
<para>
Any time during the propagation phase, a controller may indicate
that a received event was consumed and propagation should
therefore be stopped. If gestures are used, this may happen
when the gesture claims the event touch sequence (or the
pointer events) for its own. See the “gesture states” section
below to learn more about gestures and sequences.
</para>
</refsect2>
<refsect2>
<title>Keyboard input</title>
<para>
Every #GtkWindow maintains a single focus location (in the
#GtkWindow:focus-widget property). The focus widget is the target
widget for key events sent to the window. Only widgets which have
#GtkWidget:can-focus set to %TRUE can become the focus. Typically
these are input controls such as entries or text fields, but e.g.
buttons can take the focus too.
</para>
<para>
Input widgets can be given the focus by clicking on them, but focus
can also be moved around with certain key events (this is known as
“keyboard navigation”). GTK reserves the Tab key to move the focus
to the next location, and Shift-Tab to move it back to the previous
one. In addition many containers allow “directional navigation” with
the arrow keys.
</para>
<para>
Many widgets can be “activated” to trigger and action. E.g., you can
activate a button or switch by clicking on them, but you can also
activate them with the keyboard, by using the Enter or Space keys.
</para>
<para>
Apart from keyboard navigation, activation and directly typing into
entries or text views, GTK widgets can use key events for activating
“shortcuts”. Shortcuts generally act as a quick way to move the focus
around or to activate a widget that does not currently have the focus.
</para>
<para>
GTK has traditionally supported different kinds of shortcuts:
<variablelist>
<varlistentry>
<term>Accelerators</term>
<listitem><para>
Accelerators are any other shortcuts that can be activated regardless
of where the focus is, and typically trigger global actions, such as
Ctrl-Q to quit an application.
</para></listitem>
</varlistentry>
<varlistentry>
<term>Mnmemonics</term>
<listitem><para>
Mnemonics are usually triggered using Alt as a modifier for a letter.
They are used in places where a label is associated with a control,
and are indicated by underlining the letter in the label. As a special
case, inside menus (i.e. inside #GtkPopoverMenu), mnemonics can be
trigered without the modifier.
</para></listitem>
</varlistentry>
<varlistentry>
<term>Key bindings</term>
<listitem><para>
Key bindings are specific to individual widgets, such as Ctrl-C or
Ctrl-V in an entry copy to or paste from the clipboard. They are only
triggered when the widget has focus.
</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>
GTK traditionally handles accelerators and mnemonics in a global scope,
during the capture phase, and key bindings locally, during the target phase.
</para>
<para>
Under the hood, all shortcuts are represented as instances of #GtkShortcut,
and they are managed by #GtkShortcutController.
</para>
</refsect2>
<refsect2 id="event-controllers-and-gestures">
<title>Event controllers and gestures</title>
<para>
Event controllers are standalone objects that can perform
specific actions upon received #GdkEvents. These are tied
to a #GtkWidget, and can be told of the event propagation
phase at which they will manage the events.
</para>
<para>
Gestures are a set of specific controllers that are prepared
to handle pointer and/or touch events, each gesture
implementation attempts to recognize specific actions out the
received events, notifying of the state/progress accordingly to
let the widget react to those. On multi-touch gestures, every
interacting touch sequence will be tracked independently.
</para>
<para>
Since gestures are “simple” units, it is not uncommon to tie
several together to perform higher level actions, grouped
gestures handle the same event sequences simultaneously, and
those sequences share a same state across all grouped
gestures. Some examples of grouping may be:
<simplelist>
<member>
A “drag” and a “swipe” gestures may want grouping.
The former will report events as the dragging happens,
the latter will tell the swipe X/Y velocities only after
recognition has finished.
</member>
<member>
Grouping a “drag” gesture with a “pan” gesture will only
effectively allow dragging in the panning orientation, as
both gestures share state.
</member>
<member>
If “press” and “long press” are wanted simultaneously,
those would need grouping.
</member>
</simplelist>
</para>
<para>
Shortcuts are handled by #GtkShortcutController, which is
a complex event handler that can either activate shortcuts
itself, or propagate them to another controller, depending
on its #GtkShortcutController:scope.
</para>
</refsect2>
<refsect2>
<title>Gesture states</title>
<para>
Gestures have a notion of “state” for each individual touch
sequence. When events from a touch sequence are first received,
the touch sequence will have “none” state, this means the touch
sequence is being handled by the gesture to possibly trigger
actions, but the event propagation will not be stopped.
</para>
<para>
When the gesture enters recognition, or at a later point in time,
the widget may choose to claim the touch sequences (individually
or as a group), hence stopping event propagation after the event
is run through every gesture in that widget and propagation phase.
Anytime this happens, the touch sequences are cancelled downwards
the propagation chain, to let these know that no further events
will be sent.
</para>
<para>
Alternatively, or at a later point in time, the widget may choose
to deny the touch sequences, thus letting those go through again
in event propagation. When this happens in the capture phase, and
if there are no other claiming gestures in the widget,
a %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS event will be emulated and
propagated downwards, in order to preserve consistency.
</para>
<para>
Grouped gestures always share the same state for a given touch
sequence, so setting the state on one does transfer the state to
the others. They also are mutually exclusive, within a widget
there may be only one gesture group claiming a given sequence.
If another gesture group claims later that same sequence, the
first group will deny the sequence.
</para>
</refsect2>
</refsect1>
</refentry>

View File

@@ -1,5 +1,3 @@
fs = import('fs')
private_headers = [
'imm-extra.h',
'gtkbitmaskprivateimpl.h',
@@ -13,7 +11,6 @@ private_headers = [
'gtkappchooserprivate.h',
'gtkapplicationaccelsprivate.h',
'gtkapplicationprivate.h',
'gtkarrayimplprivate.h',
'gtkbindingsprivate.h',
'gtkbitmaskprivate.h',
'gtkbuilderprivate.h',
@@ -25,13 +22,6 @@ private_headers = [
'gtkcolorplaneprivate.h',
'gtkcolorscaleprivate.h',
'gtkcolorswatchprivate.h',
'gtkcolumnlistitemfactoryprivate.h',
'gtkcolumnviewcellprivate.h',
'gtkcolumnviewcolumnprivate.h',
'gtkcolumnviewlayoutprivate.h',
'gtkcolumnviewprivate.h',
'gtkcolumnviewsorterprivate.h',
'gtkcolumnviewtitleprivate.h',
'gtkcomboboxprivate.h',
'gtkconstraintexpressionprivate.h',
'gtkconstraintguideprivate.h',
@@ -140,23 +130,15 @@ private_headers = [
'gtkimmoduleprivate.h',
'gtkkineticscrollingprivate.h',
'gtklabelprivate.h',
'gtklistbaseprivate.h',
'gtklistitemprivate.h',
'gtklistitemfactoryprivate.h',
'gtklistitemmanagerprivate.h',
'gtklistitemwidgetprivate.h',
'gtklockbuttonprivate.h',
'gtkmagnifierprivate.h',
'gtkmediafileprivate.h',
'gtkmenubuttonprivate.h',
'gtkmenusectionboxprivate.h',
'gtkmenutrackeritemprivate.h',
'gtkmenutrackerprivate.h',
'gtkmodulesprivate.h',
'gtkmountoperationprivate.h',
'gtknativedialogprivate.h',
'gtknomediafileprivate.h',
'gtkpango.h',
'gtkorientableprivate.h',
'gtkplacessidebarprivate.h',
'gtkplacesviewprivate.h',
'gtkplacesviewrowprivate.h',
@@ -166,7 +148,6 @@ private_headers = [
'gtkprintoperation-private.h',
'gtkprivate.h',
'gtkprogresstrackerprivate.h',
'gtkquery.h',
'gtkrangeprivate.h',
'gtkrbtreeprivate.h',
'gtkrenderbackgroundprivate.h',
@@ -176,9 +157,7 @@ private_headers = [
'gtkroundedboxprivate.h',
'gtkscalerprivate.h',
'gtksearchentryprivate.h',
'gtkset.h',
'gtksettingsprivate.h',
'gtkshortcutcontrollerprivate.h',
'gtkshortcutsshortcutprivate.h',
'gtkshortcutswindowprivate.h',
'gtksidebarrowprivate.h',
@@ -205,9 +184,7 @@ private_headers = [
'gtktoolbarprivate.h',
'gtktooltipprivate.h',
'gtktooltipwindowprivate.h',
'gtktreepopoverprivate.h',
'gtktreeprivate.h',
'gtktreerbtreeprivate.h',
'gtkutilsprivate.h',
'gtkwidgetpaintableprivate.h',
'gtkwidgetpathprivate.h',
@@ -361,6 +338,13 @@ images = [
]
content_files = [
'actions.xml',
'broadway.xml',
'building.xml',
'compiling.xml',
'css-overview.xml',
'drawing-model.xml',
'glossary.xml',
'gtk4-broadwayd.xml',
'gtk4-builder-tool.xml',
'gtk4-demo-application.xml',
@@ -371,32 +355,34 @@ content_files = [
'gtk4-query-settings.xml',
'gtk4-update-icon-cache.xml',
'gtk4-widget-factory.xml',
'input-handling.xml',
'migrating-2to4.xml',
'migrating-3to4.xml',
'osx.xml',
'other_software.xml',
'overview.xml',
'question_index.xml',
'resources.xml',
'running.xml',
'text_widget.xml',
'tree_widget.xml',
'visual_index.xml',
'wayland.xml',
'windows.xml',
'x11.xml',
]
expand_content_md_files = [
'broadway.md',
'osx.md',
'wayland.md',
'windows.md',
'x11.md',
'getting_started.md',
'resources.md',
'building.md',
'compiling.md',
'running.md',
'migrating-2to4.md',
'migrating-3to4.md',
'actions.md',
'input-handling.md',
'drawing-model.md',
'css-overview.md',
'css-properties.md',
'section-text-widget.md',
'section-tree-widget.md',
'section-list-widget.md',
'question_index.md',
expand_content_files = [
'actions.xml',
'compiling.xml',
'drawing-model.xml',
'glossary.xml',
'input-handling.xml',
'migrating-2to4.xml',
'migrating-3to4.xml',
'question_index.xml',
'text_widget.xml',
'tree_widget.xml',
]
types_conf = configuration_data()
@@ -414,17 +400,7 @@ endif
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
# gtk-markdown-to-docbook uses pandoc
pandoc = find_program('pandoc', required: true)
expand_md = find_program('gtk-markdown-to-docbook')
expand_md_targets = []
foreach t : expand_content_md_files
expand_md_targets += custom_target(t,
input: [ t ],
output: [ fs.replace_suffix(t, '.xml') ],
command: [ expand_md, '@INPUT@', '@OUTPUT@'])
endforeach
configure_file(input: 'getting_started.xml.in', output: 'getting_started.xml', configuration: src_dir_conf)
gnome.gtkdoc('gtk4',
mode: 'none',
@@ -455,7 +431,8 @@ if get_option('gtk_doc')
'--extra-dir=../gdk',
'--extra-dir=../gsk',
],
content_files: content_files + expand_md_targets,
content_files: content_files,
expand_content_files: expand_content_files,
html_assets: images,
install: true)
endif

View File

@@ -1,5 +0,0 @@
# Migrating from GTK 2.x to GTK 4 {#gtk-migrating-2-to-4}
If your application is still using GTK 2, you should first convert it to GTK 3,
by following the [migration guide](https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html)
in the GTK 3 documentation, and then follow [these instructions](#gtk-migrating-3-to-4).

View File

@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<chapter id="gtk-migrating-2-to-4">
<title>Migrating from GTK 2.x to GTK 4</title>
<para>
If your application is still using GTK 2, you should first convert it to
GTK 3, by following the <ulink url="https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html">migration guide</ulink> in the GTK 3
documentation, and then follow <xref linkend="gtk-migrating-3-to-4"/>.
</para>
</chapter>

View File

@@ -1,942 +0,0 @@
# Migrating from GTK 3.x to GTK 4 {#gtk-migrating-3-to-4}
GTK 4 is a major new version of GTK that breaks both API and ABI
compared to GTK 3.x. Thankfully, most of the changes are not hard
to adapt to and there are a number of steps that you can take to
prepare your GTK 3.x application for the switch to GTK 4. After
that, there's a number of adjustments that you may have to do
when you actually switch your application to build against GTK 4.
## Preparation in GTK 3.x
The steps outlined in the following sections assume that your
application is working with GTK 3.24, which is the final stable
release of GTK 3.x. It includes all the necessary APIs and tools
to help you port your application to GTK 4. If you are using
an older version of GTK 3.x, you should first get your application
to build and work with the latest minor release in the 3.24 series.
### Do not use deprecated symbols
Over the years, a number of functions, and in some cases, entire
widgets have been deprecated. These deprecations are clearly spelled
out in the API reference, with hints about the recommended replacements.
The API reference for GTK 3 also includes an
[index](https://developer.gnome.org/gtk3/3.24/api-index-deprecated.html)
of all deprecated symbols.
To verify that your program does not use any deprecated symbols,
you can use defines to remove deprecated symbols from the header files,
as follows:
```
make CFLAGS+="-DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
```
Note that some parts of our API, such as enumeration values, are
not well covered by the deprecation warnings. In most cases, using
them will require you to also use deprecated functions, which will
trigger warnings.
### Enable diagnostic warnings
Deprecations of properties and signals cannot be caught at compile
time, as both properties and signals are installed and used after
types have been instantiated. In order to catch deprecations and
changes in the run time components, you should use the
`G_ENABLE_DIAGNOSTIC` environment variable when running your
application, e.g.:
```
G_ENABLE_DIAGNOSTIC=1 ./your-app
```
### Do not use widget style properties
Style properties do not exist in GTK 4. You should stop using them in
your custom CSS and in your code.
### Review your window creation flags
GTK 4 removes the `GDK_WA_CURSOR` flag. Instead, just use
gdk_window_set_cursor() to set a cursor on the window after
creating it. GTK 4 also removes the `GDK_WA_VISUAL` flag, and
always uses an RGBA visual for windows. To prepare your code for
this, use `gdk_window_set_visual (gdk_screen_get_rgba_visual ())`
after creating your window. GTK 4 also removes the `GDK_WA_WMCLASS`
flag. If you need this X11-specific functionality, use XSetClassHint()
directly.
### Stop using direct access to GdkEvent structs
In GTK 4, event structs are opaque and immutable. Many fields already
have accessors in GTK 3, and you should use those to reduce the amount
of porting work you have to do at the time of the switch.
### Stop using gdk_pointer_warp()
Warping the pointer is disorienting and unfriendly to users.
GTK 4 does not support it. In special circumstances (such as when
implementing remote connection UIs) it can be necessary to
warp the pointer; in this case, use platform APIs such as
XWarpPointer() directly.
### Stop using non-RGBA visuals
GTK 4 always uses RGBA visuals for its windows; you should make
sure that your code works with such visuals. At the same time,
you should stop using GdkVisual APIs, since this object not longer
exists in GTK 4. Most of its APIs are deprecated already and not
useful when dealing with RGBA visuals.
### Stop using GtkBox padding, fill and expand child properties
GTK 4 removes these #GtkBox child properties, so you should stop using
them. You can replace GtkBox:padding using the #GtkWidget:margin properties
on your #GtkBox child widgets.
The fill child property can be replaced by setting appropriate values
for the #GtkWidget:halign and #GtkWidget:valign properties of the child
widgets. If you previously set the fill child property to %TRUE, you can
achieve the same effect by setting the halign or valign properties to
%GTK_ALIGN_FILL, depending on the parent box -- halign for a horizontal
box, valign for a vertical one.
\#GtkBox also uses the expand child property. It can be replaced by setting
#GtkWidget:hexpand or #GtkWidget:vexpand on the child widgets. To match the
old behavior of the #GtkBox's expand child property, you need to set
#GtkWidget:hexpand on the child widgets of a horizontal #GtkBox and
#GtkWidget:vexpand on the child widgets of a vertical #GtkBox.
Note that there's a subtle but important difference between #GtkBox's
expand and fill child properties and the ones in #GtkWidget: setting
#GtkWidget:hexpand or #GtkWidget:vexpand to %TRUE will propagate up
the widget hierarchy, so a pixel-perfect port might require you to reset
the expansion flags to %FALSE in a parent widget higher up the hierarchy.
### Stop using the state argument of GtkStyleContext getters
The getters in the GtkStyleContext API, such as
gtk_style_context_get_property(), gtk_style_context_get(),
or gtk_style_context_get_color() only accept the context's current
state for their state argument. You should update all callers to pass
the current state.
### Stop using gdk_pixbuf_get_from_window() and gdk_cairo_set_source_surface()
These functions are not supported in GTK 4. Instead, either use
backend-specific APIs, or render your widgets using
#GtkWidgetClass.snapshot() (once you are using GTK 4).
Stop using GtkButton's image-related API
The functions and properties related to automatically add a GtkImage
to a GtkButton, and using a GtkSetting to control its visibility, are
not supported in GTK 4. Instead, you can just pack a GtkImage inside
a GtkButton, and control its visibility like you would for any other
widget. If you only want to add a named icon to a GtkButton, you can
use gtk_button_new_from_icon_name().
### Stop using GtkWidget event signals
Event controllers and #GtkGestures replace event signals in GTK 4.
They have been backported to GTK 3.x so you can prepare for this change.
### Set a proper application ID
In GTK 4 we want the application's #GApplication 'application-id'
(and therefore the D-Bus name), the desktop file basename and Wayland's
xdg-shell app_id to match. In order to achieve this with GTK 3.x call
g_set_prgname() with the same application ID you passed to #GtkApplication.
Rename your desktop files to match the application ID if needed.
The call to g_set_prgname() can be removed once you fully migrated to GTK 4.
You should be aware that changing the application ID makes your
application appear as a new, different app to application installers.
You should consult the appstream documentation for best practices
around renaming applications.
### Stop using gtk_main() and related APIs
GTK 4 removes the gtk_main_ family of APIs. The recommended replacement
is GtkApplication, but you can also iterate the GLib mainloop directly,
using GMainContext APIs. The replacement for gtk_events_pending() is
g_main_context_pending(), the replacement for gtk_main_iteration() is
g_main_context_iteration().
### Reduce the use of gtk_widget_destroy()
GTK 4 introduces a gtk_window_destroy() api. While that is not available
in GTK 3, you can prepare for the switch by using gtk_widget_destroy()
only on toplevel windows, and replace all other uses with
gtk_container_remove() or g_object_unref().
### Reduce the use of generic container APIs</title>
GTK 4 removes gtk_container_add() and gtk_container_remove(). While there
is not always a replacement for gtk_container_remove() in GTK 3, you can
replace many uses of gtk_container_add() with equivalent container-specific
APIs such as gtk_box_pack_start() or gtk_grid_attach(), and thereby reduce
the amount of work you have to do at the time of the switch.
## Changes that need to be done at the time of the switch
This section outlines porting tasks that you need to tackle when
you get to the point that you actually build your application against
GTK 4. Making it possible to prepare for these in GTK 3 would
have been either impossible or impractical.
### Stop using GdkScreen
The GdkScreen object has been removed in GTK 4. Most of its APIs already
had replacements in GTK 3 and were deprecated, a few remaining replacements
have been added to GdkDisplay.
### Stop using the root window
The root window is an X11-centric concept that is no longer exposed in the
backend-neutral GDK API. If you need to interact with the X11 root window,
you can use gdk_x11_display_get_xrootwindow() to get its XID.
### Stop using GdkVisual
This object is not useful with current GTK drawing APIs and has been removed
without replacement.
### Stop using GdkDeviceManager
The GdkDeviceManager object has been removed in GTK 4. Most of its APIs already
had replacements in GTK 3 and were deprecated in favor of GdkSeat.
### Adapt to GdkWindow API changes
GdkWindow has been renamed to GdkSurface.
In GTK 4, the two roles of a standalone toplevel window and of a popup
that is placed relative to a parent window have been separated out into
two interfaces, #GdkToplevel and #GdkPopup. Surfaces implementing these
interfaces are created with gdk_surface_new_toplevel() and
gdk_surface_new_popup(), respectively, and they are presented on screen
using gdk_toplevel_present() and gdk_popup_present(). The present()
functions take parameters in the form of an auxiliary layout struct,
#GdkPopupLayout or #GdkToplevelLayout. If your code is dealing directly
with surfaces, you may have to change it to call the API in these
interfaces, depending on whether the surface you are dealing with
is a toplevel or a popup.
As part of this reorganization, X11-only concepts such as sticky or
keep-below have been removed. If you need to use them on your X11 windows,
you will have to set the corresponding X11 properties (as specified in the
EWMH) yourself. Subsurfaces are only supported with the Wayland backend,
using gdk_wayland_surface_new_subsurface(). Native and foreign subwindows
are no longer supported. These concepts were complicating the code and
could not be supported across backends.
gdk_window_reparent() is no longer available.
A number of minor API cleanups have happened in GdkSurface
as well. For example, gdk_surface_input_shape_combine_region()
has been renamed to gdk_surface_set_input_region(), and
gdk_surface_begin_resize_drag() has been renamed to
gdk_toplevel_begin_resize().
### The "iconified" window state has been renamed to "minimized"
The %GDK_SURFACE_STATE_ICONIFIED value of the
#GdkSurfaceState enumeration is now %GDK_SURFACE_STATE_MINIMIZED.
The #GdkWindow functions <function>gdk_window_iconify()</function>
and <function>gdk_window_deiconify()</function> have been renamed to
gdk_toplevel_minimize() and gdk_toplevel_present(), respectively.
The behavior of the minimization and unminimization operations have
not been changed, and they still require support from the underlying
windowing system.
### Adapt to GdkEvent API changes
Direct access to GdkEvent structs is no longer possible in GTK 4.
GdkEvent is now a strictly read-only type, and you can no longer
change any of its fields, or construct new events. All event fields
have accessors that you will have to use.
Event compression is always enabled in GTK 4. If you need to see
the uncoalesced motion history, use gdk_motion_event_get_history()
on the latest motion event.
### Stop using grabs
GTK 4 no longer provides the gdk_device_grab() or gdk_seat_grab()
apis. If you need to dismiss a popup when the user clicks outside
(the most common use for grabs), you can use the GdkPopup
#GdkPopup:autohide property instead. GtkPopover also has a
#GtkPopover:autohide property for this. If you need to prevent
the user from interacting with a window while a dialog is open,
use the #GtkWindow:modal property of the dialog.
### Adapt to coordinate API changes
A number of coordinate APIs in GTK 3 had _double variants:
gdk_device_get_position(), gdk_device_get_surface_at_position(),
gdk_surface_get_device_position(). These have been changed to use
doubles, and the _double variants have been removed. Update your
code accordingly.
Any APIs that deal with global (or root) coordinates have been
removed in GTK 4, since not all backends support them. You should
replace your use of such APIs with surface-relative equivalents.
Examples of this are gdk_surface_get_origin(), gdk_surface_move()
or gdk_event_get_root_coords().
### Adapt to GdkKeymap API changes
GdkKeymap no longer exists as an independent object.
If you need access to keymap state, it is now exposed as properties
on the #GdkDevice representing the keyboard: #GdkDevice:direction,
#GdkDevice:has-bidi-layouts, #GdkDevice:caps-lock-state,
#GdkDevice:num-lock-state, #GdkDevice:scroll-lock-state and
#GdkDevice:modifier-state. To obtain the keyboard device, you can use
`gdk_seat_get_keyboard (gdk_display_get_default_seat (display)`.
If you need access to translated keys for event handling, #GdkEvent
now includes all of the translated key state, including consumed
modifiers, group and shift level, so there should be no need to
manually call gdk_keymap_translate_keyboard_state() (which has
been removed).
If you need to do forward or backward mapping between key codes
and key values, use gdk_display_map_keycode() and gdk_display_map_keyval(),
which are the replacements for gdk_keymap_get_entries_for_keycode()
and gdk_keymap_get_entries_for_keyval().
### Adapt to changes in keyboard modifier handling
GTK 3 has the idea that use of modifiers may differ between different
platforms, and has a #GdkModifierIntent api to let platforms provide
hint about how modifiers are expected to be used. It also promoted
the use of <Primary> instead of <Control> to specify accelerators that
adapt to platform conventions.
In GTK 4, the meaning of modifiers has been fixed, and backends are
expected to map the platform conventions to the existing modifiers.
The expected use of modifiers in GTK 4 is:
GDK_CONTROL_MASK
: Primary accelerators
GDK_ALT_MASK
: Mnemonics
GDK_SHIFT_MASK
: Extending selections
GDK_CONTROL_MASK
: Modifying selections
GDK_CONTROL_MASK|GDK_ALT_MASK
: Prevent text input
Consequently, #GdkModifierIntent and related APIs have been removed,
and <Control> is preferred over <Primary> in accelerators.
A related change is that GTK 4 no longer supports the use of archaic
X11 'real' modifiers with the names Mod1,..., Mod5, and %GDK_MOD1_MASK
has been renamed to %GDK_ALT_MASK.
### Stop using gtk_get_current_... APIs
The function gtk_get_current_event() and its variants have been
replaced by equivalent event controller APIs:
gtk_event_controller_get_current_event(), etc.
### Convert your ui files
A number of the changes outlined below affect .ui files. The
gtk4-builder-tool simplify command can perform many of the
necessary changes automatically, when called with the --3to4
option. You should always review the resulting changes.
### Adapt to event controller API changes
A few changes to the event controller and #GtkGesture APIs
did not make it back to GTK 3, and have to be taken into account
when moving to GTK 4. One is that the #GtkEventControllerMotion::enter
and #GtkEventControllerMotion::leave signals have gained new arguments.
Another is that #GtkGestureMultiPress has been renamed to #GtkGestureClick,
and has lost its area property. A #GtkEventControllerFocus has been
split off from #GtkEventcontrollerKey.
### Focus handling changes
The semantics of the #GtkWidget:can-focus property have changed.
In GTK 3, this property only meant that the widget itself would not
accept keyboard input, but its children still might (in the case of
containers). In GTK 4, if :can-focus is %FALSE, the focus cannot enter
the widget or any of its descendents, and the default value has changed
from %FALSE to %TRUE. In addition, there is a #GtkWidget:focusable
property, which controls whether an individual widget can receive
the input focus.
The feature to automatically keep the focus widget scrolled into view
with gtk_container_set_focus_vadjustment() has been removed together with
GtkContainer, and is provided by scrollable widgets instead. In the common
case that the scrollable is a #GtkViewport, use #GtkViewport:scroll-to-focus.
### Use the new apis for keyboard shortcuts
The APIs for keyboard shortcuts and accelerators have changed in GTK 4.
Instead of GtkAccelGroup, you now use a #GtkShortcutController with global
scope, and instead of GtkBindingSet, you now use gtk_widget_class_add_shortcut(),
gtk_widget_class_add_binding() and its variants. In both cases, you probably
want to add actions that can be triggered by your shortcuts.
There is no direct replacement for loading and saving accelerators with
GtkAccelMap. But since #GtkShortcutController implements #GListModel and
both #GtkShortcutTrigger and #GtkShortcutAction can be serialized to
strings, it is relatively easy to implement saving and loading yourself.
### Stop using GtkEventBox
GtkEventBox is no longer needed and has been removed.
All widgets receive all events.
### Stop using GtkButtonBox
GtkButtonBox has been removed. Use a GtkBox instead.
### Adapt to GtkBox API changes
The GtkBox pack-start and -end methods have been replaced by gtk_box_prepend()
and gtk_box_append(). You can also reorder box children as necessary.
### Adapt to GtkHeaderBar and GtkActionBar API changes
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 gtk_header_bar_set_custom_title() function has been renamed to
the more accurate name gtk_header_bar_set_title_widget(). The
corresponding getter and the property itself have also been renamed.
The gtk_header_bar_set_title() function has been removed along with its
corresponding getter and the property. By default #GtkHeaderBar shows
the title of the window, so if you were setting the title of the header
bar, consider setting the window title instead. If you need to show a
title that's different from the window title, use the
#GtkHeaderBar:title-widget property to add a #GtkLabel as shown in the
example in #GtkHeaderBar documentation.
The gtk_header_bar_set_subtitle() function has been removed along with
its corresponding getter and the property. The old "subtitle" behavior
can be replicated by setting the #GtkHeaderBar:title-widget property to
a #GtkBox with two labels inside, with the title label matching the
example in #GtkHeaderBar documentation, and the subtitle label being
similar, but with "subtitle" style class instead of "title".
The gtk_header_bar_set_has_subtitle() function has been removed along
with its corresponding getter and the property. Its behavior can be
replicated by setting the #GtkHeaderBar:title-widget property to a
#GtkStack with #GtkStack:vhomogeneous property set to %TRUE and two
pages, each with a #GtkBox with title and subtitle as described above.
The ::pack-type child properties of GtkHeaderBar and GtkActionBar have
been removed. If you need to programmatically place children, use the
pack_start() and pack_end() APIs. In ui files, use the type attribute
on the child element.
gtk4-builder-tool can help with this conversion, with the --3to4 option
of the simplify command.
### Adapt to GtkStack, GtkAssistant and GtkNotebook API changes
The child properties of GtkStack, GtkAssistant and GtkNotebook have been
converted into child meta objects.
Instead of gtk_container_child_set (stack, child, …), you can now use
g_object_set (gtk_stack_get_page (stack, child), …). In .ui files, the
GtkStackPage objects must be created explicitly, and take the child widget
as property. GtkNotebook and GtkAssistant are similar.
gtk4-builder-tool can help with this conversion, with the --3to4 option
of the simplify command.
### Adapt to GtkBin removal
The abstract base class GtkBin for single-child containers has been
removed. The former subclasses are now derived directly from GtkWidget,
and have a "child" property for their child widget. To add a child, use
the setter for the "child" property (e.g. gtk_frame_set_child()) instead
of gtk_container_add(). Adding a child in a ui file with <child> still works.
The affected classes are:
- GtkAspectFrame
- GtkButton (and subclasses)
- GtkComboBox
- GtkFlowBoxChild
- GtkFrame
- GtkListBoxRow
- GtkOverlay
- GtkPopover
- GtkRevealer
- GtkScrolledWindow
- GtkSearchBar
- GtkViewport
- GtkWindow (and subclasses)
If you have custom widgets that were derived from GtkBin, you should
port them to derive from GtkWidget. Notable vfuncs that you will have
to implement include dispose() (to unparent your child), compute_expand()
(if you want your container to propagate expand flags) and
get_request_mode() (if you want your container to support height-for-width.
You may also want to implement the GtkBuildable interface, to support
adding children with <child> in ui files.
### Adapt to GtkContainer removal
The abstract base class GtkContainer for general containers has been
removed. The former subclasses are now derived directly from GtkWidget,
and have class-specific add() and remove() functions.
The most noticable change is the use of gtk_box_append() or gtk_box_prepend()
instead of gtk_container_add() for adding children to GtkBox, and the change
to use container-specific remove functions, such as gtk_stack_remove() instead
of gtk_container_remove(). Adding a child in a ui file with <child> still works.
The affected classes are:
- GtkActionBar
- GtkBox (and subclasses)
- GtkExpander
- GtkFixed
- GtkFlowBox
- GtkGrid
- GtkHeaderBar
- GtkIconView
- GtkInfoBar
- GtkListBox
- GtkNotebook
- GtkPaned
- GtkStack
- GtkTextView
- GtkTreeView
Without GtkContainer, there are no longer facilities for defining and
using child properties. If you have custom widgets using child properties,
they will have to be converted either to layout properties provided
by a layout manager (if they are layout-related), or handled in some
other way. One possibility is to use child meta objects, as seen with
GtkAssistantPage, GtkStackPage and the like.
### Stop using GtkContainer::border-width
GTK 4 has removed the #GtkContainer::border-width property (together
with the rest of GtkContainer). Use other means to influence the spacing
of your containers, such as the CSS margin and padding properties on child
widgets.
### Adapt to gtk_widget_destroy() removal
The function gtk_widget_destroy() has been removed. To explicitly destroy
a toplevel window, use gtk_window_destroy(). To destroy a widget that is
part of a hierarchy, remove it from its parent using a container-specific
remove api, such as gtk_box_remove() or gtk_stack_remove(). To destroy
a freestanding non-toplevel widget, use g_object_unref() to drop your
reference.
### Adapt to coordinate API changes
A number of APIs that are accepting or returning coordinates have
been changed from ints to doubles: gtk_widget_translate_coordinates(),
gtk_fixed_put(), gtk_fixed_move(). This change is mostly transparent,
except for cases where out parameters are involved: you need to
pass double* now, instead of int*.
### Adapt to GtkStyleContext API changes
The getters in the GtkStyleContext API, such as
gtk_style_context_get_property(), gtk_style_context_get(),
or gtk_style_context_get_color() have lost their state argument,
and always use the context's current state. Update all callers
to omit the state argument.
The most commonly used GtkStyleContext API, gtk_style_context_add_class(),
has been moved to GtkWidget as gtk_widget_add_css_class(), as have the
corresponding gtk_style_context_remove_class() and
gtk_style_context_has_class() APIs.
### Adapt to GtkCssProvider API changes
In GTK 4, the various #GtkCssProvider load functions have lost their
#GError argument. If you want to handle CSS loading errors, use the
#GtkCssProvider::parsing-error signal instead. gtk_css_provider_get_named()
has been replaced by gtk_css_provider_load_named().
### Stop using GtkShadowType and GtkRelief properties
The shadow-type properties in GtkScrolledWindow, GtkViewport,
and GtkFrame, as well as the relief properties in GtkButton
and its subclasses have been removed. GtkScrolledWindow, GtkButton
and GtkMenuButton have instead gained a boolean has-frame
property.
### Adapt to GtkWidget's size request changes
GTK 3 used five different virtual functions in GtkWidget to
implement size requisition, namely the gtk_widget_get_preferred_width()
family of functions. To simplify widget implementations, GTK 4 uses
only one virtual function, GtkWidgetClass::measure() that widgets
have to implement. gtk_widget_measure() replaces the various
gtk_widget_get_preferred_ functions for querying sizes.
### Adapt to GtkWidget's size allocation changes
The #GtkWidget.size_allocate() vfunc takes the baseline as an argument
now, so you no longer need to call gtk_widget_get_allocated_baseline()
to get it.
The ::size-allocate signal has been removed, since it is easy
to misuse. If you need to learn about sizing changes of custom
drawing widgets, use the #GtkDrawingArea::resize or #GtkGLArea::resize
signals.
### Switch to GtkWidget's children APIs
In GTK 4, any widget can have children (and GtkContainer is gone).
There is new API to navigate the widget tree, for use in widget
implementations: gtk_widget_get_first_child(), gtk_widget_get_last_child(),
gtk_widget_get_next_sibling(), gtk_widget_get_prev_sibling().
### Don't use -gtk-gradient in your CSS
GTK now supports standard CSS syntax for both linear and radial
gradients, just use those.
### Don't use -gtk-icon-effect in your CSS
GTK now supports a more versatile -gtk-icon-filter instead. Replace
-gtk-icon-effect: dim; with -gtk-icon-filter: opacity(0.5); and
-gtk-icon-effect: hilight; with -gtk-icon-filter: brightness(1.2);.
### Don't use -gtk-icon-theme in your CSS
GTK now uses the current icon theme, without a way to change this.
### Don't use -gtk-outline-...-radius in your CSS
These non-standard properties have been removed from GTK
CSS. Just use regular border radius.
### Adapt to drawing model changes
This area has seen the most radical changes in the transition from GTK 3
to GTK 4. Widgets no longer use a draw() function to render their contents
to a cairo surface. Instead, they have a snapshot() function that creates
one or more GskRenderNodes to represent their content. Third-party widgets
that use a draw() function or a #GtkWidget::draw signal handler for custom
drawing will need to be converted to use gtk_snapshot_append_cairo().
The auxiliary #GtkSnapshot object has APIs to help with creating render
nodes.
If you are using a #GtkDrawingArea for custom drawing, you need to switch
to using gtk_drawing_area_set_draw_func() to set a draw function instead
of connnecting a handler to the #GtkWidget::draw signal.
### Stop using APIs to query GdkSurfaces
A number of APIs for querying special-purpose windows have been removed,
since these windows are no longer publically available:
gtk_tree_view_get_bin_window(), gtk_viewport_get_bin_window(),
gtk_viewport_get_view_window().
### Widgets are now visible by default
The default value of #GtkWidget:visible in GTK 4 is %TRUE, so you no
longer need to explicitly show all your widgets. On the flip side, you
need to hide widgets that are not meant to be visible from the start.
The only widgets that still need to be explicitly shown are toplevel
windows, dialogs and popovers.
A convenient way to remove unnecessary property assignments like this
from ui files it run the command `gtk4-builder-tool simplify --replace`
on them.
The function gtk_widget_show_all(), the #GtkWidget:no-show-all property
and its getter and setter have been removed in GTK 4, so you should stop
using them.
### Adapt to changes in animated hiding and showing of widgets
Widgets that appear and disappear with an animation, such as GtkPopover,
GtkInfoBar, GtkRevealer no longer use gtk_widget_show() and gtk_widget_hide()
for this, but have gained dedicated APIs for this purpose that you should
use.
### Stop passing commandline arguments to gtk_init
The gtk_init() and gtk_init_check() functions no longer accept commandline
arguments. Just call them without arguments. Other initialization functions
that were purely related to commandline argument handling, such as
gtk_parse_args() and gtk_get_option_group(), are gone. The APIs to
initialize GDK separately are also gone, but it is very unlikely
that you are affected by that.
### GdkPixbuf is deemphasized
A number of #GdkPixbuf-based APIs have been removed. The available replacements
are either using #GIcon, or the newly introduced #GdkTexture or #GdkPaintable
classes instead. If you are dealing with pixbufs, you can use
gdk_texture_new_for_pixbuf() to convert them to texture objects where needed.
### GtkWidget event signals are removed
Event controllers and #GtkGestures have already been introduced in GTK 3 to handle
input for many cases. In GTK 4, the traditional widget signals for handling input,
such as #GtkWidget::motion-event or #GtkWidget::event have been removed.
### Invalidation handling has changed
Only gtk_widget_queue_draw() is left to mark a widget as needing redraw.
Variations like gtk_widget_queue_draw_rectangle() or gtk_widget_queue_draw_region()
are no longer available.
### Stop using GtkWidget::draw
The #GtkWidget::draw signal has been removed. Widgets need to implement the
#GtkWidgetClass.snapshot() function now. Connecting draw signal handlers is
no longer possible. If you want to keep using cairo for drawing, use
gtk_snaphot_append_cairo().
### Window content observation has changed
Observing widget contents and widget size is now done by using the
#GtkWidgetPaintable object instead of connecting to widget signals.
### Monitor handling has changed
Instead of a monitor number, #GdkMonitor is now used throughout.
gdk_display_get_monitors() returns the list of monitors that can be queried
or observed for monitors to pass to APIs like gtk_window_fullscreen_on_monitor().
### Adapt to cursor API changes
Use the new gtk_widget_set_cursor() function to set cursors, instead of
setting the cursor on the underlying window directly. This is necessary
because most widgets don't have their own window anymore, turning any
such calls into global cursor changes.
For creating standard cursors, gdk_cursor_new_for_display() has been removed,
you have to use cursor names instead of GdkCursorType. For creating custom cursors,
use gdk_cursor_new_from_texture(). The ability to get cursor images has been removed.
### Adapt to icon size API changes
Instead of the existing extensible set of symbolic icon sizes, GTK now only
supports normal and large icons with the #GtkIconSize enumeration. The actual sizes
can be defined by themes via the CSS property -gtk-icon-size.
GtkImage setters like gtk_image_set_from_icon_name() no longer take a #GtkIconSize
argument. You can use the separate gtk_image_set_icon_size() setter if you need
to override the icon size.
The :stock-size property of GtkCellRendererPixbuf has been renamed to
#GtkCellRendererPixbuf:icon-size.
### Adapt to changes in the GtkAssistant API
The :has-padding property is gone, and GtkAssistant no longer adds padding
to pages. You can easily do that yourself.
### Adapt to changes in the API of GtkEntry, GtkSearchEntry and GtkSpinButton
The GtkEditable interface has been made more useful, and the core functionality of
GtkEntry has been broken out as a GtkText widget. GtkEntry, GtkSearchEntry,
GtkSpinButton and the new GtkPasswordEntry now use a GtkText widget internally
and implement GtkEditable. In particular, this means that it is no longer
possible to use GtkEntry API such as gtk_entry_grab_focus_without_selecting()
on a search entry.
Use GtkEditable API for editable functionality, and widget-specific APIs for
things that go beyond the common interface. For password entries, use
GtkPasswordEntry. As an example, gtk_spin_button_set_max_width_chars()
has been removed in favor of gtk_editable_set_max_width_chars().
### Adapt to changes in GtkOverlay API
The GtkOverlay :pass-through child property has been replaced by the
#GtkWidget:can-target property. Note that they have the opposite sense:
pass-through == !can-target.
### Use GtkFixed instead of GtkLayout
Since GtkScrolledWindow can deal with widgets that do not implement
the GtkScrollable interface by automatically wrapping them into a
GtkViewport, GtkLayout is redundant, and has been removed in favor
of the existing GtkFixed container widget.
### Adapt to search entry changes
The way search entries are connected to global events has changed;
gtk_search_entry_handle_event() has been dropped and replaced by
gtk_search_entry_set_key_capture_widget() and
gtk_event_controller_key_forward().
### Stop using gtk_window_activate_default()
The handling of default widgets has been changed, and activating
the default now works by calling gtk_widget_activate_default()
on the widget that caused the activation. If you have a custom widget
that wants to override the default handling, you can provide an
implementation of the default.activate action in your widgets' action
groups.
### Stop setting ::has-default and ::has-focus in .ui files
The special handling for the ::has-default and ::has-focus properties
has been removed. If you want to define the initial focus or the
the default widget in a .ui file, set the ::default-widget or
::focus-widget properties of the toplevel window.
### Stop using the GtkWidget::display-changed signal
To track the current display, use the #GtkWidget::root property instead.
### GtkPopover::modal has been renamed to autohide
The modal property has been renamed to autohide.
gtk-builder-tool can assist with the rename in ui files.
### gtk_widget_get_surface has been removed
gtk_widget_get_surface() has been removed.
Use gtk_native_get_surface() in combination with
gtk_widget_get_native() instead.
### gtk_widget_is_toplevel has been removed
gtk_widget_is_toplevel() has been removed.
Use GTK_IS_ROOT, GTK_IS_NATIVE or GTK_IS_WINDOW
instead, as appropriate.
### gtk_widget_get_toplevel has been removed
gtk_widget_get_toplevel() has been removed.
Use gtk_widget_get_root() or gtk_widget_get_native()
instead, as appropriate.
### GtkEntryBuffer ::deleted-text has changed
To allow signal handlers to access the deleted text before it
has been deleted #GtkEntryBuffer::deleted-text has changed from
%G_SIGNAL_RUN_FIRST to %G_SIGNAL_RUN_LAST. The default handler
removes the text from the #GtkEntryBuffer.
To adapt existing code, use g_signal_connect_after() or
%G_CONNECT_AFTER when using g_signal_connect_data() or
g_signal_connect_object().
### GtkMenu, GtkMenuBar and GtkMenuItem are gone
These widgets were heavily relying on X11-centric concepts such as
override-redirect windows and grabs, and were hard to adjust to other
windowing systems.
Menus can already be replaced using GtkPopoverMenu in GTK 3. Additionally,
GTK 4 introduces GtkPopoverMenuBar to replace menubars. These new widgets
can only be constructed from menu models, so the porting effort involves
switching to menu models and actions.
Tabular menus were rarely used and complicated the menu code,
so they have not been brought over to #GtkPopoverMenu. If you need
complex layout in menu-like popups, consider directly using a
#GtkPopover instead.
Since menus are gone, GtkMenuButton also lost its ability to show menus,
and needs to be used with popovers in GTK 4.
### GtkToolbar has been removed
Toolbars were using outdated concepts such as requiring special toolitem
widgets. Toolbars should be replaced by using a GtkBox with regular widgets
instead and the "toolbar" style class.
### GtkAspectFrame is no longer a frame
GtkAspectFrame is no longer derived from GtkFrame and does not
place a label and frame around its child anymore. It still lets
you control the aspect ratio of its child.
### Stop using custom tooltip windows
Tooltips no longer use GtkWindows in GTK 4, and it is no longer
possible to provide a custom window for tooltips. Replacing the content
of the tooltip with a custom widget is still possible, with
gtk_tooltip_set_custom().
### Switch to the new Drag-and-Drop api
The source-side Drag-and-Drop apis in GTK 4 have been changed to use an event
controller, #GtkDragSource. Instead of calling gtk_drag_source_set()
and connecting to #GtkWidget signals, you create a #GtkDragSource object,
attach it to the widget with gtk_widget_add_controller(), and connect
to #GtkDragSource signals. Instead of calling gtk_drag_begin() on a widget
to start a drag manually, call gdk_drag_begin().
The ::drag-data-get signal has been replaced by the #GtkDragSource::prepare
signal, which returns a #GdkContentProvider for the drag operation.
The destination-side Drag-and-Drop apis in GTK 4 have also been changed
to use an event controller, #GtkDropTarget. Instead of calling
gtk_drag_dest_set() and connecting to #GtkWidget signals, you create
a #GtkDropTarget object, attach it to the widget with
gtk_widget_add_controller(), and connect to #GtkDropTarget signals.
The ::drag-motion signal has been renamed to #GtkDropTarget::accept, and
instead of ::drag-data-received, you need to use async read methods on the
#GdkDrop object, such as gdk_drop_read_async() or gdk_drop_read_value_async().
### Adapt to GtkIconTheme API changes
gtk_icon_theme_lookup_icon() returns a #GtkIconPaintable object now, instead
of a #GtkIconInfo. It always returns a paintable in the requested size, and
never fails. A number of no-longer-relevant lookup flags and API variants
have been removed.
### Update to GtkFileChooser API changes
GtkFileChooser moved to a GFile-based API. If you need to convert a
path or a URI, use g_file_new_for_path(), g_file_new_for_commandline_arg(),
or g_file_new_for_uri(); similarly, if you need to get a path or a URI
from a GFile, use g_file_get_path(), or g_file_get_uri(). With the
removal or path and URI-based functions, the "local-only" property has
been removed; GFile can be used to access non-local as well as local
resources.
The GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER action has been removed. Use
%GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, instead. If a new folder is needed,
the user can create one.
The "confirm-overwrite" signal, and the "do-overwrite-confirmation"
property have been removed from GtkFileChooser. The file chooser widgets
will automatically handle the confirmation of overwriting a file when
using GTK_FILE_CHOOSER_ACTION_SAVE.
GtkFileChooser does not support a custom extra widget any more. If you
need to add extra widgets, use gtk_file_chooser_add_choice() instead.
GtkFileChooser does not support a custom preview widget any more. If
you need to show a custom preview, you can create your own GtkDialog
with a GtkFileChooserWidget and your own preview widget that you
update whenever the #GtkFileChooser::selection-changed signal is
emitted.
### Stop using blocking dialog functions
GtkDialog, GtkNativeDialog, and GtkPrintOperation removed their
blocking API using nested main loops. Nested main loops present
re-entrancy issues and other hard to debug issues when coupled
with other event sources (IPC, accessibility, network operations)
that are not under the toolkit or the application developer's
control. Additionally, "stop-the-world" functions do not fit
the event-driven programming model of GTK.
You can replace calls to <function>gtk_dialog_run()</function>
by specifying that the #GtkDialog must be modal using
gtk_window_set_modal() or the %GTK_DIALOG_MODAL flag, and
connecting to the #GtkDialog::response signal.

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
# Using GTK on Apple macOS {#gtk-osx}
The Apple macOS port of GTK is an implementation of GDK (and therefore GTK)
on top of the Quartz API.
Currently, the macOS port does not use any additional commandline options
or environment variables.
For up-to-date information about the current status of this port, see the
[project page](https://wiki.gnome.org/Projects/GTK/OSX).

View File

@@ -0,0 +1,39 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="gtk-osx">
<refmeta>
<refentrytitle>Using GTK on Apple macOS</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Using GTK on Apple macOS</refname>
<refpurpose>
MacOS-specific aspects of using GTK
</refpurpose>
</refnamediv>
<refsect1>
<title>Using GTK on Apple macOS</title>
<para>
The Apple macOS port of GTK is an implementation of GDK (and therefore GTK)
on top of the Quartz API.
</para>
<para>
Currently, the macOS port does not use any additional commandline options
or environment variables.
</para>
<para>
For up-to-date information about the current status of this port, see the
<ulink url="https://wiki.gnome.org/Projects/GTK/OSX">project page</ulink>.
</para>
</refsect1>
</refentry>

View File

@@ -0,0 +1,211 @@
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="gtk-other-software">
<refmeta>
<refentrytitle>Mixing GTK with other software</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>Mixing GTK with other software</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Mixing GTK with other software</refname>
<refpurpose>
How to combine GTK with other code and event loops
</refpurpose>
</refnamediv>
<refsect1>
<title>Overview</title>
<para>
Often people want to use GTK in combination with another library or existing
body of code that is not GTK-aware. The general problem people encounter
is that the control flow of the other code does not return to GTK, so
widgets do not repaint, mouse and keyboard events are ignored, and so forth.
</para>
<para>
This section describes some approaches to solving this problem. The most
suitable approach depends on the code that's involved, the platforms you're
targetting, and your own familiarity with each approach.
</para>
</refsect1>
<refsect1>
<title>Periodically yield to GTK main loop</title>
<para>
This is the simplest method, but requires you to modify the non-GTK code.
Say you have a function that does some kind of lengthy task:
<informalexample>
<programlisting>
void
do_lengthy_task (void)
{
int i;
for (i = 0; i &lt; BIG_NUMBER; ++i)
{
do_small_part_of_task ();
}
}
</programlisting>
</informalexample>
You simply insert code into this function that processes pending main loop tasks, if any:
<informalexample>
<programlisting>
void
do_lengthy_task (void)
{
int i;
for (i = 0; i &lt; BIG_NUMBER; ++i)
{
do_small_part_of_task ();
/* allow main loop to process pending events; NULL
* means the default context.
*/
while (g_main_context_pending (NULL))
g_main_context_iteration (NULL, FALSE);
}
}
</programlisting>
</informalexample>
</para>
<para>
The primary disadvantage of this approach is that you have to trade off UI
responsiveness and the performance of the task. That is, if
do_small_part_of_task() does very little of the task, you'll spend lots of CPU
time on <link
linkend="g-main-context-iteration">g_main_context_iteration()</link>. While if
do_small_part_of_task() does a lot of work, the GUI will seem noticeably
"chunky" to the user.
</para>
<para>
Another disadvantage to this approach is that you can't have more than one
lengthy task at the same time, unless you manually integrate them.
</para>
<para>
The big advantage of this approach is that it's simple and straightforward, and
works fine for simple applications such as tossing up a progress bar during the
lengthy task.
</para>
</refsect1>
<refsect1>
<title>Run the other code as a slave of the GTK main loop</title>
<para>
As a slightly cleaner solution, you can ask the main loop to run a small part of your
task whenever it isn't busy &mdash; that is, when it's <firstterm>idle</firstterm>.
GLib provides a function <link linkend="g-idle-add">g_idle_add()</link> that's useful
for this. An "idle handler" added with <link linkend="g-idle-add">g_idle_add()</link>
will be run continuously as long as it returns <literal>TRUE</literal>. However,
the main loop gives higher priority to GUI-related tasks, so will run those instead
when appropriate.
</para>
<para>
Here's a simple example:
<informalexample>
<programlisting>
gboolean
my_idle_handler (gpointer user_data)
{
do_small_part_of_task ();
if (task_complete)
return G_SOURCE_REMOVE; /* removes the idle handler */
else
return G_SOURCE_CONTINUE; /* runs the idle handler again */
}
g_idle_add (my_idle_handler, NULL);
</programlisting>
</informalexample>
</para>
<para>
If your task involves reading data from the network, you should instead use
<link linkend="g-input-add">g_input_add()</link>; this will allow the
main loop to sleep until data is available on a file descriptor, then
wake up to read that data.
</para>
<para>
<link linkend="g-idle-add">g_idle_add()</link> returns a main loop source ID you can
use to remove the idle handler with <link linkend="g-source-remove">g_source_remove()</link>.
This is useful for cancelling a task, for example. Another approach is to keep a flag
variable and have the idle handler itself return <literal>FALSE</literal> when appropriate.
</para>
</refsect1>
<refsect1>
<title>Use multiple processes</title>
<para>
If you can't break a task into small chunks &mdash; the
"do_small_part_of_task()" function in the above examples &mdash; you'll have to
separate your program into two parts, by spawning a child thread or process.
A process does not share the same address space (variables and data) with its parent.
A thread does share the same address space, so a change made to a variable in
one thread will be visible to other threads as well.
</para>
<para>
This manual can't go into full detail on processes, threads, and other UNIX
programming topics. You may wish to get a book or two &mdash; two I'm familiar
with are Beginning Linux Programming (WROX Press) and Advanced Programming in
the UNIX Environment (by Richard Stevens.
</para>
<para>
Those books also cover the central issue you'll need to address in order to have
a multi-process application: how to communicate between the processes. The
simplest solution is to use pipes; <link
linkend="g-input-add">g_input_add()</link> in combination with <link
linkend="g-spawn-async-with-pipes">g_spawn_async_with_pipes()</link> should make
this reasonably convenient. There are other possibilities, of course, such as
sockets, shared memory, and X Window System client message events, depending on
your needs.
</para>
</refsect1>
<refsect1>
<title>Use multiple threads</title>
<para>
</para>
</refsect1>
<refsect1>
<title>Integrate the GTK main loop with another main loop</title>
<para>
</para>
</refsect1>
<refsect1>
<title>Things that won't work</title>
<para>
signals
</para>
</refsect1>
</refentry>

Some files were not shown because too many files have changed in this diff Show More