Compare commits
1 Commits
ebassi/ci-
...
avoid-labe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c640e4a4cc |
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
89
NEWS
@@ -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
|
||||
=================================
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
18
demos/gtk-demo/appmenu.ui
Normal 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"><Control>q</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 9 283 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
list.viewswitcher {
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
list.viewswitcher > row {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
list.viewswitcher row:selected {
|
||||
background: gray;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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 (¤t_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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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 70 000 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
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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"><Control>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"><Control>s</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Save _As...</attribute>
|
||||
<attribute name="action">app.save-as</attribute>
|
||||
<attribute name="accel"><Control>s</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
<attribute name="accel"><Control>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"><Control>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"><Control>s</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Save _As...</attribute>
|
||||
<attribute name="action">app.save-as</attribute>
|
||||
<attribute name="accel"><Control>s</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
<attribute name="accel"><Control>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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'><Primary>a</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Quit</attribute>"
|
||||
" <attribute name='action'>app.quit</attribute>"
|
||||
" <attribute name='accel'><Primary>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'><Primary>a</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Quit</attribute>"
|
||||
" <attribute name='action'>app.quit</attribute>"
|
||||
" <attribute name='accel'><Primary>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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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: ...
|
||||
*
|
||||
* ...
|
||||
```
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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):
|
||||
394
docs/reference/gtk/actions.xml
Normal file
394
docs/reference/gtk/actions.xml
Normal 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>
|
||||
@@ -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`
|
||||
71
docs/reference/gtk/broadway.xml
Normal file
71
docs/reference/gtk/broadway.xml
Normal 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>
|
||||
@@ -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.
|
||||
518
docs/reference/gtk/building.xml
Normal file
518
docs/reference/gtk/building.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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 # 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) | |
|
||||
1179
docs/reference/gtk/css-overview.xml
Normal file
1179
docs/reference/gtk/css-overview.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 |
|
||||
@@ -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 don’t 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.
|
||||
232
docs/reference/gtk/drawing-model.xml
Normal file
232
docs/reference/gtk/drawing-model.xml
Normal 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 don’t 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
1048
docs/reference/gtk/getting_started.xml.in
Normal file
1048
docs/reference/gtk/getting_started.xml.in
Normal file
File diff suppressed because it is too large
Load Diff
366
docs/reference/gtk/glossary.xml
Normal file
366
docs/reference/gtk/glossary.xml
Normal 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×20 pixels, but its
|
||||
parent may decide to allocate 50×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>
|
||||
@@ -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)
|
||||
@@ -6,7 +6,7 @@
|
||||
<!ENTITY pi "π">
|
||||
<!ENTITY solidus "⁄">
|
||||
]>
|
||||
<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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 |
@@ -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.
|
||||
|
||||

|
||||
|
||||
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:
|
||||
332
docs/reference/gtk/input-handling.xml
Normal file
332
docs/reference/gtk/input-handling.xml
Normal 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>
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
15
docs/reference/gtk/migrating-2to4.xml
Normal file
15
docs/reference/gtk/migrating-2to4.xml
Normal 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>
|
||||
@@ -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.
|
||||
1243
docs/reference/gtk/migrating-3to4.xml
Normal file
1243
docs/reference/gtk/migrating-3to4.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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).
|
||||
39
docs/reference/gtk/osx.xml
Normal file
39
docs/reference/gtk/osx.xml
Normal 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>
|
||||
211
docs/reference/gtk/other_software.xml
Normal file
211
docs/reference/gtk/other_software.xml
Normal 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 < 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 < 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 — 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 — the
|
||||
"do_small_part_of_task()" function in the above examples — 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 — 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
Reference in New Issue
Block a user