Compare commits
353 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61f7ac09bc | |||
| 688085cfaf | |||
| 7257d1c15f | |||
| 21d40fc038 | |||
| 93ff65c685 | |||
| 7e7201745d | |||
| 50a986605c | |||
| 96994568fd | |||
| b494d94bdb | |||
| 9d6ccc0fe0 | |||
| a56e187352 | |||
| dcdcc659ef | |||
| ae8e844dec | |||
| e566ba54d9 | |||
| 70732afb95 | |||
| f2aed69f87 | |||
| 6bd96522e8 | |||
| 1e26c352d6 | |||
| 2de65ebd4d | |||
| ed3d9aaaed | |||
| 27a3998c8f | |||
| 979c124e57 | |||
| 20ad839075 | |||
| bed67edd2e | |||
| 6efcc02806 | |||
| 8a6dd2805f | |||
| 464219c0fa | |||
| e602768794 | |||
| 262f2a1453 | |||
| b408967278 | |||
| 1fd97fed91 | |||
| fef179b625 | |||
| 87ac411c50 | |||
| 46a7aaac76 | |||
| e14d6fe9d5 | |||
| fb5b2d3d8e | |||
| 9dccdd1008 | |||
| 8e8a746cce | |||
| ee71effe98 | |||
| ce2c4f0f08 | |||
| ef9dbf73cc | |||
| 3bed5334bf | |||
| 5dc940ead2 | |||
| 7872b41f16 | |||
| be81f6b4ab | |||
| 1229032b4e | |||
| ad73e2d07b | |||
| 6d80135342 | |||
| c36a10da83 | |||
| c30d09cef4 | |||
| 716e0b97bd | |||
| ff862dc926 | |||
| 17c2a1cb4e | |||
| 895e640fd0 | |||
| e8f5f86ad5 | |||
| 5055b41ee7 | |||
| 7efd08ca2e | |||
| 76b421e064 | |||
| 063e6baa0a | |||
| 9e5d412a8b | |||
| fa9b634d8f | |||
| d76379428d | |||
| 46509b6dd2 | |||
| 89dbf9cc81 | |||
| c138aaabf3 | |||
| 7cef454c86 | |||
| 5cb8d15505 | |||
| 2aab55983d | |||
| 31714e5c1d | |||
| 96c351e792 | |||
| edd57004d3 | |||
| 234d20641c | |||
| dd802f21e7 | |||
| dbbc990c72 | |||
| 3a6e772cba | |||
| c9fa16fcfa | |||
| 07b04fbea9 | |||
| 1c633cbea2 | |||
| 2f685d5d2a | |||
| 0fdf2cc195 | |||
| 4f7d18a28f | |||
| c77272a7d7 | |||
| 7a1004df73 | |||
| 0e86d2b345 | |||
| 2441bdb900 | |||
| 57679b7b7f | |||
| 37063e7a05 | |||
| 791dc7b9be | |||
| ff24dfb2e7 | |||
| 4db60fa5a8 | |||
| 5301367630 | |||
| 9409b7ef7d | |||
| afeb7f668b | |||
| 38b8da0f5f | |||
| d029b62d23 | |||
| 1e9bdb4647 | |||
| 1d72024605 | |||
| 06570443b7 | |||
| 77f7caf18d | |||
| 8767ffde2f | |||
| d58b7fa779 | |||
| dcbf3f8879 | |||
| 30d8c8e17c | |||
| b803bb5edb | |||
| 985a39d41f | |||
| f846eec894 | |||
| e7fc8ad1f5 | |||
| 95169ad54b | |||
| ddb2e91a42 | |||
| 90357193c9 | |||
| a336fe2850 | |||
| fcb8e4cf37 | |||
| b7b6c147f9 | |||
| 35ee82ca07 | |||
| 2dc56a6e9b | |||
| e12ef76de5 | |||
| 536b05e35b | |||
| 1354854d23 | |||
| 2b062d60f2 | |||
| c8bdb4c7fb | |||
| 80328e8a4f | |||
| 1138e3770b | |||
| ec58013b22 | |||
| 70cb61fb71 | |||
| 8e6a0ec23d | |||
| e2ab334636 | |||
| dd0effe957 | |||
| ac210c1765 | |||
| c58e48e648 | |||
| acdadab617 | |||
| aa19194f7b | |||
| 9319a6e39b | |||
| b41206abab | |||
| 07c3dc6b6f | |||
| fa71a2a993 | |||
| b997d1e892 | |||
| 4b71fba540 | |||
| 48d39c0a57 | |||
| 0aad053507 | |||
| 6ed14b2a5f | |||
| c7df5ef957 | |||
| a9013febcf | |||
| 815c430ba1 | |||
| e94d5bf006 | |||
| a00480f4a1 | |||
| 6da952100c | |||
| df8588e9b7 | |||
| fce9b35e4d | |||
| 6fd4421add | |||
| 7149bfd100 | |||
| 344ad0355e | |||
| e7871fbc43 | |||
| 99d8dd751e | |||
| 22b1abb36d | |||
| aa289d1023 | |||
| ef51e02767 | |||
| 7118127139 | |||
| 2ce2afa036 | |||
| 5803dd765d | |||
| 6a310b5069 | |||
| 2caab68be9 | |||
| 4e2dbc1258 | |||
| 40eca1a68e | |||
| 98f937ba15 | |||
| a70988ecd5 | |||
| 6f2ff620bd | |||
| bd772610b1 | |||
| de42b5bfae | |||
| fcdd5173bd | |||
| c419799313 | |||
| c5973a630b | |||
| e5a88b64b1 | |||
| 74f58a49b9 | |||
| cff9d9f5eb | |||
| ddd64f2918 | |||
| 9f06f53a59 | |||
| 4c00d7a306 | |||
| 88726e12f7 | |||
| 248bb148af | |||
| 49589e1da1 | |||
| 552267b93d | |||
| 855357f871 | |||
| c83cba2322 | |||
| 20dcc31d19 | |||
| 29e6cc5808 | |||
| 4e6ee28bcb | |||
| 4b3247576a | |||
| 69edf17c2a | |||
| d91a4ad1dd | |||
| 9b750ef69f | |||
| 0bf22ee3ce | |||
| 981ed22dff | |||
| d40321ef63 | |||
| c94996e8e8 | |||
| 4b19dd46dd | |||
| 942e841cbc | |||
| e0a595273a | |||
| 92ca52822c | |||
| f89dbce93c | |||
| 28f0e2eb2a | |||
| 47ac080565 | |||
| afdf5cfde9 | |||
| a4760bcff7 | |||
| 72e571a3de | |||
| 484c0fdd15 | |||
| 2636fb7c8d | |||
| 99c2936e90 | |||
| 66c74d6091 | |||
| a43ba245e2 | |||
| 810d734eda | |||
| 687d6c5dc4 | |||
| 5e090c1fac | |||
| ceb61e6600 | |||
| ae60293c24 | |||
| e411081c84 | |||
| 0682a5e45e | |||
| 4f751aa53d | |||
| 27fa51cfa6 | |||
| 2772ff624f | |||
| 69b160cfe8 | |||
| ee7541c032 | |||
| abf6068d91 | |||
| 9d5f3e787d | |||
| ab2b9ba444 | |||
| 6ab1aff531 | |||
| 6012276093 | |||
| 9648cf226b | |||
| 56532a505d | |||
| 6bb2e5625a | |||
| d57a5dffa1 | |||
| 1028ca0841 | |||
| 6dbe6b42c2 | |||
| 7611c3ea03 | |||
| 2fa9f934b6 | |||
| e9fd7b7ed6 | |||
| 075e954b71 | |||
| 3f7122b3d2 | |||
| 35251c6d9c | |||
| 173594365c | |||
| 2fc44fb27d | |||
| 0264630c90 | |||
| 208769f70f | |||
| c5bffb9fb5 | |||
| c7afa5452b | |||
| c7c6e83779 | |||
| fcb6adaaaa | |||
| 9c12b58e32 | |||
| 6c8b505f93 | |||
| 8b228e7471 | |||
| 4ce07f41ca | |||
| 1bfd0e5e38 | |||
| b962d37f79 | |||
| c6ecf02a07 | |||
| 8b7d4b423c | |||
| 83dc126565 | |||
| f2d3d7e710 | |||
| f991428cb9 | |||
| e2b4108377 | |||
| c9cf7b1e08 | |||
| 4d865cd7ba | |||
| a55458a84a | |||
| 66d8631c23 | |||
| 5c1ad88137 | |||
| e230c9c6f0 | |||
| 6d24a2c942 | |||
| 5222dc0cd1 | |||
| 02c484e844 | |||
| 5face79cd0 | |||
| 51a72a9c53 | |||
| f609d9cd59 | |||
| 3901c6ab91 | |||
| da6f86bd79 | |||
| 42fd499af4 | |||
| de5b88477a | |||
| cd49a7f9e9 | |||
| df025fcb88 | |||
| bbb1404bd3 | |||
| af2a172197 | |||
| 252b9fc39c | |||
| 6fc5e04d7c | |||
| 66f1fef083 | |||
| 645d4807c3 | |||
| e2c360ada0 | |||
| a463ead739 | |||
| dbe5e57b8e | |||
| 99b99d7b23 | |||
| 787111a145 | |||
| 9a872f059f | |||
| eadc94e0a1 | |||
| f8855e892a | |||
| 27d05014e3 | |||
| ebb58b7cbc | |||
| 7f6895a4bb | |||
| 80ae4c1a69 | |||
| e72df9cd5f | |||
| 80ba529fb9 | |||
| fd6b3ef5a0 | |||
| 4cd0a39794 | |||
| 5fbc510f94 | |||
| 600ab5ba5f | |||
| ae92181d02 | |||
| 66910ed998 | |||
| 5371e4403e | |||
| 79375dd7dd | |||
| 6889609ab9 | |||
| 0bf87281e0 | |||
| bc7bed7517 | |||
| cfac6fd752 | |||
| 97c09c827b | |||
| 0370672886 | |||
| 2d062fedd9 | |||
| c6a68f3de2 | |||
| d6181b2335 | |||
| d74e62886c | |||
| d8505f09eb | |||
| 935c6aade0 | |||
| a35c35f849 | |||
| 57518a2bb4 | |||
| 99a8202015 | |||
| 17c903e246 | |||
| 4de5d225db | |||
| 7741df9963 | |||
| 7ef54e9c53 | |||
| 12bb700c62 | |||
| e3ba7250f1 | |||
| 54842095c3 | |||
| d1aec0c3f1 | |||
| 00d5f72d6e | |||
| 15d01d4315 | |||
| 348e34f221 | |||
| ce7b0656c0 | |||
| fd0d360f9b | |||
| f26cae3838 | |||
| b8468af411 | |||
| 9fd7e319f3 | |||
| 80a8b59f24 | |||
| b9d4da9cfe | |||
| 5bf5b58eb3 | |||
| b2c227e9c5 | |||
| d854228d58 | |||
| a0c09bc2a9 | |||
| aca3b2da58 | |||
| 604541863c | |||
| fd9e0dd13a | |||
| da535164b4 | |||
| 82d9570ed4 | |||
| a619e8af4a | |||
| 25ec20d861 | |||
| 0579220546 | |||
| 031c37c7b0 | |||
| 860821114a | |||
| 73bba62d82 | |||
| 42249ce28e |
+1
-1
@@ -167,7 +167,7 @@ macos:
|
||||
needs: []
|
||||
before_script:
|
||||
- bash .gitlab-ci/show-info-osx.sh
|
||||
- pip3 install --user meson==0.56
|
||||
- pip3 install --user meson==0.59
|
||||
- pip3 install --user ninja
|
||||
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
|
||||
- export MESON_FORCE_BACKTRACE=1
|
||||
|
||||
@@ -5,7 +5,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
|
||||
@echo on
|
||||
|
||||
:: FIXME: make warnings fatal
|
||||
pip3 install --upgrade --user meson==0.56.2 || goto :error
|
||||
pip3 install --upgrade --user meson==0.59 || goto :error
|
||||
meson -Dmedia-gstreamer=disabled _build || goto :error
|
||||
ninja -C _build || goto :error
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ pacman --noconfirm -S --needed \
|
||||
mingw-w64-$MSYS2_ARCH-pango \
|
||||
mingw-w64-$MSYS2_ARCH-fribidi \
|
||||
mingw-w64-$MSYS2_ARCH-gst-plugins-bad \
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info \
|
||||
mingw-w64-$MSYS2_ARCH-python-gobject
|
||||
|
||||
mkdir -p _ccache
|
||||
export CCACHE_BASEDIR="$(pwd)"
|
||||
|
||||
@@ -1,8 +1,127 @@
|
||||
Overview of Changes
|
||||
===================
|
||||
|
||||
* GtkProgressBar:
|
||||
- Fix handling of "inverted"
|
||||
|
||||
* GtkLabel:
|
||||
- Add a "natural wrap mode" property to influence how
|
||||
natural width is determined
|
||||
|
||||
* GtkTextView
|
||||
- Scroll insertion on-screen after undo / redo
|
||||
|
||||
* gsk:
|
||||
- Abort region diffing when changes are too complex
|
||||
|
||||
* gdk:
|
||||
- Avoid compressing discrete scroll events
|
||||
- Fix problems with hiding windows
|
||||
- Improve GL and GLES version checks
|
||||
|
||||
* Wayland:
|
||||
- Support new high-contrast setting
|
||||
|
||||
* Inspector:
|
||||
- Add DND inspection support
|
||||
|
||||
* build:
|
||||
- Avoid deprecated meson apis
|
||||
|
||||
* Translation updates
|
||||
Galician
|
||||
Portuguese
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.5.1, 16-12-2021
|
||||
========================================
|
||||
|
||||
* GtkWidget sizing has been rewritten to implement
|
||||
width-for-height more properly. This had some fallout,
|
||||
and some widgets may still not react kindly to the
|
||||
new way of doing things.
|
||||
|
||||
See https://blog.gtk.org/2021/12/03/sizable-news/
|
||||
for details, and please file issues if you notice fallout.
|
||||
|
||||
* Rename git `master` branch to `main`
|
||||
|
||||
* Css:
|
||||
- Fully support font-variant-caps
|
||||
- Fix a crash with gradients
|
||||
|
||||
* Make various widgets activatable:
|
||||
- GtkComboBox
|
||||
- GtkDropDown
|
||||
|
||||
* GtkPopover:
|
||||
- Make focus indicators not disappear
|
||||
|
||||
* GtkTextView:
|
||||
- Don't leave embedded children stranded when scrolling
|
||||
- Don't insert Emoji into non-editable textviews
|
||||
- Fix Emoji chooser positioning
|
||||
- Fix problems with pasting text
|
||||
- Improve scroll-to-mark behavior
|
||||
- Support right-aligned, centered and decimal tabs
|
||||
- Make child anchor replacement character settable
|
||||
- Provide more context to input methods
|
||||
|
||||
* GtkDragIcon:
|
||||
- Provide default icons for paintables and files
|
||||
|
||||
* GtkBuilder:
|
||||
- Speed up template precompilation
|
||||
|
||||
* Actions:
|
||||
- Reduce allocations during signal emissions
|
||||
- Avoid duplication and unnecessary recursion
|
||||
|
||||
* Inspector:
|
||||
- Show the selected im-module in the General tab
|
||||
- Add a clipboard viewer
|
||||
- Make the recorder record events too
|
||||
- Add a graph visualizing gtk_widget_measure()
|
||||
|
||||
* Gsk:
|
||||
- Fix hexbox rendering
|
||||
- Fix transformed linear gradient rendering
|
||||
|
||||
* Printing:
|
||||
- Fix dialog-less printing
|
||||
|
||||
* Windows:
|
||||
- Use the common EGL setup code
|
||||
- Respect GDK_DEBUG=gl-egl
|
||||
- Fix AeroSnap indicator and positioning
|
||||
|
||||
* X11:
|
||||
- Improve behavior of windows drags on headerbar controls
|
||||
- Trap errors for RANDR changes
|
||||
- Fix problems with drag icons
|
||||
|
||||
* Wayland:
|
||||
- Ensure we prefer the Wayland im-module over others
|
||||
|
||||
* Translation updates
|
||||
Basque
|
||||
Catalan
|
||||
Croatian
|
||||
Friulian
|
||||
Galician
|
||||
Hebrew
|
||||
Icelandic
|
||||
Italian
|
||||
Latvian
|
||||
Lithuanian
|
||||
Occitan
|
||||
Persian
|
||||
Portuguese
|
||||
Spanish
|
||||
Swedish
|
||||
Ukrainian
|
||||
|
||||
Overview of Changes in 4.5.0
|
||||
============================
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ executable('gtk4-constraint-editor',
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_dep,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: false,
|
||||
)
|
||||
|
||||
+316
-127
@@ -1,12 +1,10 @@
|
||||
/* Clipboard
|
||||
*
|
||||
* GdkClipboard is used for clipboard handling. This demo shows how to
|
||||
* copy and paste text to and from the clipboard.
|
||||
* copy and paste text, images, colors or files to and from the clipboard.
|
||||
*
|
||||
* It also shows how to transfer images via the clipboard or via
|
||||
* drag-and-drop, and how to make clipboard contents persist after
|
||||
* the application exits. Clipboard persistence requires a clipboard
|
||||
* manager to run.
|
||||
* You can also use Drag-And-Drop to copy the data from the source to the
|
||||
* target.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
@@ -14,22 +12,103 @@
|
||||
#include <string.h>
|
||||
#include "demoimage.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static void
|
||||
copy_button_clicked (GtkStack *source_stack,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
const char *visible_child_name;
|
||||
GtkWidget *visible_child;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (source_stack));
|
||||
|
||||
visible_child = gtk_stack_get_visible_child (source_stack);
|
||||
visible_child_name = gtk_stack_get_visible_child_name (source_stack);
|
||||
|
||||
if (strcmp (visible_child_name, "Text") == 0)
|
||||
{
|
||||
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (visible_child)));
|
||||
}
|
||||
else if (strcmp (visible_child_name, "Image") == 0)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
for (child = gtk_widget_get_first_child (visible_child); child; child = gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (child)))
|
||||
{
|
||||
GtkWidget *image = gtk_widget_get_first_child (child);
|
||||
GdkPaintable *paintable = gtk_image_get_paintable (GTK_IMAGE (image));
|
||||
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, paintable);
|
||||
else
|
||||
gdk_clipboard_set (clipboard, GDK_TYPE_PAINTABLE, paintable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp (visible_child_name, "Color") == 0)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (visible_child), &color);
|
||||
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, &color);
|
||||
}
|
||||
else if (strcmp (visible_child_name, "File") == 0)
|
||||
{
|
||||
gdk_clipboard_set (clipboard, G_TYPE_FILE, g_object_get_data (G_OBJECT (visible_child), "file"), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("TODO");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
copy_button_clicked (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
present_value (GtkStack *dest_stack,
|
||||
const GValue *value)
|
||||
{
|
||||
GtkWidget *entry;
|
||||
GdkClipboard *clipboard;
|
||||
GtkWidget *child;
|
||||
|
||||
entry = GTK_WIDGET (user_data);
|
||||
if (G_VALUE_HOLDS (value, G_TYPE_FILE))
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
/* Get the clipboard object */
|
||||
clipboard = gtk_widget_get_clipboard (entry);
|
||||
gtk_stack_set_visible_child_name (dest_stack, "File");
|
||||
child = gtk_stack_get_visible_child (dest_stack);
|
||||
|
||||
/* Set clipboard text */
|
||||
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (entry)));
|
||||
file = g_value_get_object (value);
|
||||
g_object_set (child, "label", g_file_peek_path (file), NULL);
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
|
||||
{
|
||||
GdkRGBA *color;
|
||||
|
||||
gtk_stack_set_visible_child_name (dest_stack, "Color");
|
||||
child = gtk_widget_get_first_child (gtk_stack_get_visible_child (dest_stack));
|
||||
|
||||
color = g_value_get_boxed (value);
|
||||
g_object_set (child, "rgba", color, NULL);
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE) ||
|
||||
G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE))
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
|
||||
gtk_stack_set_visible_child_name (dest_stack, "Image");
|
||||
child = gtk_stack_get_visible_child (dest_stack);
|
||||
|
||||
paintable = g_value_get_object (value);
|
||||
g_object_set (child, "paintable", paintable, NULL);
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, G_TYPE_STRING))
|
||||
{
|
||||
gtk_stack_set_visible_child_name (dest_stack, "Text");
|
||||
child = gtk_stack_get_visible_child (dest_stack);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (child), g_value_get_string (value));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -37,149 +116,259 @@ paste_received (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkStack *dest_stack = user_data;
|
||||
GdkClipboard *clipboard;
|
||||
GtkWidget *entry;
|
||||
char *text;
|
||||
const GValue *value;
|
||||
GError *error = NULL;
|
||||
|
||||
clipboard = GDK_CLIPBOARD (source_object);
|
||||
entry = GTK_WIDGET (user_data);
|
||||
|
||||
/* Get the resulting text of the read operation */
|
||||
text = gdk_clipboard_read_text_finish (clipboard, result, &error);
|
||||
|
||||
if (text)
|
||||
value = gdk_clipboard_read_value_finish (clipboard, result, &error);
|
||||
if (value)
|
||||
{
|
||||
/* Set the entry text */
|
||||
gtk_editable_set_text (GTK_EDITABLE (entry), text);
|
||||
g_free (text);
|
||||
present_value (dest_stack, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
/* Show an error about why pasting failed.
|
||||
* Usually you probably want to ignore such failures,
|
||||
* but for demonstration purposes, we show the error.
|
||||
*/
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Could not paste text: %s",
|
||||
error->message);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
g_print ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
paste_button_clicked (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
paste_button_clicked (GtkStack *dest_stack,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *entry;
|
||||
GdkClipboard *clipboard;
|
||||
GdkContentFormats *formats;
|
||||
|
||||
entry = GTK_WIDGET (user_data);
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (dest_stack));
|
||||
formats = gdk_clipboard_get_formats (clipboard);
|
||||
|
||||
/* Get the clipboard object */
|
||||
clipboard = gtk_widget_get_clipboard (entry);
|
||||
if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE))
|
||||
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_TEXTURE, 0, NULL, paste_received, dest_stack);
|
||||
else if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_PAINTABLE))
|
||||
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_PAINTABLE, 0, NULL, paste_received, dest_stack);
|
||||
else if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_RGBA))
|
||||
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_RGBA, 0, NULL, paste_received, dest_stack);
|
||||
else if (gdk_content_formats_contain_gtype (formats, G_TYPE_FILE))
|
||||
gdk_clipboard_read_value_async (clipboard, G_TYPE_FILE, 0, NULL, paste_received, dest_stack);
|
||||
else if (gdk_content_formats_contain_gtype (formats, G_TYPE_STRING))
|
||||
gdk_clipboard_read_value_async (clipboard, G_TYPE_STRING, 0, NULL, paste_received, dest_stack);
|
||||
}
|
||||
|
||||
/* Request the contents of the clipboard, contents_received will be
|
||||
called when we do get the contents.
|
||||
*/
|
||||
gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
|
||||
static void
|
||||
update_copy_button_sensitivity (GtkWidget *source_stack)
|
||||
{
|
||||
GtkButton *copy_button;
|
||||
const char *visible_child_name;
|
||||
GtkWidget *visible_child;
|
||||
gboolean sensitive;
|
||||
|
||||
copy_button = GTK_BUTTON (g_object_get_data (G_OBJECT (source_stack), "copy-button"));
|
||||
|
||||
visible_child = gtk_stack_get_visible_child (GTK_STACK (source_stack));
|
||||
visible_child_name = gtk_stack_get_visible_child_name (GTK_STACK (source_stack));
|
||||
if (strcmp (visible_child_name, "Text") == 0)
|
||||
{
|
||||
sensitive = strlen (gtk_editable_get_text (GTK_EDITABLE (visible_child))) > 0;
|
||||
}
|
||||
else if (strcmp (visible_child_name, "Color") == 0 ||
|
||||
strcmp (visible_child_name, "Image") == 0)
|
||||
{
|
||||
sensitive = TRUE;
|
||||
}
|
||||
else if (strcmp (visible_child_name, "File") == 0)
|
||||
{
|
||||
sensitive = g_object_get_data (G_OBJECT (visible_child), "file") != NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensitive = FALSE;
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (copy_button), sensitive);
|
||||
}
|
||||
|
||||
static void
|
||||
source_changed_cb (GtkButton *copy_button,
|
||||
GParamSpec *pspec,
|
||||
GtkWidget *source_stack)
|
||||
{
|
||||
update_copy_button_sensitivity (source_stack);
|
||||
}
|
||||
|
||||
static void
|
||||
text_changed_cb (GtkButton *copy_button,
|
||||
GParamSpec *pspec,
|
||||
GtkWidget *entry)
|
||||
{
|
||||
update_copy_button_sensitivity (gtk_widget_get_ancestor (entry, GTK_TYPE_STACK));
|
||||
}
|
||||
|
||||
static void
|
||||
file_button_set_file (GtkButton *button,
|
||||
GFile *file)
|
||||
{
|
||||
gtk_label_set_label (GTK_LABEL (gtk_button_get_child (button)), g_file_peek_path (file));
|
||||
g_object_set_data_full (G_OBJECT (button), "file", g_object_ref (file), g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
file_chooser_response (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
GtkButton *button)
|
||||
{
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
file_button_set_file (button, file);
|
||||
g_object_unref (file);
|
||||
|
||||
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
|
||||
}
|
||||
|
||||
gtk_native_dialog_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
open_file_cb (GtkWidget *button)
|
||||
{
|
||||
GtkFileChooserNative *chooser;
|
||||
|
||||
chooser = gtk_file_chooser_native_new ("Choose a file",
|
||||
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"_Open",
|
||||
"_Cancel");
|
||||
|
||||
g_signal_connect (chooser, "response", G_CALLBACK (file_chooser_response), button);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
|
||||
}
|
||||
|
||||
static void
|
||||
update_paste_button_sensitivity (GdkClipboard *clipboard,
|
||||
GtkWidget *paste_button)
|
||||
{
|
||||
GdkContentFormats *formats;
|
||||
gboolean sensitive = FALSE;
|
||||
|
||||
formats = gdk_clipboard_get_formats (clipboard);
|
||||
|
||||
if (gdk_content_formats_contain_gtype (formats, G_TYPE_FILE) ||
|
||||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_RGBA) ||
|
||||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE) ||
|
||||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_PAINTABLE) ||
|
||||
gdk_content_formats_contain_gtype (formats, G_TYPE_STRING))
|
||||
sensitive = TRUE;
|
||||
|
||||
gtk_widget_set_sensitive (paste_button, sensitive);
|
||||
}
|
||||
|
||||
static void
|
||||
unset_clipboard_handler (gpointer data)
|
||||
{
|
||||
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
|
||||
|
||||
g_signal_handlers_disconnect_by_func (clipboard, update_paste_button_sensitivity, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_drop (GtkStack *dest_stack,
|
||||
const GValue *value,
|
||||
double x,
|
||||
double y,
|
||||
gpointer data)
|
||||
{
|
||||
present_value (dest_stack, value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
drag_prepare (GtkDragSource *drag_source,
|
||||
double x,
|
||||
double y,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *button;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
button = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag_source));
|
||||
|
||||
if (GTK_IS_TOGGLE_BUTTON (button))
|
||||
{
|
||||
GtkWidget *image = gtk_widget_get_first_child (button);
|
||||
GdkPaintable *paintable = gtk_image_get_paintable (GTK_IMAGE (image));
|
||||
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
{
|
||||
g_value_init (&value, GDK_TYPE_TEXTURE);
|
||||
g_value_set_object (&value, paintable);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_value_init (&value, GDK_TYPE_PAINTABLE);
|
||||
g_value_set_object (&value, paintable);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *file = g_object_get_data (G_OBJECT (button), "file");
|
||||
|
||||
if (file)
|
||||
{
|
||||
g_value_init (&value, G_TYPE_FILE);
|
||||
g_value_set_object (&value, file);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gdk_content_provider_new_for_value (&value);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_clipboard (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *vbox, *hbox;
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry, *button;
|
||||
GtkWidget *image;
|
||||
GtkBuilderScope *scope;
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *button;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Clipboard");
|
||||
scope = gtk_builder_cscope_new ();
|
||||
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
|
||||
"copy_button_clicked", G_CALLBACK (copy_button_clicked),
|
||||
"paste_button_clicked", G_CALLBACK (paste_button_clicked),
|
||||
"source_changed_cb", G_CALLBACK (source_changed_cb),
|
||||
"text_changed_cb", G_CALLBACK (text_changed_cb),
|
||||
"open_file_cb", G_CALLBACK (open_file_cb),
|
||||
"on_drop", G_CALLBACK (on_drop),
|
||||
"drag_prepare", G_CALLBACK (drag_prepare),
|
||||
NULL);
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_set_scope (builder, scope);
|
||||
gtk_builder_add_from_resource (builder, "/clipboard/clipboard.ui", NULL);
|
||||
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (vbox, 8);
|
||||
gtk_widget_set_margin_end (vbox, 8);
|
||||
gtk_widget_set_margin_top (vbox, 8);
|
||||
gtk_widget_set_margin_bottom (vbox, 8);
|
||||
button = GTK_WIDGET (gtk_builder_get_object (builder, "copy_button"));
|
||||
g_object_set_data (gtk_builder_get_object (builder, "source_stack"), "copy-button", button);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
button = GTK_WIDGET (gtk_builder_get_object (builder, "paste_button"));
|
||||
g_signal_connect (gtk_widget_get_clipboard (button), "changed",
|
||||
G_CALLBACK (update_paste_button_sensitivity), button);
|
||||
g_object_set_data_full (G_OBJECT (button), "clipboard-handler", button, unset_clipboard_handler);
|
||||
|
||||
label = gtk_label_new ("\"Copy\" will copy the text\nin the entry to the clipboard");
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
|
||||
/* Create the first entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (hbox), entry);
|
||||
|
||||
/* Create the button */
|
||||
button = gtk_button_new_with_mnemonic (_("_Copy"));
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (copy_button_clicked), entry);
|
||||
|
||||
label = gtk_label_new ("\"Paste\" will paste the text from the clipboard to the entry");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
|
||||
/* Create the second entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (hbox), entry);
|
||||
|
||||
/* Create the button */
|
||||
button = gtk_button_new_with_mnemonic (_("_Paste"));
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (paste_button_clicked), entry);
|
||||
|
||||
label = gtk_label_new ("Images can be transferred via the clipboard, too");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
|
||||
/* Create the first image */
|
||||
image = demo_image_new ("dialog-warning");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
|
||||
/* Create the second image */
|
||||
image = demo_image_new ("process-stop");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
|
||||
/* Create the third image */
|
||||
image = demo_image_new ("weather-clear");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
g_object_unref (builder);
|
||||
g_object_unref (scope);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
|
||||
@@ -0,0 +1,288 @@
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="resizable">1</property>
|
||||
<property name="title">Clipboard</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-start">12</property>
|
||||
<property name="margin-end">12</property>
|
||||
<property name="margin-top">12</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">“Copy” will copy the selected data the clipboard, “Paste” will show the current clipboard contents. You can also drag the data to the bottom.</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="max-width-chars">40</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="source_chooser">
|
||||
<property name="valign">center</property>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item>Text</item>
|
||||
<item>Color</item>
|
||||
<item>Image</item>
|
||||
<item>File</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="source_stack">
|
||||
<signal name="notify::visible-child" handler="source_changed_cb" object="copy_button"/>
|
||||
<property name="vexpand">1</property>
|
||||
<binding name="visible-child-name">
|
||||
<lookup name="string" type="GtkStringObject">
|
||||
<lookup name="selected-item">
|
||||
source_chooser
|
||||
</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkEntry" id="source_text">
|
||||
<property name="valign">center</property>
|
||||
<signal name="notify::text" handler="text_changed_cb" object="copy_button"/>
|
||||
<property name="text">Copy this!</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Color</property>
|
||||
<property name="child">
|
||||
<object class="GtkColorButton" id="source_color">
|
||||
<property name="valign">center</property>
|
||||
<property name="rgba">purple</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Image</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_rose">
|
||||
<property name="active">1</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
<property name="paintable">resource:///transparent/portland-rose.jpg</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_floppy">
|
||||
<property name="group">image_rose</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
<property name="paintable">resource:///images/floppybuddy.gif</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_logo">
|
||||
<property name="group">image_floppy</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
<property name="paintable">resource:///images/org.gtk.Demo4.svg</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="source_file">
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="propagation-phase">capture</property>
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<property name="valign">center</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">—</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ellipsize">start</property>
|
||||
</object>
|
||||
</property>
|
||||
<signal name="clicked" handler="open_file_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="copy_button">
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">_Copy</property>
|
||||
<signal name="clicked" handler="copy_button_clicked" object="source_stack"/>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkDropTarget">
|
||||
<property name="actions">copy</property>
|
||||
<property name="formats">GdkTexture GdkPaintable GFile GdkRGBA gchararray</property>
|
||||
<signal name="drop" handler="on_drop" object="dest_stack"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="paste_button">
|
||||
<property name="label" translatable="yes">_Paste</property>
|
||||
<signal name="clicked" handler="paste_button_clicked" object="dest_stack"/>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="visible-child-name" type="GtkStack">
|
||||
dest_stack
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="dest_stack">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name"></property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Image</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Color</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkColorSwatch">
|
||||
<property name="accessible-role">img</property>
|
||||
<property name="can-focus">0</property>
|
||||
<property name="selectable">0</property>
|
||||
<property name="has-menu">0</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="ellipsize">start</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -15,6 +15,7 @@
|
||||
<file>demo.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/clipboard">
|
||||
<file>clipboard.ui</file>
|
||||
<file>demoimage.c</file>
|
||||
<file>demoimage.h</file>
|
||||
</gresource>
|
||||
|
||||
@@ -45,9 +45,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<property name="label" translatable="yes">Font Features</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"></attribute>
|
||||
</attributes>
|
||||
<property name="attributes" translatable="yes">0 -1 weight bold</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -75,9 +73,7 @@
|
||||
<object class="GtkLabel" id="variations_heading">
|
||||
<property name="label" translatable="yes">Font Variations</property>
|
||||
<property name="xalign">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"></attribute>
|
||||
</attributes>
|
||||
<property name="attributes" translatable="yes">0 -1 weight bold</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Save _As...</attribute>
|
||||
<attribute name="action">app.save-as</attribute>
|
||||
<attribute name="accel"><Control>s</attribute>
|
||||
<attribute name="accel"><Control><Shift>s</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
|
||||
@@ -242,7 +242,7 @@ executable('gtk4-demo',
|
||||
c_args: gtkdemo_args + demo_cflags,
|
||||
dependencies: gtkdemo_deps,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
||||
@@ -252,7 +252,7 @@ executable('gtk4-demo-application',
|
||||
c_args: gtkdemo_args + common_cflags,
|
||||
dependencies: gtkdemo_deps,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ executable('gtk4-icon-browser',
|
||||
c_args: common_cflags,
|
||||
dependencies: [ libgtk_dep, demo_conf_h ],
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ demo_profile = get_option('profile')
|
||||
|
||||
demo_conf_h = declare_dependency(
|
||||
sources: custom_target('demo-header',
|
||||
command: [gen_demo_header, meson.source_root(), demo_profile],
|
||||
command: [gen_demo_header, meson.project_source_root(), demo_profile],
|
||||
capture: true,
|
||||
output: 'demo_conf.h',
|
||||
build_by_default: true,
|
||||
|
||||
@@ -17,7 +17,7 @@ executable('gtk4-node-editor',
|
||||
c_args: [
|
||||
'-DNODE_EDITOR_SOURCE_DIR="@0@/../../testsuite/gsk/compare/"'.format(meson.current_source_dir())
|
||||
] + common_cflags,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: false,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ executable('gtk4-print-editor',
|
||||
c_args: common_cflags,
|
||||
dependencies: [ libgtk_dep, demo_conf_h ],
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
||||
|
||||
@@ -74,7 +74,7 @@ executable('gtk4-widget-factory',
|
||||
c_args: common_cflags,
|
||||
dependencies: [ libgtk_dep, demo_conf_h ],
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
win_subsystem: 'windows',
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
||||
|
||||
@@ -1927,6 +1927,12 @@ microphone-sensitivity-medium-symbolic</property>
|
||||
<property name="tooltip-text" translatable="1">Insert something</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColorButton">
|
||||
<property name="rgba">#9141AC</property>
|
||||
<property name="tooltip-text" translatable="1">Select a color</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -1276,6 +1276,15 @@ is provided in the form of a `GtkIconPaintable` (this can be checked with
|
||||
[method@Gtk.IconPaintable.is_symbolic]), you have to call
|
||||
[method@Gtk.IconPaintable.get_icon_name] and set the icon name on a `GtkImage`.
|
||||
|
||||
### Adapt to GtkImage changes
|
||||
`GtkPicture`'s behaviour was "split out" of `GtkImage` as the latter was covering
|
||||
too many use cases; if you're loading an icon, [class@Gtk.Image] in GTK3 and GTK4 are
|
||||
perfectly equivalent. If you are loading a more complex image asset, like a picture
|
||||
or a thumbnail, then [class@Gtk.Picture] is the appropriate widget.
|
||||
|
||||
One noteworthy distinction is that while `GtkImage` has its size computed by
|
||||
GTK, `GtkPicture` lets you decide about the size.
|
||||
|
||||
### Update to GtkFileChooser API changes
|
||||
|
||||
`GtkFileChooser` moved to a GFile-based API. If you need to convert a path
|
||||
|
||||
@@ -286,7 +286,7 @@ requires that GTK is compiled with support for that backend.
|
||||
The following backends can be selected, provided they are
|
||||
included in the GDK libraries you are using:
|
||||
|
||||
`quartz`
|
||||
`macos`
|
||||
: Selects the native Quartz backend
|
||||
|
||||
`win32`
|
||||
@@ -336,9 +336,6 @@ using and the GDK backend supports them:
|
||||
`gl`
|
||||
: Selects the "gl" OpenGL renderer
|
||||
|
||||
`ngl`
|
||||
: Selects the "ngl" OpenGL renderer
|
||||
|
||||
`vulkan`
|
||||
: Selects the Vulkan renderer
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
typedef struct _Deserializer Deserializer;
|
||||
|
||||
struct _Deserializer
|
||||
struct _Deserializer
|
||||
{
|
||||
const char * mime_type; /* interned */
|
||||
GType type;
|
||||
@@ -264,7 +264,7 @@ gdk_content_deserializer_get_priority (GdkContentDeserializer *deserializer)
|
||||
*
|
||||
* This is the `GCancellable` that was passed to [func@Gdk.content_deserialize_async].
|
||||
*
|
||||
* Returns: (transfer none): the cancellable for the current operation
|
||||
* Returns: (transfer none) (nullable): the cancellable for the current operation
|
||||
*/
|
||||
GCancellable *
|
||||
gdk_content_deserializer_get_cancellable (GdkContentDeserializer *deserializer)
|
||||
@@ -934,25 +934,6 @@ init (void)
|
||||
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
|
||||
/* Make sure png comes first */
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
char *name;
|
||||
|
||||
name = gdk_pixbuf_format_get_name (fmt);
|
||||
if (g_str_equal (name, "png"))
|
||||
{
|
||||
formats = g_slist_delete_link (formats, f);
|
||||
formats = g_slist_prepend (formats, fmt);
|
||||
|
||||
g_free (name);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
|
||||
+26
-12
@@ -718,19 +718,33 @@ gdk_content_formats_builder_to_formats (GdkContentFormatsBuilder *builder)
|
||||
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
gtypes = g_new (GType, builder->n_gtypes + 1);
|
||||
i = builder->n_gtypes;
|
||||
gtypes[i--] = G_TYPE_INVALID;
|
||||
/* add backwards because most important type is last in the list */
|
||||
for (l = builder->gtypes; l; l = l->next)
|
||||
gtypes[i--] = GPOINTER_TO_SIZE (l->data);
|
||||
if (builder->n_gtypes > 0)
|
||||
{
|
||||
gtypes = g_new (GType, builder->n_gtypes + 1);
|
||||
i = builder->n_gtypes;
|
||||
gtypes[i--] = G_TYPE_INVALID;
|
||||
/* add backwards because most important type is last in the list */
|
||||
for (l = builder->gtypes; l; l = l->next)
|
||||
gtypes[i--] = GPOINTER_TO_SIZE (l->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtypes = NULL;
|
||||
}
|
||||
|
||||
mime_types = g_new (const char *, builder->n_mime_types + 1);
|
||||
i = builder->n_mime_types;
|
||||
mime_types[i--] = NULL;
|
||||
/* add backwards because most important type is last in the list */
|
||||
for (l = builder->mime_types; l; l = l->next)
|
||||
mime_types[i--] = l->data;
|
||||
if (builder->n_mime_types > 0)
|
||||
{
|
||||
mime_types = g_new (const char *, builder->n_mime_types + 1);
|
||||
i = builder->n_mime_types;
|
||||
mime_types[i--] = NULL;
|
||||
/* add backwards because most important type is last in the list */
|
||||
for (l = builder->mime_types; l; l = l->next)
|
||||
mime_types[i--] = l->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
mime_types = NULL;
|
||||
}
|
||||
|
||||
result = gdk_content_formats_new_take (gtypes, builder->n_gtypes,
|
||||
mime_types, builder->n_mime_types);
|
||||
|
||||
@@ -342,7 +342,7 @@ gdk_content_provider_write_mime_type_finish (GdkContentProvider *provider,
|
||||
/**
|
||||
* gdk_content_provider_get_value:
|
||||
* @provider: a `GdkContentProvider`
|
||||
* @value: the `GValue` to fill
|
||||
* @value: (out caller-allocates): the `GValue` to fill
|
||||
* @error: a `GError` location to store the error occurring
|
||||
*
|
||||
* Gets the contents of @provider stored in @value.
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
typedef struct _Serializer Serializer;
|
||||
|
||||
struct _Serializer
|
||||
struct _Serializer
|
||||
{
|
||||
const char * mime_type; /* interned */
|
||||
GType type;
|
||||
@@ -270,7 +270,7 @@ gdk_content_serializer_get_priority (GdkContentSerializer *serializer)
|
||||
*
|
||||
* This is the `GCancellable` that was passed to [func@content_serialize_async].
|
||||
*
|
||||
* Returns: (transfer none): the cancellable for the current operation
|
||||
* Returns: (transfer none) (nullable): the cancellable for the current operation
|
||||
*/
|
||||
GCancellable *
|
||||
gdk_content_serializer_get_cancellable (GdkContentSerializer *serializer)
|
||||
@@ -446,7 +446,7 @@ lookup_serializer (const char *mime_type,
|
||||
serializer->type == type)
|
||||
return serializer;
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ pixbuf_serializer (GdkContentSerializer *serializer)
|
||||
const GValue *value;
|
||||
GdkPixbuf *pixbuf;
|
||||
const char *name;
|
||||
|
||||
|
||||
name = gdk_content_serializer_get_user_data (serializer);
|
||||
value = gdk_content_serializer_get_value (serializer);
|
||||
|
||||
@@ -651,7 +651,7 @@ pixbuf_serializer (GdkContentSerializer *serializer)
|
||||
gdk_pixbuf_save_to_stream_async (pixbuf,
|
||||
gdk_content_serializer_get_output_stream (serializer),
|
||||
name,
|
||||
gdk_content_serializer_get_cancellable (serializer),
|
||||
gdk_content_serializer_get_cancellable (serializer),
|
||||
pixbuf_serializer_finish,
|
||||
serializer,
|
||||
g_str_equal (name, "png") ? "compression" : NULL, "2",
|
||||
@@ -823,7 +823,7 @@ file_uri_serializer (GdkContentSerializer *serializer)
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_FILE_LIST))
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
|
||||
for (l = g_value_get_boxed (value); l; l = l->next)
|
||||
{
|
||||
uri = g_file_get_uri (l->data);
|
||||
@@ -867,7 +867,7 @@ file_text_serializer (GdkContentSerializer *serializer)
|
||||
{
|
||||
GString *str;
|
||||
GSList *l;
|
||||
|
||||
|
||||
str = g_string_new (NULL);
|
||||
|
||||
for (l = g_value_get_boxed (value); l; l = l->next)
|
||||
@@ -966,25 +966,6 @@ init (void)
|
||||
|
||||
formats = gdk_pixbuf_get_formats ();
|
||||
|
||||
/* Make sure png comes first */
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
char *name;
|
||||
|
||||
name = gdk_pixbuf_format_get_name (fmt);
|
||||
if (g_str_equal (name, "png"))
|
||||
{
|
||||
formats = g_slist_delete_link (formats, f);
|
||||
formats = g_slist_prepend (formats, fmt);
|
||||
|
||||
g_free (name);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
for (f = formats; f; f = f->next)
|
||||
{
|
||||
GdkPixbufFormat *fmt = f->data;
|
||||
|
||||
+1
-2
@@ -47,8 +47,7 @@
|
||||
* Cursors by themselves are not very interesting: they must be bound to a
|
||||
* window for users to see them. This is done with [method@Gdk.Surface.set_cursor]
|
||||
* or [method@Gdk.Surface.set_device_cursor]. Applications will typically
|
||||
* use higher-level GTK functions such as [method@Gtk.Widget.set_cursor]`
|
||||
* instead.
|
||||
* use higher-level GTK functions such as [method@Gtk.Widget.set_cursor] instead.
|
||||
*
|
||||
* Cursors are not bound to a given [class@Gdk.Display], so they can be shared.
|
||||
* However, the appearance of cursors may vary when used on different
|
||||
|
||||
@@ -132,6 +132,8 @@ gdk_device_class_init (GdkDeviceClass *klass)
|
||||
* GdkDevice:source: (attributes org.gtk.Property.get=gdk_device_get_source)
|
||||
*
|
||||
* Source type for the device.
|
||||
*
|
||||
* Deprecated: 4.6: Use GdkDeviceTool:tool-type instead
|
||||
*/
|
||||
device_props[PROP_SOURCE] =
|
||||
g_param_spec_enum ("source",
|
||||
@@ -596,6 +598,8 @@ gdk_device_get_has_cursor (GdkDevice *device)
|
||||
* Determines the type of the device.
|
||||
*
|
||||
* Returns: a `GdkInputSource`
|
||||
*
|
||||
* Deprecated: 4.6: Use gdk_device_tool_get_tool_type() instead
|
||||
*/
|
||||
GdkInputSource
|
||||
gdk_device_get_source (GdkDevice *device)
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
GdkDisplay * gdk_device_get_display (GdkDevice *device);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkSeat * gdk_device_get_seat (GdkDevice *device);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GDK_DEPRECATED_IN_4_6_FOR(gdk_device_tool_get_tool_type)
|
||||
GdkDeviceTool * gdk_device_get_device_tool (GdkDevice *device);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
||||
+135
-62
@@ -19,7 +19,7 @@
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@@ -522,7 +522,9 @@ _gdk_event_queue_find_first (GdkDisplay *display)
|
||||
if (pending_motion)
|
||||
return pending_motion;
|
||||
|
||||
if (event->event_type == GDK_MOTION_NOTIFY && (event->flags & GDK_EVENT_FLUSHED) == 0)
|
||||
if ((event->event_type == GDK_MOTION_NOTIFY ||
|
||||
(event->event_type == GDK_SCROLL && gdk_scroll_event_get_direction (event) == GDK_SCROLL_SMOOTH)) &&
|
||||
(event->flags & GDK_EVENT_FLUSHED) == 0)
|
||||
pending_motion = tmp_list;
|
||||
else
|
||||
return tmp_list;
|
||||
@@ -596,6 +598,9 @@ _gdk_event_unqueue (GdkDisplay *display)
|
||||
/*
|
||||
* If the last N events in the event queue are smooth scroll events
|
||||
* for the same surface and device, combine them into one.
|
||||
*
|
||||
* We give the remaining event a history with N items, and deltas
|
||||
* that are the sum over the history entries.
|
||||
*/
|
||||
void
|
||||
gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
|
||||
@@ -605,7 +610,6 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
|
||||
GdkDevice *device = NULL;
|
||||
GdkEvent *last_event = NULL;
|
||||
GList *scrolls = NULL;
|
||||
double delta_x, delta_y;
|
||||
GArray *history = NULL;
|
||||
GdkTimeCoord hist;
|
||||
|
||||
@@ -640,35 +644,42 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
|
||||
l = l->prev;
|
||||
}
|
||||
|
||||
delta_x = delta_y = 0;
|
||||
|
||||
while (scrolls && scrolls->next != NULL)
|
||||
{
|
||||
GdkEvent *event = scrolls->data;
|
||||
GList *next = scrolls->next;
|
||||
double dx, dy;
|
||||
gboolean inherited = FALSE;
|
||||
|
||||
if (!history && ((GdkScrollEvent *)event)->history)
|
||||
{
|
||||
history = ((GdkScrollEvent *)event)->history;
|
||||
((GdkScrollEvent *)event)->history = NULL;
|
||||
inherited = TRUE;
|
||||
}
|
||||
|
||||
if (!history)
|
||||
history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
|
||||
|
||||
gdk_scroll_event_get_deltas (event, &dx, &dy);
|
||||
delta_x += dx;
|
||||
delta_y += dy;
|
||||
if (!inherited)
|
||||
{
|
||||
gdk_scroll_event_get_deltas (event, &dx, &dy);
|
||||
|
||||
memset (&hist, 0, sizeof (GdkTimeCoord));
|
||||
hist.time = gdk_event_get_time (event);
|
||||
hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
|
||||
hist.axes[GDK_AXIS_DELTA_X] = dx;
|
||||
hist.axes[GDK_AXIS_DELTA_Y] = dy;
|
||||
memset (&hist, 0, sizeof (GdkTimeCoord));
|
||||
hist.time = gdk_event_get_time (event);
|
||||
hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
|
||||
hist.axes[GDK_AXIS_DELTA_X] = dx;
|
||||
hist.axes[GDK_AXIS_DELTA_Y] = dy;
|
||||
|
||||
g_array_append_val (history, hist);
|
||||
g_array_append_val (history, hist);
|
||||
}
|
||||
|
||||
gdk_event_unref (event);
|
||||
g_queue_delete_link (&display->queued_events, scrolls);
|
||||
scrolls = next;
|
||||
}
|
||||
|
||||
if (scrolls)
|
||||
if (scrolls && history)
|
||||
{
|
||||
GdkEvent *old_event, *event;
|
||||
double dx, dy;
|
||||
@@ -676,13 +687,29 @@ gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
|
||||
old_event = scrolls->data;
|
||||
|
||||
gdk_scroll_event_get_deltas (old_event, &dx, &dy);
|
||||
|
||||
memset (&hist, 0, sizeof (GdkTimeCoord));
|
||||
hist.time = gdk_event_get_time (old_event);
|
||||
hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
|
||||
hist.axes[GDK_AXIS_DELTA_X] = dx;
|
||||
hist.axes[GDK_AXIS_DELTA_Y] = dy;
|
||||
g_array_append_val (history, hist);
|
||||
|
||||
dx = dy = 0;
|
||||
for (int i = 0; i < history->len; i++)
|
||||
{
|
||||
GdkTimeCoord *val = &g_array_index (history, GdkTimeCoord, i);
|
||||
dx += val->axes[GDK_AXIS_DELTA_X];
|
||||
dy += val->axes[GDK_AXIS_DELTA_Y];
|
||||
}
|
||||
|
||||
event = gdk_scroll_event_new (surface,
|
||||
device,
|
||||
gdk_event_get_device_tool (old_event),
|
||||
gdk_event_get_time (old_event),
|
||||
gdk_event_get_modifier_state (old_event),
|
||||
delta_x + dx,
|
||||
delta_y + dy,
|
||||
dx,
|
||||
dy,
|
||||
gdk_scroll_event_is_stop (old_event));
|
||||
|
||||
((GdkScrollEvent *)event)->history = history;
|
||||
@@ -714,24 +741,41 @@ gdk_motion_event_push_history (GdkEvent *event,
|
||||
g_assert (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY));
|
||||
g_assert (GDK_IS_EVENT_TYPE (history_event, GDK_MOTION_NOTIFY));
|
||||
|
||||
if (!self->tool)
|
||||
return;
|
||||
if (G_UNLIKELY (!self->history))
|
||||
self->history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
|
||||
|
||||
if (((GdkMotionEvent *)history_event)->history)
|
||||
{
|
||||
GArray *history = ((GdkMotionEvent *)history_event)->history;
|
||||
g_array_append_vals (self->history, history->data, history->len);
|
||||
}
|
||||
|
||||
tool = gdk_event_get_device_tool (history_event);
|
||||
|
||||
memset (&hist, 0, sizeof (GdkTimeCoord));
|
||||
hist.time = gdk_event_get_time (history_event);
|
||||
hist.flags = gdk_device_tool_get_axes (tool);
|
||||
|
||||
for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
|
||||
gdk_event_get_axis (history_event, i, &hist.axes[i]);
|
||||
|
||||
if (G_UNLIKELY (!self->history))
|
||||
self->history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
|
||||
if (tool)
|
||||
{
|
||||
hist.flags = gdk_device_tool_get_axes (tool);
|
||||
for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
|
||||
gdk_event_get_axis (history_event, i, &hist.axes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
hist.flags = GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
|
||||
gdk_event_get_position (history_event, &hist.axes[GDK_AXIS_X], &hist.axes[GDK_AXIS_Y]);
|
||||
}
|
||||
|
||||
g_array_append_val (self->history, hist);
|
||||
}
|
||||
|
||||
/* If the last N events in the event queue are motion notify
|
||||
* events for the same surface, drop all but the last.
|
||||
*
|
||||
* If a button is held down or the device has a tool, then
|
||||
* we give the remaining events a history containing the N-1
|
||||
* dropped events.
|
||||
*/
|
||||
void
|
||||
_gdk_event_queue_handle_motion_compression (GdkDisplay *display)
|
||||
{
|
||||
@@ -741,9 +785,6 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
|
||||
GdkDevice *pending_motion_device = NULL;
|
||||
GdkEvent *last_motion = NULL;
|
||||
|
||||
/* If the last N events in the event queue are motion notify
|
||||
* events for the same surface, drop all but the last */
|
||||
|
||||
tmp_list = g_queue_peek_tail_link (&display->queued_events);
|
||||
|
||||
while (tmp_list)
|
||||
@@ -780,12 +821,11 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
|
||||
|
||||
if (last_motion != NULL)
|
||||
{
|
||||
GdkModifierType state = gdk_event_get_modifier_state (last_motion);
|
||||
|
||||
if (state &
|
||||
(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
|
||||
GDK_BUTTON4_MASK | GDK_BUTTON5_MASK))
|
||||
gdk_motion_event_push_history (last_motion, pending_motions->data);
|
||||
if ((gdk_event_get_modifier_state (last_motion) &
|
||||
(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
|
||||
GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)) ||
|
||||
gdk_event_get_device_tool (last_motion) != NULL)
|
||||
gdk_motion_event_push_history (last_motion, pending_motions->data);
|
||||
}
|
||||
|
||||
gdk_event_unref (pending_motions->data);
|
||||
@@ -903,6 +943,9 @@ gdk_event_get_pointer_emulated (GdkEvent *event)
|
||||
* Extract the axis value for a particular axis use from
|
||||
* an event structure.
|
||||
*
|
||||
* To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
|
||||
* on the device tool returned by [method@Gdk.Event.get_device_tool].
|
||||
*
|
||||
* Returns: %TRUE if the specified axis was found, otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
@@ -1129,6 +1172,9 @@ G_DEFINE_BOXED_TYPE (GdkEventSequence, gdk_event_sequence,
|
||||
*
|
||||
* Extracts all axis values from an event.
|
||||
*
|
||||
* To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
|
||||
* on the device tool returned by [method@Gdk.Event.get_device_tool].
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
@@ -1179,7 +1225,7 @@ gdk_event_get_event_type (GdkEvent *event)
|
||||
*
|
||||
* Extracts the surface associated with an event.
|
||||
*
|
||||
* Returns: (transfer none): The `GdkSurface` associated with the event
|
||||
* Returns: (transfer none) (nullable): The `GdkSurface` associated with the event
|
||||
*/
|
||||
GdkSurface *
|
||||
gdk_event_get_surface (GdkEvent *event)
|
||||
@@ -2431,6 +2477,14 @@ gdk_touchpad_event_get_state (GdkEvent *event)
|
||||
return self->state;
|
||||
}
|
||||
|
||||
static GdkEventSequence *
|
||||
gdk_touchpad_event_get_sequence (GdkEvent *event)
|
||||
{
|
||||
GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
|
||||
|
||||
return self->sequence;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_touchpad_event_get_position (GdkEvent *event,
|
||||
double *x,
|
||||
@@ -2450,7 +2504,7 @@ static const GdkEventTypeInfo gdk_touchpad_event_info = {
|
||||
NULL,
|
||||
gdk_touchpad_event_get_state,
|
||||
gdk_touchpad_event_get_position,
|
||||
NULL,
|
||||
gdk_touchpad_event_get_sequence,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
@@ -2461,19 +2515,28 @@ GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event,
|
||||
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH))
|
||||
|
||||
GdkEvent *
|
||||
gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy)
|
||||
gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
GdkEventSequence *sequence,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy)
|
||||
{
|
||||
GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_SWIPE, surface, device, time);
|
||||
GdkTouchpadEvent *self;
|
||||
|
||||
g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
|
||||
|
||||
self = gdk_event_alloc (GDK_TOUCHPAD_SWIPE, surface, device, time);
|
||||
|
||||
self->sequence = sequence;
|
||||
self->state = state;
|
||||
self->phase = phase;
|
||||
self->x = x;
|
||||
@@ -2486,21 +2549,30 @@ gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
}
|
||||
|
||||
GdkEvent *
|
||||
gdk_touchpad_event_new_pinch (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy,
|
||||
double scale,
|
||||
double angle_delta)
|
||||
gdk_touchpad_event_new_pinch (GdkSurface *surface,
|
||||
GdkEventSequence *sequence,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy,
|
||||
double scale,
|
||||
double angle_delta)
|
||||
{
|
||||
GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_PINCH, surface, device, time);
|
||||
GdkTouchpadEvent *self;
|
||||
|
||||
g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
|
||||
phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
|
||||
|
||||
self = gdk_event_alloc (GDK_TOUCHPAD_PINCH, surface, device, time);
|
||||
|
||||
self->sequence = sequence;
|
||||
self->state = state;
|
||||
self->phase = phase;
|
||||
self->x = x;
|
||||
@@ -2907,7 +2979,8 @@ gdk_motion_event_new (GdkSurface *surface,
|
||||
* to the application because they occurred in the same frame as @event.
|
||||
*
|
||||
* Note that only motion and scroll events record history, and motion
|
||||
* events do it only if one of the mouse buttons is down.
|
||||
* events do it only if one of the mouse buttons is down, or the device
|
||||
* has a tool.
|
||||
*
|
||||
* Returns: (transfer container) (array length=out_n_coords) (nullable): an
|
||||
* array of time and coordinates
|
||||
|
||||
+14
-11
@@ -209,7 +209,7 @@ struct _GdkTouchEvent
|
||||
* @pointer_emulated: whether the scroll event was the result of
|
||||
* a pointer emulation
|
||||
* @tool: a `GdkDeviceTool`
|
||||
* @history: (element-type GdkScrollHistory): array of times and deltas
|
||||
* @history: (element-type GdkTimeCoord): array of times and deltas
|
||||
* for other scroll events that were compressed before delivering the
|
||||
* current event
|
||||
*
|
||||
@@ -233,7 +233,7 @@ struct _GdkScrollEvent
|
||||
gboolean pointer_emulated;
|
||||
gboolean is_stop;
|
||||
GdkDeviceTool *tool;
|
||||
GArray *history; /* <GdkScrollHistory> */
|
||||
GArray *history; /* <GdkTimeCoord> */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -402,6 +402,7 @@ struct _GdkTouchpadEvent
|
||||
{
|
||||
GdkEvent parent_instance;
|
||||
|
||||
GdkEventSequence *sequence;
|
||||
GdkModifierType state;
|
||||
gint8 phase;
|
||||
gint8 n_fingers;
|
||||
@@ -506,18 +507,20 @@ GdkEvent * gdk_touch_event_new (GdkEventType type,
|
||||
double *axes,
|
||||
gboolean emulating);
|
||||
|
||||
GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface *surface,
|
||||
GdkEventSequence *sequence,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GdkTouchpadGesturePhase phase,
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy);
|
||||
double x,
|
||||
double y,
|
||||
int n_fingers,
|
||||
double dx,
|
||||
double dy);
|
||||
|
||||
GdkEvent * gdk_touchpad_event_new_pinch (GdkSurface *surface,
|
||||
GdkEventSequence *sequence,
|
||||
GdkDevice *device,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
|
||||
+70
-13
@@ -151,6 +151,12 @@ unmask_context (MaskedContext *mask)
|
||||
return GDK_GL_CONTEXT (GSIZE_TO_POINTER (GPOINTER_TO_SIZE (mask) & ~(gsize) 1));
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
mask_is_surfaceless (MaskedContext *mask)
|
||||
{
|
||||
return GPOINTER_TO_SIZE (mask) & (gsize) 1;
|
||||
}
|
||||
|
||||
static void
|
||||
unref_unmasked (gpointer data)
|
||||
{
|
||||
@@ -179,8 +185,7 @@ gdk_gl_context_dispose (GObject *gobject)
|
||||
|
||||
if (priv->egl_context != NULL)
|
||||
{
|
||||
GdkSurface *surface = gdk_gl_context_get_surface (context);
|
||||
GdkDisplay *display = gdk_surface_get_display (surface);
|
||||
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||
EGLDisplay *egl_display = gdk_display_get_egl_display (display);
|
||||
|
||||
if (eglGetCurrentContext () == priv->egl_context)
|
||||
@@ -574,8 +579,8 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
|
||||
glViewport (0, 0, ww, wh);
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (priv->egl_context)
|
||||
glDrawBuffers (1, (GLenum[1]) { GL_BACK_LEFT });
|
||||
if (priv->egl_context && gdk_gl_context_check_version (context, 0, 0, 3, 0))
|
||||
glDrawBuffers (1, (GLenum[1]) { gdk_gl_context_get_use_es (context) ? GL_BACK : GL_BACK_LEFT });
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -997,16 +1002,33 @@ gdk_gl_context_set_required_version (GdkGLContext *context,
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_check_version (GdkGLContext *context,
|
||||
int required_major,
|
||||
int required_minor)
|
||||
gdk_gl_context_check_version (GdkGLContext *self,
|
||||
int required_gl_major,
|
||||
int required_gl_minor,
|
||||
int required_gles_major,
|
||||
int required_gles_minor)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (required_minor < 10, FALSE);
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), FALSE);
|
||||
g_return_val_if_fail (required_gl_minor < 10, FALSE);
|
||||
g_return_val_if_fail (required_gles_minor < 10, FALSE);
|
||||
|
||||
return priv->gl_version >= required_major * 10 + required_minor;
|
||||
if (!gdk_gl_context_is_realized (self))
|
||||
return FALSE;
|
||||
|
||||
switch (priv->api)
|
||||
{
|
||||
case GDK_GL_API_GL:
|
||||
return priv->gl_version >= required_gl_major * 10 + required_gl_minor;
|
||||
|
||||
case GDK_GL_API_GLES:
|
||||
return priv->gl_version >= required_gles_major * 10 + required_gles_minor;
|
||||
|
||||
default:
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1323,6 +1345,7 @@ gl_debug_message_callback (GLenum source,
|
||||
const char *message_source;
|
||||
const char *message_type;
|
||||
const char *message_severity;
|
||||
GLogLevelFlags log_level;
|
||||
|
||||
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
|
||||
return;
|
||||
@@ -1384,22 +1407,31 @@ gl_debug_message_callback (GLenum source,
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
message_severity = "High";
|
||||
log_level = G_LOG_LEVEL_CRITICAL;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
message_severity = "Medium";
|
||||
log_level = G_LOG_LEVEL_WARNING;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
message_severity = "Low";
|
||||
log_level = G_LOG_LEVEL_MESSAGE;
|
||||
break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
||||
message_severity = "Notification";
|
||||
log_level = G_LOG_LEVEL_INFO;
|
||||
break;
|
||||
default:
|
||||
message_severity = "Unknown";
|
||||
log_level = G_LOG_LEVEL_MESSAGE;
|
||||
}
|
||||
|
||||
g_warning ("OPENGL:\n Source: %s\n Type: %s\n Severity: %s\n Message: %s",
|
||||
message_source, message_type, message_severity, message);
|
||||
/* There's no higher level function taking a log level argument... */
|
||||
g_log_structured_standard (G_LOG_DOMAIN, log_level,
|
||||
__FILE__, G_STRINGIFY (__LINE__),
|
||||
G_STRFUNC,
|
||||
"OPENGL:\n Source: %s\n Type: %s\n Severity: %s\n Message: %s",
|
||||
message_source, message_type, message_severity, message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1655,6 +1687,31 @@ gdk_gl_context_clear_current (void)
|
||||
}
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gdk_gl_context_clear_current_if_surface:
|
||||
* @surface: surface to clear for
|
||||
*
|
||||
* Does a gdk_gl_context_clear_current() if the current context is attached
|
||||
* to @surface, leaves the current context alone otherwise.
|
||||
**/
|
||||
void
|
||||
gdk_gl_context_clear_current_if_surface (GdkSurface *surface)
|
||||
{
|
||||
MaskedContext *current;
|
||||
|
||||
current = g_private_get (&thread_current_context);
|
||||
if (current != NULL && !mask_is_surfaceless (current))
|
||||
{
|
||||
GdkGLContext *context = unmask_context (current);
|
||||
|
||||
if (gdk_gl_context_get_surface (context) != surface)
|
||||
return;
|
||||
|
||||
if (GDK_GL_CONTEXT_GET_CLASS (context)->clear_current (context))
|
||||
g_private_replace (&thread_current_context, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_current:
|
||||
*
|
||||
|
||||
@@ -99,6 +99,8 @@ gboolean gdk_gl_backend_can_be_used (GdkGLBackend
|
||||
GError **error);
|
||||
void gdk_gl_backend_use (GdkGLBackend backend_type);
|
||||
|
||||
void gdk_gl_context_clear_current_if_surface (GdkSurface *surface);
|
||||
|
||||
GdkGLContext * gdk_gl_context_new (GdkDisplay *display,
|
||||
GdkSurface *surface);
|
||||
|
||||
@@ -109,8 +111,10 @@ void gdk_gl_context_set_is_legacy (GdkGLContext
|
||||
gboolean is_legacy);
|
||||
|
||||
gboolean gdk_gl_context_check_version (GdkGLContext *context,
|
||||
int required_major,
|
||||
int required_minor);
|
||||
int required_gl_major,
|
||||
int required_gl_minor,
|
||||
int required_gles_major,
|
||||
int required_gles_minor);
|
||||
|
||||
gboolean gdk_gl_context_has_unpack_subimage (GdkGLContext *context);
|
||||
void gdk_gl_context_push_debug_group (GdkGLContext *context,
|
||||
|
||||
+7
-3
@@ -21,6 +21,7 @@
|
||||
#include "gdkgltextureprivate.h"
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkglcontextprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdktextureprivate.h"
|
||||
@@ -305,9 +306,11 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
|
||||
GLint active_texture;
|
||||
GLint internal_format;
|
||||
|
||||
if (self->context != gdk_gl_context_get_current ())
|
||||
/* Abort if somebody else is GL-ing here... */
|
||||
if (self->context != gdk_gl_context_get_current () ||
|
||||
/* ... or glGetTexLevelParameter() isn't supported */
|
||||
!gdk_gl_context_check_version (self->context, 0, 0, 3, 1))
|
||||
{
|
||||
/* Somebody else is GL-ing here, abort! */
|
||||
texture->format = GDK_MEMORY_DEFAULT;
|
||||
return;
|
||||
}
|
||||
@@ -380,7 +383,8 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
|
||||
* which will happen when the GdkTexture object is finalized, or due to
|
||||
* an explicit call of [method@Gdk.GLTexture.release].
|
||||
*
|
||||
* Return value: (transfer full): A newly-created `GdkTexture`
|
||||
* Return value: (transfer full) (type GdkGLTexture): A newly-created
|
||||
* `GdkTexture`
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_gl_texture_new (GdkGLContext *context,
|
||||
|
||||
@@ -2,3 +2,4 @@ BOOLEAN:BOXED
|
||||
BOOLEAN:OBJECT
|
||||
BOOLEAN:POINTER
|
||||
VOID:POINTER,POINTER,BOOLEAN,BOOLEAN
|
||||
VOID:INT,INT
|
||||
|
||||
@@ -133,10 +133,10 @@ gdk_memory_sanitize (GBytes *bytes,
|
||||
*
|
||||
* Creates a new texture for a blob of image data.
|
||||
*
|
||||
* The `GBytes` must contain @stride x @height pixels
|
||||
* The `GBytes` must contain @stride × @height pixels
|
||||
* in the given format.
|
||||
*
|
||||
* Returns: A newly-created `GdkTexture`
|
||||
* Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_memory_texture_new (int width,
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ gdk_popup_get_rect_anchor (GdkPopup *popup)
|
||||
*
|
||||
* Returns the parent surface of a popup.
|
||||
*
|
||||
* Returns: (transfer none): the parent surface
|
||||
* Returns: (transfer none) (nullable): the parent surface
|
||||
*/
|
||||
GdkSurface *
|
||||
gdk_popup_get_parent (GdkPopup *popup)
|
||||
|
||||
+6
-1
@@ -605,11 +605,14 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
_gdk_marshal_VOID__INT_INT,
|
||||
G_TYPE_NONE,
|
||||
2,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
g_signal_set_va_marshaller (signals[LAYOUT],
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
_gdk_marshal_VOID__INT_INTv);
|
||||
|
||||
/**
|
||||
* GdkSurface::render:
|
||||
@@ -1092,6 +1095,7 @@ gdk_surface_set_egl_native_window (GdkSurface *self,
|
||||
|
||||
if (priv->egl_surface != NULL)
|
||||
{
|
||||
gdk_gl_context_clear_current_if_surface (self);
|
||||
eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface);
|
||||
priv->egl_surface = NULL;
|
||||
}
|
||||
@@ -1120,6 +1124,7 @@ gdk_surface_ensure_egl_surface (GdkSurface *self,
|
||||
priv->egl_surface != NULL &&
|
||||
gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display))
|
||||
{
|
||||
gdk_gl_context_clear_current_if_surface (self);
|
||||
eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface);
|
||||
priv->egl_surface = NULL;
|
||||
}
|
||||
|
||||
+10
-10
@@ -25,14 +25,14 @@
|
||||
* multiple frames, and will be used for a long time.
|
||||
*
|
||||
* There are various ways to create `GdkTexture` objects from a
|
||||
* `GdkPixbuf`, or a Cairo surface, or other pixel data.
|
||||
* [class@GdkPixbuf.Pixbuf], or a Cairo surface, or other pixel data.
|
||||
*
|
||||
* The ownership of the pixel data is transferred to the `GdkTexture`
|
||||
* instance; you can only make a copy of it, via [method@Gdk.Texture.download].
|
||||
*
|
||||
* `GdkTexture` is an immutable object: That means you cannot change
|
||||
* anything about it other than increasing the reference count via
|
||||
* g_object_ref().
|
||||
* [method@GObject.Object.ref], and consequently, it is a thread-safe object.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@@ -346,7 +346,7 @@ gdk_texture_init (GdkTexture *self)
|
||||
*
|
||||
* Creates a new texture object representing the surface.
|
||||
*
|
||||
* @surface must be an image surface with format CAIRO_FORMAT_ARGB32.
|
||||
* @surface must be an image surface with format `CAIRO_FORMAT_ARGB32`.
|
||||
*
|
||||
* Returns: a new `GdkTexture`
|
||||
*/
|
||||
@@ -384,7 +384,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
|
||||
* Creates a new texture object representing the `GdkPixbuf`.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Returns: a new `GdkTexture`
|
||||
@@ -430,7 +430,7 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
|
||||
* [ctor@Gdk.Texture.new_from_file] to load it.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -454,7 +454,7 @@ gdk_texture_new_from_resource (const char *resource_path)
|
||||
texture = NULL;
|
||||
|
||||
if (texture == NULL)
|
||||
g_error ("Resource path %s s not a valid image: %s", resource_path, error->message);
|
||||
g_error ("Resource path %s is not a valid image: %s", resource_path, error->message);
|
||||
|
||||
return texture;
|
||||
}
|
||||
@@ -472,7 +472,7 @@ gdk_texture_new_from_resource (const char *resource_path)
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -565,7 +565,7 @@ gdk_texture_new_from_bytes_pixbuf (GBytes *bytes,
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -611,7 +611,7 @@ gdk_texture_new_from_bytes (GBytes *bytes,
|
||||
* If %NULL is returned, then @error will be set.
|
||||
*
|
||||
* This function is threadsafe, so that you can e.g. use GTask
|
||||
* and g_task_run_in_thread() to avoid blocking the main thread
|
||||
* and [method@Gio.Task.run_in_thread] to avoid blocking the main thread
|
||||
* while loading a big image.
|
||||
*
|
||||
* Return value: A newly-created `GdkTexture`
|
||||
@@ -796,7 +796,7 @@ gdk_texture_get_render_data (GdkTexture *self,
|
||||
*
|
||||
* This is a utility function intended for debugging and testing.
|
||||
* If you want more control over formats, proper error handling or
|
||||
* want to store to a `GFile` or other location, you might want to
|
||||
* want to store to a [iface@Gio.File] or other location, you might want to
|
||||
* use [method@Gdk.Texture.save_to_png_bytes] or look into the
|
||||
* gdk-pixbuf library.
|
||||
*
|
||||
|
||||
@@ -89,10 +89,6 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gdk_texture_download (GdkTexture *texture,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
void gdk_texture_download_float (GdkTexture *texture,
|
||||
float *data,
|
||||
gsize stride);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_texture_save_to_png (GdkTexture *texture,
|
||||
const char *filename);
|
||||
|
||||
@@ -222,11 +222,7 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
if (depth == 8)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -236,11 +232,7 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
if (depth == 8)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else if (depth == 16)
|
||||
{
|
||||
@@ -325,22 +317,14 @@ gdk_save_png (GdkTexture *texture)
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
@@ -240,7 +240,7 @@ static const FormatData format_data[] = {
|
||||
[GDK_MEMORY_A8R8G8B8] = { GDK_MEMORY_R8G8B8A8, 8, 4, SAMPLEFORMAT_UINT, EXTRASAMPLE_UNASSALPHA },
|
||||
[GDK_MEMORY_R8G8B8A8] = { GDK_MEMORY_R8G8B8A8, 8, 4, SAMPLEFORMAT_UINT, EXTRASAMPLE_UNASSALPHA },
|
||||
[GDK_MEMORY_A8B8G8R8] = { GDK_MEMORY_R8G8B8A8, 8, 4, SAMPLEFORMAT_UINT, EXTRASAMPLE_UNASSALPHA },
|
||||
[GDK_MEMORY_R8G8B8] = { GDK_MEMORY_R8G8B8, 8, 3, SAMPLEFORMAT_UINT, 0 },
|
||||
[GDK_MEMORY_R8G8B8] = { GDK_MEMORY_R8G8B8, 8, 3, SAMPLEFORMAT_UINT, 0 },
|
||||
[GDK_MEMORY_B8G8R8] = { GDK_MEMORY_R8G8B8, 8, 3, SAMPLEFORMAT_UINT, 0 },
|
||||
[GDK_MEMORY_R16G16B16] = { GDK_MEMORY_R16G16B16, 16, 3, SAMPLEFORMAT_UINT, 0 },
|
||||
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = { GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, 16, 4, SAMPLEFORMAT_UINT, EXTRASAMPLE_ASSOCALPHA },
|
||||
@@ -376,6 +376,13 @@ gdk_load_tiff (GBytes *input_bytes,
|
||||
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
|
||||
|
||||
tif = tiff_open_read (input_bytes);
|
||||
if (!tif)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
|
||||
_("Could not load TIFF data"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TIFFSetDirectory (tif, 0);
|
||||
|
||||
|
||||
@@ -537,6 +537,7 @@ fill_pinch_event (GdkMacosDisplay *display,
|
||||
seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
|
||||
|
||||
return gdk_touchpad_event_new_pinch (GDK_SURFACE (surface),
|
||||
NULL, /* FIXME make up sequences */
|
||||
gdk_seat_get_pointer (seat),
|
||||
get_time_from_ns_event (nsevent),
|
||||
get_keyboard_modifiers_from_ns_event (nsevent),
|
||||
|
||||
@@ -137,6 +137,7 @@ struct _GdkWaylandPointerData {
|
||||
guint cursor_timeout_id;
|
||||
guint cursor_image_index;
|
||||
guint cursor_image_delay;
|
||||
guint touchpad_event_sequence;
|
||||
|
||||
guint current_output_scale;
|
||||
GSList *pointer_surface_outputs;
|
||||
@@ -1127,7 +1128,7 @@ data_offer_source_actions (void *data,
|
||||
seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (source_actions);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (seat->drop == NULL)
|
||||
return;
|
||||
|
||||
@@ -1152,7 +1153,7 @@ data_offer_action (void *data,
|
||||
seat->pending_action = gdk_wayland_actions_to_gdk_actions (action);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (seat->drop == NULL)
|
||||
return;
|
||||
|
||||
@@ -2164,7 +2165,7 @@ deliver_key_event (GdkWaylandSeat *seat,
|
||||
key,
|
||||
device_get_modifiers (seat->logical_pointer),
|
||||
_gdk_wayland_keymap_key_is_modifier (keymap, key),
|
||||
&translated,
|
||||
&translated,
|
||||
&no_lock);
|
||||
|
||||
_gdk_wayland_display_deliver_event (seat->display, event);
|
||||
@@ -2667,7 +2668,11 @@ emit_gesture_swipe_event (GdkWaylandSeat *seat,
|
||||
|
||||
seat->pointer_info.time = _time;
|
||||
|
||||
if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
|
||||
seat->pointer_info.touchpad_event_sequence++;
|
||||
|
||||
event = gdk_touchpad_event_new_swipe (seat->pointer_info.focus,
|
||||
GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
|
||||
seat->logical_pointer,
|
||||
_time,
|
||||
device_get_modifiers (seat->logical_pointer),
|
||||
@@ -2763,7 +2768,11 @@ emit_gesture_pinch_event (GdkWaylandSeat *seat,
|
||||
|
||||
seat->pointer_info.time = _time;
|
||||
|
||||
if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
|
||||
seat->pointer_info.touchpad_event_sequence++;
|
||||
|
||||
event = gdk_touchpad_event_new_pinch (seat->pointer_info.focus,
|
||||
GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
|
||||
seat->logical_pointer,
|
||||
_time,
|
||||
device_get_modifiers (seat->logical_pointer),
|
||||
@@ -4088,7 +4097,7 @@ tablet_pad_strip_handle_frame (void *data,
|
||||
event = gdk_pad_event_new_strip (seat->keyboard_focus,
|
||||
pad->device,
|
||||
time,
|
||||
g_list_index (pad->mode_groups, group),
|
||||
g_list_index (pad->mode_groups, group),
|
||||
g_list_index (pad->strips, wp_tablet_pad_strip),
|
||||
group->current_mode,
|
||||
group->axis_tmp_info.value);
|
||||
|
||||
@@ -1662,6 +1662,7 @@ static TranslationEntry translations[] = {
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-middle-click-titlebar", "gtk-titlebar-middle-click", G_TYPE_STRING, { .s = "none" } },
|
||||
{ FALSE, "org.gnome.desktop.wm.preferences", "action-right-click-titlebar", "gtk-titlebar-right-click", G_TYPE_STRING, { .s = "menu" } },
|
||||
{ FALSE, "org.gnome.desktop.a11y", "always-show-text-caret", "gtk-keynav-use-caret", G_TYPE_BOOLEAN, { .b = FALSE } },
|
||||
{ FALSE, "org.gnome.desktop.a11y.interface", "high-contrast", "high-contast", G_TYPE_NONE, { .b = FALSE } },
|
||||
/* Note, this setting doesn't exist, the portal and gsd fake it */
|
||||
{ FALSE, "org.gnome.fontconfig", "serial", "gtk-fontconfig-timestamp", G_TYPE_NONE, { .i = 0 } },
|
||||
};
|
||||
@@ -1711,6 +1712,13 @@ find_translation_entry_by_setting (const char *setting)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
high_contrast_changed (GdkDisplay *display)
|
||||
{
|
||||
gdk_display_setting_changed (display, "gtk-theme-name");
|
||||
gdk_display_setting_changed (display, "gtk-icon-theme-name");
|
||||
}
|
||||
|
||||
static void
|
||||
settings_changed (GSettings *settings,
|
||||
const char *key,
|
||||
@@ -1724,6 +1732,8 @@ settings_changed (GSettings *settings,
|
||||
{
|
||||
if (entry->type != G_TYPE_NONE)
|
||||
gdk_display_setting_changed (display, entry->setting);
|
||||
else if (strcmp (key, "high-contrast") == 0)
|
||||
high_contrast_changed (display);
|
||||
else
|
||||
update_xft_settings (display);
|
||||
}
|
||||
@@ -2090,6 +2100,36 @@ set_decoration_layout_from_entry (GdkDisplay *display,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_theme_from_entry (GdkDisplay *display,
|
||||
TranslationEntry *entry,
|
||||
GValue *value)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
|
||||
GSettings *settings = NULL;
|
||||
GSettingsSchema *schema = NULL;
|
||||
gboolean hc = FALSE;
|
||||
|
||||
if (display_wayland->settings_portal == NULL)
|
||||
{
|
||||
settings = (GSettings *)g_hash_table_lookup (display_wayland->settings,
|
||||
"org.gnome.desktop.a11y.interface");
|
||||
}
|
||||
|
||||
if (settings)
|
||||
g_object_get (settings, "settings-schema", &schema, NULL);
|
||||
|
||||
if (schema && g_settings_schema_has_key (schema, "high-contrast"))
|
||||
hc = g_settings_get_boolean (settings, "high-contrast");
|
||||
|
||||
g_clear_pointer (&schema, g_settings_schema_unref);
|
||||
|
||||
if (hc)
|
||||
g_value_set_static_string (value, "HighContrast");
|
||||
else
|
||||
set_value_from_entry (display, entry, value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
set_capability_setting (GdkDisplay *display,
|
||||
GValue *value,
|
||||
@@ -2121,6 +2161,9 @@ gdk_wayland_display_get_setting (GdkDisplay *display,
|
||||
{
|
||||
if (strcmp (name, "gtk-decoration-layout") == 0)
|
||||
set_decoration_layout_from_entry (display, entry, value);
|
||||
else if (strcmp (name, "gtk-theme-name") == 0 ||
|
||||
strcmp (name, "gtk-icon-theme-name") == 0)
|
||||
set_theme_from_entry (display, entry, value);
|
||||
else
|
||||
set_value_from_entry (display, entry, value);
|
||||
return TRUE;
|
||||
|
||||
@@ -118,7 +118,6 @@ struct _GdkWaylandSurface
|
||||
unsigned int mapped : 1;
|
||||
unsigned int awaiting_frame : 1;
|
||||
unsigned int awaiting_frame_frozen : 1;
|
||||
unsigned int is_drag_surface : 1;
|
||||
|
||||
int pending_buffer_offset_x;
|
||||
int pending_buffer_offset_y;
|
||||
@@ -780,11 +779,22 @@ gdk_wayland_surface_update_scale (GdkSurface *surface)
|
||||
return;
|
||||
}
|
||||
|
||||
scale = 1;
|
||||
for (l = impl->display_server.outputs; l != NULL; l = l->next)
|
||||
if (!impl->display_server.outputs)
|
||||
{
|
||||
guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data);
|
||||
scale = MAX (scale, output_scale);
|
||||
scale = impl->scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = 1;
|
||||
for (l = impl->display_server.outputs; l != NULL; l = l->next)
|
||||
{
|
||||
struct wl_output *output = l->data;
|
||||
uint32_t output_scale;
|
||||
|
||||
output_scale = gdk_wayland_display_get_output_scale (display_wayland,
|
||||
output);
|
||||
scale = MAX (scale, output_scale);
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify app that scale changed */
|
||||
@@ -2825,27 +2835,12 @@ find_grab_input_seat (GdkSurface *surface,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_be_mapped (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
/* Don't map crazy temp that GTK uses for internal X11 shenanigans. */
|
||||
if (GDK_IS_DRAG_SURFACE (surface) && surface->x < 0 && surface->y < 0)
|
||||
return FALSE;
|
||||
|
||||
if (impl->is_drag_surface)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_map_toplevel (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
|
||||
if (!should_be_mapped (surface))
|
||||
if (!GDK_IS_WAYLAND_TOPLEVEL (surface))
|
||||
return;
|
||||
|
||||
if (impl->mapped)
|
||||
@@ -4703,7 +4698,6 @@ create_dnd_surface (GdkDisplay *display)
|
||||
GDK_SURFACE_TEMP,
|
||||
NULL,
|
||||
0, 0, 100, 100);
|
||||
GDK_WAYLAND_SURFACE (surface)->is_drag_surface = TRUE;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
@@ -1,406 +0,0 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2001 Stefan Ondrejicka
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int id;
|
||||
char *bitmap;
|
||||
int hotx;
|
||||
int hoty;
|
||||
} font_info_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int id;
|
||||
int width;
|
||||
int height;
|
||||
int hotx;
|
||||
int hoty;
|
||||
char *data;
|
||||
} cursor_info_t;
|
||||
|
||||
static GSList *fonts = NULL;
|
||||
static GSList *cursors = NULL;
|
||||
|
||||
static int dw,dh;
|
||||
|
||||
static gboolean debug = FALSE;
|
||||
|
||||
#define HEX(c) (((c) >= '0' && (c) <= '9') ? \
|
||||
((c) - '0') : (toupper(c) - 'A' + 10))
|
||||
|
||||
static void print_font(fi)
|
||||
font_info_t *fi;
|
||||
{
|
||||
int x,y;
|
||||
|
||||
for (y = 0; y < dh; y++)
|
||||
{
|
||||
for (x = 0; x < dw; x++)
|
||||
{
|
||||
printf(fi->bitmap[y*dw+x]? "X" : " ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_cursor(ci)
|
||||
cursor_info_t *ci;
|
||||
{
|
||||
int x,y;
|
||||
|
||||
for (y = 0; y < ci->height; y++)
|
||||
{
|
||||
printf("/* ");
|
||||
for (x = 0; x < ci->width; x++)
|
||||
{
|
||||
if (ci->hotx == x && ci->hoty == y)
|
||||
printf("o");
|
||||
else
|
||||
switch (ci->data[y*ci->width+x])
|
||||
{
|
||||
case 0:
|
||||
printf(" ");
|
||||
break;
|
||||
case 1:
|
||||
printf(".");
|
||||
break;
|
||||
case 2:
|
||||
printf("X");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf(" */\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int read_bdf_font(fname)
|
||||
char *fname;
|
||||
{
|
||||
FILE *f;
|
||||
char line[2048];
|
||||
int rv = 0;
|
||||
gboolean startchar = FALSE, startbitmap = FALSE;
|
||||
char *charname,*p,*bitmap;
|
||||
int dx = 0,dy = 0;
|
||||
int w,h,x,y,py;
|
||||
int id,tmp;
|
||||
|
||||
dw = 0;
|
||||
dh = 0;
|
||||
|
||||
if (!(f = fopen(fname, "r")))
|
||||
{
|
||||
perror(fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fgets(line, sizeof(line), f) && strncasecmp("STARTFONT ", line, 10))
|
||||
{
|
||||
printf("!BDF font file\n");
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = line;
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
if (!startchar)
|
||||
{
|
||||
if (!strncasecmp("STARTCHAR ", line, 10))
|
||||
{
|
||||
startchar = TRUE;
|
||||
charname = g_strndup(p + 10,
|
||||
strcspn(p+10, "\r\n"));
|
||||
}
|
||||
else if (!strncasecmp("FONTBOUNDINGBOX ", line, 16))
|
||||
sscanf(p+16, "%d %d %d %d", &dw, &dh, &dx, &dy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strncasecmp("ENDCHAR", line, 7))
|
||||
{
|
||||
font_info_t *nfi;
|
||||
|
||||
if (debug)
|
||||
printf(" %*s*/\n", dw, "");
|
||||
startchar = FALSE;
|
||||
startbitmap = FALSE;
|
||||
|
||||
nfi = g_malloc(sizeof(font_info_t));
|
||||
memset(nfi, '\0', sizeof(font_info_t));
|
||||
|
||||
nfi->name = charname;
|
||||
nfi->id = id;
|
||||
nfi->bitmap = bitmap;
|
||||
nfi->hotx = 0 - dx;
|
||||
nfi->hoty = 0 - dy;
|
||||
|
||||
fonts = g_slist_append(fonts, nfi);
|
||||
}
|
||||
else if (startbitmap)
|
||||
{
|
||||
int px,cx;
|
||||
guchar mask;
|
||||
|
||||
px = x - dx + py * dw;
|
||||
for (cx = 0; cx < w; cx++)
|
||||
{
|
||||
mask = 1 << (3 - (cx % 4));
|
||||
|
||||
bitmap[px+cx] =
|
||||
(mask & HEX(line[cx/4])) != 0;
|
||||
|
||||
if (debug)
|
||||
printf(bitmap[px+cx] ? "X" : " ");
|
||||
}
|
||||
py++;
|
||||
if (debug)
|
||||
printf(" %*s*/\n/* %*s", dw-w, "", dw+dx, "");
|
||||
}
|
||||
else if (!strncasecmp("BBX ", line, 4))
|
||||
{
|
||||
sscanf(p+4, "%d %d %d %d", &w, &h, &x, &y);
|
||||
if (debug)
|
||||
printf("/* %s: */\n/* %*s", charname, dw+dx, "");
|
||||
}
|
||||
else if (!strncasecmp("ENCODING ", line, 9))
|
||||
{
|
||||
if (sscanf(p+9, "%d %d", &tmp, &id) != 2)
|
||||
id = tmp;
|
||||
}
|
||||
else if (!strncasecmp("BITMAP", line, 6))
|
||||
{
|
||||
py = y - dy;
|
||||
startbitmap = TRUE;
|
||||
bitmap = g_malloc(dw*dh);
|
||||
memset(bitmap, '\0', dw*dh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strncasecmp("ENDFONT", line, 7))
|
||||
rv = -1;
|
||||
|
||||
fclose(f);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int font_info_compare(fi, name)
|
||||
font_info_t *fi;
|
||||
char *name;
|
||||
{
|
||||
return strcmp(name, fi->name);
|
||||
}
|
||||
|
||||
static cursor_info_t *gen_cursor(bmap, mask)
|
||||
font_info_t *bmap;
|
||||
font_info_t *mask;
|
||||
{
|
||||
cursor_info_t *ci;
|
||||
int bx = dw,by = dh,ex = 0,ey = 0;
|
||||
int i,j;
|
||||
|
||||
for (j = 0; j < dh; j++)
|
||||
{
|
||||
gboolean havep = FALSE;
|
||||
|
||||
for (i = 0; i < dw; i++)
|
||||
{
|
||||
if (bmap->bitmap[j*dw+i] || mask->bitmap[j*dw+i])
|
||||
{
|
||||
havep = TRUE;
|
||||
bx = MIN(bx, i);
|
||||
ex = MAX(i+1, ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (havep)
|
||||
{
|
||||
by = MIN(by, j);
|
||||
ey = MAX(ey, j+1);
|
||||
}
|
||||
}
|
||||
|
||||
ci = g_malloc(sizeof(cursor_info_t));
|
||||
ci->name = g_strdup(bmap->name);
|
||||
ci->id = bmap->id;
|
||||
|
||||
ci->width = ex - bx;
|
||||
ci->height = ey - by;
|
||||
|
||||
ci->hotx = bmap->hotx - bx;
|
||||
ci->hoty = ci->height - (bmap->hoty - by);
|
||||
|
||||
ci->data = g_malloc(ci->width * ci->height);
|
||||
memset(ci->data, '\0', ci->width * ci->height);
|
||||
|
||||
for (j = 0; j < ci->height; j++)
|
||||
{
|
||||
for (i = 0; i < ci->width; i++)
|
||||
{
|
||||
int ofs = (by + j) * dw + bx + i;
|
||||
|
||||
ci->data[j*ci->width + i] = mask->bitmap[ofs] *
|
||||
(1 + bmap->bitmap[ofs]);
|
||||
}
|
||||
}
|
||||
|
||||
return ci;
|
||||
}
|
||||
|
||||
static void compose_cursors_from_fonts()
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = g_slist_copy (fonts); l; l = g_slist_delete_link (l,l))
|
||||
{
|
||||
font_info_t *fi = l->data;
|
||||
char *name;
|
||||
GSList *ml;
|
||||
|
||||
name = g_strconcat(fi->name, "_mask", NULL);
|
||||
|
||||
if ((ml = g_slist_find_custom(fonts, name,
|
||||
(GCompareFunc) font_info_compare)))
|
||||
{
|
||||
cursors = g_slist_append(cursors, gen_cursor(l->data, ml->data));
|
||||
fonts = g_slist_remove(fonts, l->data);
|
||||
fonts = g_slist_remove(fonts, ml->data);
|
||||
}
|
||||
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
|
||||
static char *dump_cursor(ci, id)
|
||||
cursor_info_t *ci;
|
||||
int id;
|
||||
{
|
||||
static char cdata[8192];
|
||||
char *p;
|
||||
int i;
|
||||
int c;
|
||||
gboolean flushed;
|
||||
|
||||
sprintf(cdata, " { \"%s\", %d, %d, %d, %d, %d, \n \"",
|
||||
ci->name, ci->id, ci->width, ci->height, ci->hotx, ci->hoty);
|
||||
p = cdata + strlen(cdata);
|
||||
|
||||
for (i = 0; i < ci->width * ci->height; i++)
|
||||
{
|
||||
flushed = FALSE;
|
||||
|
||||
if (!(i%4))
|
||||
c = 0;
|
||||
|
||||
c = c << 2;
|
||||
|
||||
c += ci->data[i];
|
||||
|
||||
if ((i % 4) == 3)
|
||||
{
|
||||
flushed = TRUE;
|
||||
sprintf(p, "\\%03o", c);
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
if (i > 0 && !(i % 64))
|
||||
{
|
||||
strcpy(p ,"\"\n \"");
|
||||
p += strlen(p);
|
||||
}
|
||||
}
|
||||
if (!flushed)
|
||||
{
|
||||
sprintf(p, "\\%03o", c);
|
||||
p += strlen(p);
|
||||
}
|
||||
|
||||
strcpy(p, "\" }");
|
||||
|
||||
return cdata;
|
||||
}
|
||||
|
||||
static int dump_cursors()
|
||||
{
|
||||
GSList *ptr;
|
||||
FILE *f = stdout;
|
||||
|
||||
fprintf(f, "static const struct { const char *name; int type; guchar width; guchar height; guchar hotx; guchar hoty; guchar *data; } cursors[] = {\n");
|
||||
|
||||
for (ptr = cursors; ptr; ptr = ptr->next)
|
||||
{
|
||||
if (debug)
|
||||
print_cursor(ptr->data);
|
||||
fprintf(f, "%s, \n", dump_cursor(ptr->data));
|
||||
}
|
||||
|
||||
fprintf(f, " { NULL, 0, 0, 0, 0, 0, NULL },\n};\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
printf("missing parameters !\n");
|
||||
printf("Usage: %s [BDF cursor file]\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g_getenv ("BDFCURSOR_DEBUG") != NULL)
|
||||
debug = TRUE;
|
||||
|
||||
if (read_bdf_font(argv[1]) || !fonts)
|
||||
{
|
||||
printf("Error reading font\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
compose_cursors_from_fonts();
|
||||
|
||||
if (!cursors)
|
||||
{
|
||||
printf("failed to generate cursors from font!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dump_cursors();
|
||||
|
||||
if (fonts)
|
||||
{
|
||||
printf("some fonts remained unconverted!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -157,7 +157,6 @@ static HKL latin_locale = NULL;
|
||||
|
||||
static gboolean in_ime_composition = FALSE;
|
||||
static UINT modal_timer;
|
||||
static UINT sync_timer = 0;
|
||||
|
||||
static int debug_indent = 0;
|
||||
|
||||
@@ -1453,23 +1452,6 @@ _gdk_win32_end_modal_call (GdkWin32ModalOpKind kind)
|
||||
}
|
||||
}
|
||||
|
||||
static VOID CALLBACK
|
||||
sync_timer_proc (HWND hwnd,
|
||||
UINT msg,
|
||||
UINT_PTR id,
|
||||
DWORD time)
|
||||
{
|
||||
MSG message;
|
||||
if (PeekMessageW (&message, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RedrawWindow (hwnd, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
|
||||
|
||||
KillTimer (hwnd, sync_timer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_nchittest (HWND hwnd,
|
||||
GdkSurface *window,
|
||||
@@ -2854,12 +2836,6 @@ gdk_event_translate (MSG *msg,
|
||||
*ret_valp = 1;
|
||||
break;
|
||||
|
||||
case WM_SYNCPAINT:
|
||||
sync_timer = SetTimer (GDK_SURFACE_HWND (window),
|
||||
1,
|
||||
200, sync_timer_proc);
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
handle_wm_paint (msg, window);
|
||||
break;
|
||||
|
||||
+140
-140
@@ -653,6 +653,7 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
|
||||
g_object_unref (frame_clock);
|
||||
impl->hdc = GetDC (impl->handle);
|
||||
impl->inhibit_configure = TRUE;
|
||||
|
||||
return surface;
|
||||
}
|
||||
@@ -786,26 +787,6 @@ show_window_internal (GdkSurface *window,
|
||||
if (!unminimize && !already_mapped && IsWindowVisible (GDK_SURFACE_HWND (window)))
|
||||
return;
|
||||
|
||||
/* Other cases */
|
||||
|
||||
exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
|
||||
|
||||
/* Use SetWindowPos to show transparent windows so automatic redraws
|
||||
* in other windows can be suppressed.
|
||||
*/
|
||||
if (exstyle & WS_EX_TRANSPARENT)
|
||||
{
|
||||
UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
|
||||
|
||||
if (GDK_IS_DRAG_SURFACE (window))
|
||||
flags |= SWP_NOACTIVATE;
|
||||
|
||||
SetWindowPos (GDK_SURFACE_HWND (window),
|
||||
SWP_NOZORDER_SPECIFIED, 0, 0, 0, 0, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* For initial map of "normal" windows we want to emulate WM window
|
||||
* positioning behaviour, which means:
|
||||
* + default to the initial CW_USEDEFAULT placement,
|
||||
@@ -952,6 +933,8 @@ show_window_internal (GdkSurface *window,
|
||||
GtkShowWindow (window, SW_SHOW);
|
||||
}
|
||||
|
||||
exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
|
||||
|
||||
/* Sync STATE_ABOVE to TOPMOST */
|
||||
if (!GDK_IS_DRAG_SURFACE (window) &&
|
||||
(((window->state & GDK_TOPLEVEL_STATE_ABOVE) &&
|
||||
@@ -988,22 +971,7 @@ gdk_win32_surface_hide (GdkSurface *window)
|
||||
|
||||
_gdk_surface_clear_update_area (window);
|
||||
|
||||
if (GDK_IS_TOPLEVEL (window))
|
||||
ShowOwnedPopups (GDK_SURFACE_HWND (window), FALSE);
|
||||
|
||||
/* Use SetWindowPos to hide transparent windows so automatic redraws
|
||||
* in other windows can be suppressed.
|
||||
*/
|
||||
if (GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
|
||||
{
|
||||
SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
|
||||
0, 0, 0, 0,
|
||||
SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkShowWindow (window, SW_HIDE);
|
||||
}
|
||||
GtkShowWindow (window, SW_HIDE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1042,14 +1010,15 @@ gdk_win32_surface_do_move (GdkSurface *window,
|
||||
}
|
||||
|
||||
void
|
||||
gdk_win32_surface_resize (GdkSurface *window,
|
||||
int width, int height)
|
||||
gdk_win32_surface_resize (GdkSurface *surface,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
RECT outer_rect;
|
||||
|
||||
g_return_if_fail (GDK_IS_SURFACE (window));
|
||||
g_return_if_fail (GDK_IS_SURFACE (surface));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
if (GDK_SURFACE_DESTROYED (surface))
|
||||
return;
|
||||
|
||||
if (width < 1)
|
||||
@@ -1058,28 +1027,29 @@ gdk_win32_surface_resize (GdkSurface *window,
|
||||
height = 1;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("gdk_win32_surface_resize: %p: %dx%d\n",
|
||||
GDK_SURFACE_HWND (window), width, height));
|
||||
GDK_SURFACE_HWND (surface), width, height));
|
||||
|
||||
if (window->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
|
||||
if (surface->state & GDK_TOPLEVEL_STATE_FULLSCREEN)
|
||||
return;
|
||||
|
||||
get_outer_rect (window, width, height, &outer_rect);
|
||||
get_outer_rect (surface, width, height, &outer_rect);
|
||||
|
||||
GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
|
||||
"NOACTIVATE|NOMOVE|NOZORDER)\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
GDK_SURFACE_HWND (surface),
|
||||
outer_rect.right - outer_rect.left,
|
||||
outer_rect.bottom - outer_rect.top));
|
||||
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
|
||||
API_CALL (SetWindowPos, (GDK_SURFACE_HWND (surface),
|
||||
SWP_NOZORDER_SPECIFIED,
|
||||
0, 0,
|
||||
outer_rect.right - outer_rect.left,
|
||||
outer_rect.bottom - outer_rect.top,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
|
||||
window->resize_count += 1;
|
||||
surface->resize_count += 1;
|
||||
|
||||
gdk_surface_request_layout (window);
|
||||
if (!GDK_WIN32_SURFACE (surface)->force_recompute_size)
|
||||
gdk_surface_request_layout (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1333,33 +1303,22 @@ gdk_win32_surface_set_urgency_hint (GdkSurface *window,
|
||||
gboolean urgent)
|
||||
{
|
||||
FLASHWINFO flashwinfo;
|
||||
typedef BOOL (WINAPI *PFN_FlashWindowEx) (FLASHWINFO*);
|
||||
PFN_FlashWindowEx flashWindowEx = NULL;
|
||||
|
||||
g_return_if_fail (GDK_IS_SURFACE (window));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
return;
|
||||
|
||||
flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
|
||||
|
||||
if (flashWindowEx)
|
||||
{
|
||||
flashwinfo.cbSize = sizeof (flashwinfo);
|
||||
flashwinfo.hwnd = GDK_SURFACE_HWND (window);
|
||||
if (urgent)
|
||||
flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
|
||||
else
|
||||
flashwinfo.dwFlags = FLASHW_STOP;
|
||||
flashwinfo.uCount = 0;
|
||||
flashwinfo.dwTimeout = 0;
|
||||
|
||||
flashWindowEx (&flashwinfo);
|
||||
}
|
||||
flashwinfo.cbSize = sizeof (flashwinfo);
|
||||
flashwinfo.hwnd = GDK_SURFACE_HWND (window);
|
||||
if (urgent)
|
||||
flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
|
||||
else
|
||||
{
|
||||
FlashWindow (GDK_SURFACE_HWND (window), urgent);
|
||||
}
|
||||
flashwinfo.dwFlags = FLASHW_STOP;
|
||||
flashwinfo.uCount = 0;
|
||||
flashwinfo.dwTimeout = 0;
|
||||
|
||||
FlashWindowEx (&flashwinfo);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -2495,35 +2454,41 @@ _gdk_win32_surface_handle_aerosnap (GdkSurface *window,
|
||||
}
|
||||
|
||||
static void
|
||||
apply_snap (GdkSurface *window,
|
||||
GdkWin32AeroSnapState snap)
|
||||
apply_snap (GdkSurface *surface,
|
||||
GdkWin32AeroSnapState snap)
|
||||
{
|
||||
GdkMonitor *monitor;
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gdk_surface_get_display (window);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, window);
|
||||
display = gdk_surface_get_display (surface);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, surface);
|
||||
|
||||
switch (snap)
|
||||
{
|
||||
case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
|
||||
unsnap (window, monitor);
|
||||
gdk_win32_surface_maximize (window);
|
||||
unsnap (surface, monitor);
|
||||
gdk_win32_surface_maximize (surface);
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
|
||||
unsnap (window, monitor);
|
||||
snap_left (window, monitor, monitor);
|
||||
unsnap (surface, monitor);
|
||||
snap_left (surface, monitor, monitor);
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
|
||||
unsnap (window, monitor);
|
||||
snap_right (window, monitor, monitor);
|
||||
unsnap (surface, monitor);
|
||||
snap_right (surface, monitor, monitor);
|
||||
break;
|
||||
case GDK_WIN32_AEROSNAP_STATE_FULLUP:
|
||||
snap_up (window);
|
||||
snap_up (surface);
|
||||
break;
|
||||
}
|
||||
|
||||
if (snap != GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
|
||||
{
|
||||
GDK_WIN32_SURFACE (surface)->inhibit_configure = TRUE;
|
||||
GDK_WIN32_SURFACE (surface)->force_recompute_size = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers a dumb window class. This window
|
||||
@@ -3403,10 +3368,10 @@ get_cursor_name_from_op (GdkW32WindowDragOp op,
|
||||
}
|
||||
|
||||
static void
|
||||
setup_drag_move_resize_context (GdkSurface *window,
|
||||
setup_drag_move_resize_context (GdkSurface *surface,
|
||||
GdkW32DragMoveResizeContext *context,
|
||||
GdkW32WindowDragOp op,
|
||||
GdkSurfaceEdge edge,
|
||||
GdkSurfaceEdge edge,
|
||||
GdkDevice *device,
|
||||
int button,
|
||||
double x,
|
||||
@@ -3415,12 +3380,13 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
{
|
||||
RECT rect;
|
||||
const char *cursor_name;
|
||||
GdkSurface *pointer_window;
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
|
||||
gboolean maximized = gdk_toplevel_get_state (GDK_TOPLEVEL (window)) & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
GdkSurface *pointer_surface;
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
|
||||
gboolean maximized = gdk_toplevel_get_state (GDK_TOPLEVEL (surface)) & GDK_TOPLEVEL_STATE_MAXIMIZED;
|
||||
int root_x, root_y;
|
||||
gboolean restore_configure = FALSE;
|
||||
|
||||
gdk_win32_surface_get_root_coords (window, x, y, &root_x, &root_y);
|
||||
gdk_win32_surface_get_root_coords (surface, x, y, &root_x, &root_y);
|
||||
|
||||
/* Before we drag, we need to undo any maximization or snapping.
|
||||
* AeroSnap behaviour:
|
||||
@@ -3443,7 +3409,7 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
* resize
|
||||
* don't unsnap
|
||||
* apply new width and x position to unsnapped cache,
|
||||
* so that unsnapped window only regains its height
|
||||
* so that unsnapped surface only regains its height
|
||||
* and y position, but inherits x and width from
|
||||
* the fullup snapped state
|
||||
* vertical resize:
|
||||
@@ -3458,7 +3424,7 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
*
|
||||
* TODO: make this implementation behave as AeroSnap on resizes?
|
||||
* There's also the case where
|
||||
* a halfleft/halfright window isn't unsnapped when it's
|
||||
* a halfleft/halfright surface isn't unsnapped when it's
|
||||
* being moved horizontally, but it's more difficult to implement.
|
||||
*/
|
||||
if (op == GDK_WIN32_DRAGOP_RESIZE &&
|
||||
@@ -3466,7 +3432,8 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
|
||||
impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
|
||||
{
|
||||
discard_snapinfo (window);
|
||||
discard_snapinfo (surface);
|
||||
restore_configure = TRUE;
|
||||
}
|
||||
else if (maximized ||
|
||||
(impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
|
||||
@@ -3476,24 +3443,25 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
GdkMonitor *monitor;
|
||||
int wx, wy, wwidth, wheight;
|
||||
int swx, swy, swwidth, swheight;
|
||||
gboolean pointer_outside_of_window;
|
||||
gboolean pointer_outside_of_surface;
|
||||
int offsetx, offsety;
|
||||
gboolean left_half;
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gdk_surface_get_display (window);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, window);
|
||||
gdk_surface_get_geometry (window, &wx, &wy, &wwidth, &wheight);
|
||||
restore_configure = TRUE;
|
||||
display = gdk_surface_get_display (surface);
|
||||
monitor = gdk_display_get_monitor_at_surface (display, surface);
|
||||
gdk_surface_get_geometry (surface, &wx, &wy, &wwidth, &wheight);
|
||||
|
||||
swx = wx;
|
||||
swy = wy;
|
||||
swwidth = wwidth;
|
||||
swheight = wheight;
|
||||
|
||||
/* Subtract window shadow. We don't want pointer to go outside of
|
||||
* the visible window during drag-move. For drag-resize it's OK.
|
||||
* Don't take shadow into account if the window is maximized -
|
||||
* maximized windows don't have shadows.
|
||||
/* Subtract surface shadow. We don't want pointer to go outside of
|
||||
* the visible surface during drag-move. For drag-resize it's OK.
|
||||
* Don't take shadow into account if the surface is maximized -
|
||||
* maximized surfaces don't have shadows.
|
||||
*/
|
||||
if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
|
||||
{
|
||||
@@ -3503,16 +3471,16 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
swheight -= impl->shadow_y;
|
||||
}
|
||||
|
||||
pointer_outside_of_window = root_x < swx || root_x > swx + swwidth ||
|
||||
pointer_outside_of_surface = root_x < swx || root_x > swx + swwidth ||
|
||||
root_y < swy || root_y > swy + swheight;
|
||||
/* Calculate the offset of the pointer relative to the window */
|
||||
/* Calculate the offset of the pointer relative to the surface */
|
||||
offsetx = root_x - swx;
|
||||
offsety = root_y - swy;
|
||||
|
||||
/* Figure out in which half of the window the pointer is.
|
||||
/* Figure out in which half of the surface the pointer is.
|
||||
* The code currently only concerns itself with horizontal
|
||||
* dimension (left/right halves).
|
||||
* There's no upper/lower half, because usually window
|
||||
* There's no upper/lower half, because usually surface
|
||||
* is dragged by its upper half anyway. If that changes, adjust
|
||||
* accordingly.
|
||||
*/
|
||||
@@ -3522,26 +3490,26 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
if (!left_half)
|
||||
offsetx = swwidth - offsetx;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Pointer at %d : %d, this is %d : %d relative to the window's %s\n",
|
||||
GDK_NOTE (MISC, g_print ("Pointer at %d : %d, this is %d : %d relative to the surface's %s\n",
|
||||
root_x, root_y, offsetx, offsety,
|
||||
left_half ? "left half" : "right half"));
|
||||
|
||||
/* Move window in such a way that on unmaximization/unsnapping the pointer
|
||||
* is still pointing at the appropriate half of the window,
|
||||
/* Move surface in such a way that on unmaximization/unsnapping the pointer
|
||||
* is still pointing at the appropriate half of the surface,
|
||||
* with the same offset from the left or right edge. If the new
|
||||
* window size is too small, and adding that offset puts the pointer
|
||||
* surface size is too small, and adding that offset puts the pointer
|
||||
* into the other half or even beyond, move the pointer to the middle.
|
||||
*/
|
||||
if (!pointer_outside_of_window && maximized)
|
||||
if (!pointer_outside_of_surface && maximized)
|
||||
{
|
||||
WINDOWPLACEMENT placement;
|
||||
int unmax_width, unmax_height;
|
||||
int shadow_unmax_width, shadow_unmax_height;
|
||||
|
||||
placement.length = sizeof (placement);
|
||||
API_CALL (GetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
|
||||
API_CALL (GetWindowPlacement, (GDK_SURFACE_HWND (surface), &placement));
|
||||
|
||||
GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
|
||||
GDK_NOTE (MISC, g_print ("W32 WM unmaximized surface placement is %ld x %ld @ %ld : %ld\n",
|
||||
placement.rcNormalPosition.right - placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
|
||||
placement.rcNormalPosition.left,
|
||||
@@ -3587,9 +3555,9 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
placement.rcNormalPosition.left,
|
||||
placement.rcNormalPosition.top));
|
||||
|
||||
API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
|
||||
API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (surface), &placement));
|
||||
}
|
||||
else if (!pointer_outside_of_window && impl->snap_stash_int)
|
||||
else if (!pointer_outside_of_surface && impl->snap_stash_int)
|
||||
{
|
||||
GdkRectangle new_pos;
|
||||
GdkRectangle snew_pos;
|
||||
@@ -3619,22 +3587,22 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
new_pos.y = root_y - new_pos.height / 2;
|
||||
}
|
||||
|
||||
GDK_NOTE (MISC, g_print ("Unsnapped window to %d : %d\n",
|
||||
GDK_NOTE (MISC, g_print ("Unsnapped surface to %d : %d\n",
|
||||
new_pos.x, new_pos.y));
|
||||
discard_snapinfo (window);
|
||||
gdk_win32_surface_move_resize (window, new_pos.x, new_pos.y,
|
||||
discard_snapinfo (surface);
|
||||
gdk_win32_surface_move_resize (surface, new_pos.x, new_pos.y,
|
||||
new_pos.width, new_pos.height);
|
||||
}
|
||||
|
||||
|
||||
if (maximized)
|
||||
gdk_win32_surface_unmaximize (window);
|
||||
gdk_win32_surface_unmaximize (surface);
|
||||
else
|
||||
unsnap (window, monitor);
|
||||
unsnap (surface, monitor);
|
||||
|
||||
if (pointer_outside_of_window)
|
||||
if (pointer_outside_of_surface)
|
||||
{
|
||||
/* Pointer outside of the window, move pointer into window */
|
||||
/* Pointer outside of the surface, move pointer into surface */
|
||||
GDK_NOTE (MISC, g_print ("Pointer at %d : %d is outside of %d x %d @ %d : %d, move it to %d : %d\n",
|
||||
root_x, root_y, wwidth, wheight, wx, wy, wx + wwidth / 2, wy + wheight / 2));
|
||||
root_x = wx + wwidth / 2;
|
||||
@@ -3647,26 +3615,29 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
}
|
||||
}
|
||||
|
||||
_gdk_win32_get_window_rect (window, &rect);
|
||||
if (restore_configure)
|
||||
impl->inhibit_configure = FALSE;
|
||||
|
||||
_gdk_win32_get_window_rect (surface, &rect);
|
||||
|
||||
cursor_name = get_cursor_name_from_op (op, edge);
|
||||
|
||||
context->cursor = gdk_cursor_new_from_name (cursor_name, NULL);
|
||||
|
||||
pointer_window = window;
|
||||
pointer_surface = surface;
|
||||
|
||||
/* Note: This triggers a WM_CAPTURECHANGED, which will trigger
|
||||
* gdk_win32_surface_end_move_resize_drag(), which will end
|
||||
* our op before it even begins, but only if context->op is not NONE.
|
||||
* This is why we first do the grab, *then* set the op.
|
||||
*/
|
||||
gdk_device_grab (device, pointer_window,
|
||||
gdk_device_grab (device, pointer_surface,
|
||||
FALSE,
|
||||
GDK_ALL_EVENTS_MASK,
|
||||
context->cursor,
|
||||
timestamp);
|
||||
|
||||
context->window = g_object_ref (window);
|
||||
context->window = g_object_ref (surface);
|
||||
context->op = op;
|
||||
context->edge = edge;
|
||||
context->device = device;
|
||||
@@ -3686,10 +3657,10 @@ setup_drag_move_resize_context (GdkSurface *window,
|
||||
calculate_aerosnap_regions (context);
|
||||
|
||||
GDK_NOTE (EVENTS,
|
||||
g_print ("begin drag moveresize: window %p, toplevel %p, "
|
||||
g_print ("begin drag moveresize: surface %p, toplevel %p, "
|
||||
"op %u, edge %d, device %p, "
|
||||
"button %d, coord %d:%d, time %u\n",
|
||||
pointer_window, window,
|
||||
pointer_surface, surface,
|
||||
context->op, context->edge, context->device,
|
||||
context->button, context->start_root_x,
|
||||
context->start_root_y, context->timestamp));
|
||||
@@ -4084,45 +4055,61 @@ gdk_win32_surface_minimize (GdkSurface *window)
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_surface_maximize (GdkSurface *window)
|
||||
gdk_win32_surface_maximize (GdkSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_SURFACE (window));
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
g_return_if_fail (GDK_IS_SURFACE (surface));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (surface))
|
||||
return;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("gdk_surface_maximize: %p: %s\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
_gdk_win32_surface_state_to_string (window->state)));
|
||||
GDK_SURFACE_HWND (surface),
|
||||
_gdk_win32_surface_state_to_string (surface->state)));
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (window))
|
||||
GtkShowWindow (window, SW_MAXIMIZE);
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
impl->inhibit_configure = TRUE;
|
||||
impl->force_recompute_size = FALSE;
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
GtkShowWindow (surface, SW_MAXIMIZE);
|
||||
else
|
||||
gdk_synthesize_surface_state (window,
|
||||
gdk_synthesize_surface_state (surface,
|
||||
0,
|
||||
GDK_TOPLEVEL_STATE_MAXIMIZED);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_surface_unmaximize (GdkSurface *window)
|
||||
gdk_win32_surface_unmaximize (GdkSurface *surface)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_SURFACE (window));
|
||||
GdkWin32Surface *impl;
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (window))
|
||||
g_return_if_fail (GDK_IS_SURFACE (surface));
|
||||
|
||||
if (GDK_SURFACE_DESTROYED (surface))
|
||||
return;
|
||||
|
||||
GDK_NOTE (MISC, g_print ("gdk_surface_unmaximize: %p: %s\n",
|
||||
GDK_SURFACE_HWND (window),
|
||||
_gdk_win32_surface_state_to_string (window->state)));
|
||||
GDK_SURFACE_HWND (surface),
|
||||
_gdk_win32_surface_state_to_string (surface->state)));
|
||||
|
||||
_gdk_win32_surface_invalidate_egl_framebuffer (window);
|
||||
_gdk_win32_surface_invalidate_egl_framebuffer (surface);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (window))
|
||||
GtkShowWindow (window, SW_RESTORE);
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
GtkShowWindow (surface, SW_RESTORE);
|
||||
else
|
||||
gdk_synthesize_surface_state (window,
|
||||
gdk_synthesize_surface_state (surface,
|
||||
GDK_TOPLEVEL_STATE_MAXIMIZED,
|
||||
0);
|
||||
|
||||
impl = GDK_WIN32_SURFACE (surface);
|
||||
|
||||
if (impl->inhibit_configure)
|
||||
{
|
||||
impl->inhibit_configure = FALSE;
|
||||
impl->force_recompute_size = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4547,6 +4534,9 @@ _gdk_win32_surface_request_layout (GdkSurface *surface)
|
||||
&surface->x, &surface->y,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (!impl->inhibit_configure)
|
||||
impl->force_recompute_size = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4561,8 +4551,18 @@ _gdk_win32_surface_compute_size (GdkSurface *surface)
|
||||
|
||||
if (!impl->drag_move_resize_context.native_move_resize_pending)
|
||||
{
|
||||
surface->width = impl->next_layout.configured_width;
|
||||
surface->height = impl->next_layout.configured_height;
|
||||
if (GDK_IS_TOPLEVEL (surface) && impl->force_recompute_size)
|
||||
{
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
gdk_win32_surface_resize (surface, width, height);
|
||||
impl->force_recompute_size = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
surface->width = impl->next_layout.configured_width;
|
||||
surface->height = impl->next_layout.configured_height;
|
||||
}
|
||||
|
||||
_gdk_surface_update_size (surface);
|
||||
}
|
||||
|
||||
@@ -337,6 +337,7 @@ struct _GdkWin32Surface
|
||||
int configured_height;
|
||||
RECT configured_rect;
|
||||
} next_layout;
|
||||
gboolean force_recompute_size;
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
guint egl_force_redraw_all : 1;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# libwntab32x.la - a libtool library file
|
||||
# Generated by hand, compatible with libtool
|
||||
# Just a wrapper for libwntab32x.a, which is just a copy of wntab32x.lib
|
||||
#
|
||||
# The name that we can dlopen(3).
|
||||
dlname=''
|
||||
|
||||
# Names of this library.
|
||||
library_names=''
|
||||
|
||||
# The name of the static archive.
|
||||
old_library='libwntab32x.a'
|
||||
|
||||
# Libraries that this one depends upon.
|
||||
dependency_libs=''
|
||||
|
||||
# Version information
|
||||
current=0
|
||||
age=0
|
||||
revision=0
|
||||
|
||||
# Is this an already installed library?
|
||||
installed=no
|
||||
|
||||
# Files to dlopen/dlpreopen
|
||||
dlopen=''
|
||||
dlpreopen=''
|
||||
|
||||
# Directory that this library needs to be installed in:
|
||||
libdir=''
|
||||
@@ -76,11 +76,30 @@ print_atoms (GdkX11Clipboard *cb,
|
||||
});
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_clipboard_default_output_closed (GObject *stream,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_close_finish (G_OUTPUT_STREAM (stream), result, &error))
|
||||
{
|
||||
GDK_NOTE (CLIPBOARD,
|
||||
g_printerr ("-------: failed to close stream: %s\n",
|
||||
error->message));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_clipboard_default_output_done (GObject *clipboard,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GOutputStream *stream = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!gdk_clipboard_write_finish (GDK_CLIPBOARD (clipboard), result, &error))
|
||||
@@ -90,6 +109,12 @@ gdk_x11_clipboard_default_output_done (GObject *clipboard,
|
||||
GDK_X11_CLIPBOARD (clipboard)->selection, error->message));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_output_stream_close_async (stream,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
gdk_x11_clipboard_default_output_closed,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -103,8 +128,7 @@ gdk_x11_clipboard_default_output_handler (GOutputStream *stream,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
gdk_x11_clipboard_default_output_done,
|
||||
NULL);
|
||||
g_object_unref (stream);
|
||||
stream);
|
||||
}
|
||||
|
||||
static GInputStream *
|
||||
|
||||
@@ -1665,7 +1665,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
|
||||
direction,
|
||||
FALSE);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1799,7 +1799,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
|
||||
x, y,
|
||||
axes);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1838,7 +1838,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
|
||||
x = (double) xev->event_x / scale;
|
||||
y = (double) xev->event_y / scale;
|
||||
|
||||
|
||||
event = gdk_touch_event_new (ev->evtype == XI_TouchBegin
|
||||
? GDK_TOUCH_BEGIN
|
||||
: GDK_TOUCH_END,
|
||||
@@ -1946,6 +1946,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
y = (double) xev->event_y / scale;
|
||||
|
||||
event = gdk_touchpad_event_new_pinch (surface,
|
||||
NULL, /* FIXME make up sequences */
|
||||
device,
|
||||
xev->time,
|
||||
state,
|
||||
@@ -2006,6 +2007,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
y = (double) xev->event_y / scale;
|
||||
|
||||
event = gdk_touchpad_event_new_swipe (surface,
|
||||
NULL, /* FIXME make up sequences */
|
||||
device,
|
||||
xev->time,
|
||||
state,
|
||||
|
||||
+26
-2
@@ -1612,11 +1612,30 @@ gdk_x11_drag_set_hotspot (GdkDrag *drag,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_drag_default_output_closed (GObject *stream,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_output_stream_close_finish (G_OUTPUT_STREAM (stream), result, &error))
|
||||
{
|
||||
GDK_NOTE (DND,
|
||||
g_printerr ("failed to close stream: %s\n",
|
||||
error->message));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_drag_default_output_done (GObject *drag,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GOutputStream *stream = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!gdk_drag_write_finish (GDK_DRAG (drag), result, &error))
|
||||
@@ -1624,6 +1643,12 @@ gdk_x11_drag_default_output_done (GObject *drag,
|
||||
GDK_DISPLAY_NOTE (gdk_drag_get_display (GDK_DRAG (drag)), DND, g_printerr ("failed to write stream: %s\n", error->message));
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_output_stream_close_async (stream,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
gdk_x11_drag_default_output_closed,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1637,8 +1662,7 @@ gdk_x11_drag_default_output_handler (GOutputStream *stream,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
gdk_x11_drag_default_output_done,
|
||||
NULL);
|
||||
g_object_unref (stream);
|
||||
stream);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -71,6 +71,8 @@ gdk_x11_surface_destroy_glx_drawable (GdkX11Surface *self)
|
||||
if (self->glx_drawable == None)
|
||||
return;
|
||||
|
||||
gdk_gl_context_clear_current_if_surface (GDK_SURFACE (self));
|
||||
|
||||
glXDestroyWindow (gdk_x11_display_get_xdisplay (gdk_surface_get_display (GDK_SURFACE (self))),
|
||||
self->glx_drawable);
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ struct _GdkX11SelectionOutputStreamPrivate {
|
||||
GTask *pending_task;
|
||||
|
||||
guint incr : 1;
|
||||
guint delete_pending : 1;
|
||||
guint sent_end_of_stream : 1;
|
||||
guint delete_pending : 1; /* owns a reference */
|
||||
};
|
||||
|
||||
struct _GdkX11PendingSelectionNotify
|
||||
@@ -176,12 +177,16 @@ gdk_x11_selection_output_stream_needs_flush_unlocked (GdkX11SelectionOutputStrea
|
||||
{
|
||||
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
if (priv->data->len == 0 && priv->notify == NULL)
|
||||
if (priv->sent_end_of_stream)
|
||||
return FALSE;
|
||||
|
||||
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
|
||||
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)) ||
|
||||
g_output_stream_is_closed (G_OUTPUT_STREAM (stream)))
|
||||
return TRUE;
|
||||
|
||||
if (priv->data->len == 0 && priv->notify == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (priv->flush_requested)
|
||||
return TRUE;
|
||||
|
||||
@@ -284,6 +289,8 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
|
||||
g_byte_array_remove_range (priv->data, 0, n_elements * element_size);
|
||||
if (priv->data->len < element_size)
|
||||
priv->flush_requested = FALSE;
|
||||
if (!priv->incr || n_elements == 0)
|
||||
priv->sent_end_of_stream = TRUE;
|
||||
}
|
||||
|
||||
if (priv->notify)
|
||||
@@ -292,6 +299,7 @@ gdk_x11_selection_output_stream_perform_flush (GdkX11SelectionOutputStream *stre
|
||||
priv->notify = NULL;
|
||||
}
|
||||
|
||||
g_object_ref (stream);
|
||||
priv->delete_pending = TRUE;
|
||||
g_cond_broadcast (&priv->cond);
|
||||
g_mutex_unlock (&priv->mutex);
|
||||
@@ -494,60 +502,6 @@ gdk_x11_selection_output_stream_flush_finish (GOutputStream *stream,
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_selection_output_stream_invoke_close (gpointer stream)
|
||||
{
|
||||
GdkX11SelectionOutputStreamPrivate *priv = gdk_x11_selection_output_stream_get_instance_private (stream);
|
||||
|
||||
GDK_X11_DISPLAY (priv->display)->streams = g_slist_remove (GDK_X11_DISPLAY (priv->display)->streams, stream);
|
||||
g_signal_handlers_disconnect_by_func (priv->display,
|
||||
gdk_x11_selection_output_stream_xevent,
|
||||
stream);
|
||||
g_object_unref (stream);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_selection_output_stream_close (GOutputStream *stream,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_main_context_invoke (NULL, gdk_x11_selection_output_stream_invoke_close, g_object_ref (stream));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_selection_output_stream_close_async (GOutputStream *stream,
|
||||
int io_priority,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (stream, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, gdk_x11_selection_output_stream_close_async);
|
||||
g_task_set_priority (task, io_priority);
|
||||
|
||||
gdk_x11_selection_output_stream_invoke_close (stream);
|
||||
g_task_return_boolean (task, TRUE);
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_selection_output_stream_close_finish (GOutputStream *stream,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
|
||||
g_return_val_if_fail (g_async_result_is_tagged (result, gdk_x11_selection_output_stream_close_async), FALSE);
|
||||
|
||||
return g_task_propagate_boolean (G_TASK (result), error);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_selection_output_stream_finalize (GObject *object)
|
||||
{
|
||||
@@ -557,6 +511,13 @@ gdk_x11_selection_output_stream_finalize (GObject *object)
|
||||
/* not sending a notify is terrible */
|
||||
g_assert (priv->notify == NULL);
|
||||
|
||||
GDK_DISPLAY_NOTE (priv->display, SELECTION, g_printerr ("%s:%s: finalizing\n",
|
||||
priv->selection, priv->target));
|
||||
GDK_X11_DISPLAY (priv->display)->streams = g_slist_remove (GDK_X11_DISPLAY (priv->display)->streams, stream);
|
||||
g_signal_handlers_disconnect_by_func (priv->display,
|
||||
gdk_x11_selection_output_stream_xevent,
|
||||
stream);
|
||||
|
||||
g_byte_array_unref (priv->data);
|
||||
g_cond_clear (&priv->cond);
|
||||
g_mutex_clear (&priv->mutex);
|
||||
@@ -579,14 +540,11 @@ gdk_x11_selection_output_stream_class_init (GdkX11SelectionOutputStreamClass *kl
|
||||
|
||||
output_stream_class->write_fn = gdk_x11_selection_output_stream_write;
|
||||
output_stream_class->flush = gdk_x11_selection_output_stream_flush;
|
||||
output_stream_class->close_fn = gdk_x11_selection_output_stream_close;
|
||||
|
||||
output_stream_class->write_async = gdk_x11_selection_output_stream_write_async;
|
||||
output_stream_class->write_finish = gdk_x11_selection_output_stream_write_finish;
|
||||
output_stream_class->flush_async = gdk_x11_selection_output_stream_flush_async;
|
||||
output_stream_class->flush_finish = gdk_x11_selection_output_stream_flush_finish;
|
||||
output_stream_class->close_async = gdk_x11_selection_output_stream_close_async;
|
||||
output_stream_class->close_finish = gdk_x11_selection_output_stream_close_finish;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -628,6 +586,7 @@ gdk_x11_selection_output_stream_xevent (GdkDisplay *display,
|
||||
if (gdk_x11_selection_output_stream_needs_flush (stream) &&
|
||||
gdk_x11_selection_output_stream_can_flush (stream))
|
||||
gdk_x11_selection_output_stream_perform_flush (stream);
|
||||
g_object_unref (stream); /* from unsetting the delete_pending */
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
|
||||
@@ -3535,7 +3535,7 @@ gdk_x11_surface_unfullscreen (GdkSurface *surface)
|
||||
*
|
||||
* Returns the group this surface belongs to.
|
||||
*
|
||||
* Returns: (transfer none): The group of this surface;
|
||||
* Returns: (transfer none) (nullable): The group of this surface;
|
||||
*/
|
||||
GdkSurface *
|
||||
gdk_x11_surface_get_group (GdkSurface *surface)
|
||||
|
||||
@@ -952,9 +952,9 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
guint program = 0;
|
||||
guint width = 0;
|
||||
guint height = 0;
|
||||
guint n_binds = 0;
|
||||
G_GNUC_UNUSED guint n_binds = 0;
|
||||
guint n_fbos = 0;
|
||||
guint n_uniforms = 0;
|
||||
G_GNUC_UNUSED guint n_uniforms = 0;
|
||||
guint n_programs = 0;
|
||||
guint vao_id;
|
||||
guint vbo_id;
|
||||
@@ -1396,7 +1396,7 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self,
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
}
|
||||
else if (stride % bpp == 0 &&
|
||||
(!use_es || gdk_gl_context_check_version (context, 3, 0) || gdk_gl_context_has_unpack_subimage (context)))
|
||||
(gdk_gl_context_check_version (context, 0, 0, 3, 0) || gdk_gl_context_has_unpack_subimage (context)))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
|
||||
@@ -147,7 +147,8 @@ gsk_gl_compiler_new (GskGLDriver *driver,
|
||||
|
||||
gdk_gl_context_get_version (context, &maj, &min);
|
||||
|
||||
if (maj == 3)
|
||||
/* On Windows, legacy contexts can give us a GL 4.x context */
|
||||
if (maj >= 3)
|
||||
self->glsl_version = SHADER_VERSION_GL3_LEGACY;
|
||||
else
|
||||
self->glsl_version = SHADER_VERSION_GL2_LEGACY;
|
||||
|
||||
+74
-18
@@ -245,6 +245,47 @@ gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
|
||||
self->corner[1].height + self->corner[2].height);
|
||||
}
|
||||
|
||||
static inline gboolean G_GNUC_PURE
|
||||
node_supports_2d_transform (const GskRenderNode *node)
|
||||
{
|
||||
switch ((int)gsk_render_node_get_node_type (node))
|
||||
{
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_OPACITY_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_CONIC_GRADIENT_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_DEBUG_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
return TRUE;
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
return node_supports_2d_transform (gsk_shadow_node_get_child (node));
|
||||
|
||||
case GSK_TRANSFORM_NODE:
|
||||
return node_supports_2d_transform (gsk_transform_node_get_child (node));
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
for (guint i = 0, p = gsk_container_node_get_n_children (node); i < p; i++)
|
||||
{
|
||||
if (!node_supports_2d_transform (gsk_container_node_get_child (node, i)))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline gboolean G_GNUC_PURE
|
||||
node_supports_transform (const GskRenderNode *node)
|
||||
{
|
||||
@@ -257,24 +298,26 @@ node_supports_transform (const GskRenderNode *node)
|
||||
|
||||
switch ((int)gsk_render_node_get_node_type (node))
|
||||
{
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_OPACITY_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
case GSK_DEBUG_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
return TRUE;
|
||||
case GSK_COLOR_NODE:
|
||||
case GSK_OPACITY_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXTURE_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_DEBUG_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
return TRUE;
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
return node_supports_transform (gsk_shadow_node_get_child (node));
|
||||
case GSK_SHADOW_NODE:
|
||||
return node_supports_transform (gsk_shadow_node_get_child (node));
|
||||
|
||||
case GSK_TRANSFORM_NODE:
|
||||
return node_supports_transform (gsk_transform_node_get_child (node));
|
||||
case GSK_TRANSFORM_NODE:
|
||||
return node_supports_transform (gsk_transform_node_get_child (node));
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2017,6 +2060,14 @@ gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job,
|
||||
break;
|
||||
|
||||
case GSK_TRANSFORM_CATEGORY_2D:
|
||||
if (node_supports_2d_transform (child))
|
||||
{
|
||||
gsk_gl_render_job_push_modelview (job, transform);
|
||||
gsk_gl_render_job_visit_node (job, child);
|
||||
gsk_gl_render_job_pop_modelview (job);
|
||||
return;
|
||||
}
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GSK_TRANSFORM_CATEGORY_3D:
|
||||
case GSK_TRANSFORM_CATEGORY_ANY:
|
||||
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
|
||||
@@ -4066,14 +4117,19 @@ gsk_gl_render_job_set_debug_fallback (GskGLRenderJob *job,
|
||||
}
|
||||
|
||||
static int
|
||||
get_framebuffer_format (guint framebuffer)
|
||||
get_framebuffer_format (GdkGLContext *context,
|
||||
guint framebuffer)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!gdk_gl_context_check_version (context, 0, 0, 3, 0))
|
||||
return GL_RGBA8;
|
||||
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
|
||||
glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
|
||||
framebuffer ? GL_COLOR_ATTACHMENT0
|
||||
: GL_BACK_LEFT,
|
||||
: gdk_gl_context_get_use_es (context) ? GL_BACK
|
||||
: GL_BACK_LEFT,
|
||||
GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size);
|
||||
|
||||
if (size > 16)
|
||||
@@ -4110,7 +4166,7 @@ gsk_gl_render_job_new (GskGLDriver *driver,
|
||||
job->scale_x = scale_factor;
|
||||
job->scale_y = scale_factor;
|
||||
job->viewport = *viewport;
|
||||
job->target_format = get_framebuffer_format (framebuffer);
|
||||
job->target_format = get_framebuffer_format (job->command_queue->context, framebuffer);
|
||||
|
||||
gsk_gl_render_job_set_alpha (job, 1.0f);
|
||||
gsk_gl_render_job_set_projection_from_rect (job, viewport, NULL);
|
||||
|
||||
+14
-5
@@ -356,6 +356,8 @@ compare (gconstpointer *elem1,
|
||||
const GskDiffSettings *settings,
|
||||
gpointer data)
|
||||
{
|
||||
GskDiffResult res;
|
||||
|
||||
/*
|
||||
* Shrink the box by walking through each diagonal snake (SW and NE).
|
||||
*/
|
||||
@@ -364,7 +366,9 @@ compare (gconstpointer *elem1,
|
||||
if (settings->compare_func (elem1[off1], elem2[off2], data) != 0)
|
||||
break;
|
||||
|
||||
settings->keep_func (elem1[off1], elem2[off2], data);
|
||||
res = settings->keep_func (elem1[off1], elem2[off2], data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
for (; off1 < lim1 && off2 < lim2; lim1--, lim2--)
|
||||
@@ -372,7 +376,9 @@ compare (gconstpointer *elem1,
|
||||
if (settings->compare_func (elem1[lim1 - 1], elem2[lim2 - 1], data) != 0)
|
||||
break;
|
||||
|
||||
settings->keep_func (elem1[lim1 - 1], elem2[lim2 - 1], data);
|
||||
res = settings->keep_func (elem1[lim1 - 1], elem2[lim2 - 1], data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -383,20 +389,23 @@ compare (gconstpointer *elem1,
|
||||
{
|
||||
for (; off2 < lim2; off2++)
|
||||
{
|
||||
settings->insert_func (elem2[off2], off2, data);
|
||||
res = settings->insert_func (elem2[off2], off2, data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else if (off2 == lim2)
|
||||
{
|
||||
for (; off1 < lim1; off1++)
|
||||
{
|
||||
settings->delete_func (elem1[off1], off1, data);
|
||||
res = settings->delete_func (elem1[off1], off1, data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitResult spl = { 0, };
|
||||
GskDiffResult res;
|
||||
|
||||
/*
|
||||
* Divide ...
|
||||
|
||||
@@ -29,9 +29,9 @@ typedef enum {
|
||||
GSK_DIFF_ABORTED,
|
||||
} GskDiffResult;
|
||||
|
||||
typedef void (* GskKeepFunc) (gconstpointer elem1, gconstpointer elem2, gpointer data);
|
||||
typedef void (* GskDeleteFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
typedef void (* GskInsertFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
typedef GskDiffResult (* GskKeepFunc) (gconstpointer elem1, gconstpointer elem2, gpointer data);
|
||||
typedef GskDiffResult (* GskDeleteFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
typedef GskDiffResult (* GskInsertFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
|
||||
typedef struct _GskDiffSettings GskDiffSettings;
|
||||
|
||||
|
||||
+6
-1
@@ -289,10 +289,15 @@ gsk_renderer_is_realized (GskRenderer *renderer)
|
||||
*
|
||||
* Since GTK 4.6, the surface may be `NULL`, which allows using
|
||||
* renderers without having to create a surface.
|
||||
*
|
||||
* Note that it is mandatory to call [method@Gsk.Renderer.unrealize] before
|
||||
* destroying the renderer.
|
||||
*
|
||||
* Returns: Whether the renderer was successfully realized
|
||||
*/
|
||||
gboolean
|
||||
gsk_renderer_realize (GskRenderer *renderer,
|
||||
GdkSurface *surface,
|
||||
GdkSurface *surface,
|
||||
GError **error)
|
||||
{
|
||||
GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
|
||||
|
||||
+9
-9
@@ -20,7 +20,7 @@
|
||||
* GskRenderNode: (ref-func gsk_render_node_ref) (unref-func gsk_render_node_unref) (set-value-func gsk_value_set_render_node) (get-value-func gsk_value_get_render_node)
|
||||
*
|
||||
* `GskRenderNode` is the basic block in a scene graph to be
|
||||
* rendered using `GskRenderer`.
|
||||
* rendered using [class@Gsk.Renderer].
|
||||
*
|
||||
* Each node has a parent, except the top-level node; each node may have
|
||||
* children nodes.
|
||||
@@ -424,7 +424,7 @@ gsk_render_node_get_bounds (GskRenderNode *node,
|
||||
*
|
||||
* Typically, you'll use this function to implement fallback rendering
|
||||
* of `GskRenderNode`s on an intermediate Cairo context, instead of using
|
||||
* the drawing context associated to a `GdkSurface`'s rendering buffer.
|
||||
* the drawing context associated to a [class@Gdk.Surface]'s rendering buffer.
|
||||
*
|
||||
* For advanced nodes that cannot be supported using Cairo, in particular
|
||||
* for nodes doing 3D operations, this function may fail.
|
||||
@@ -565,8 +565,8 @@ gsk_render_node_diff (GskRenderNode *node1,
|
||||
* @filename: (type filename): the file to save it to.
|
||||
* @error: Return location for a potential error
|
||||
*
|
||||
* This function is equivalent to calling gsk_render_node_serialize()
|
||||
* followed by g_file_set_contents().
|
||||
* This function is equivalent to calling [method@Gsk.RenderNode.serialize]
|
||||
* followed by [func@GLib.file_set_contents].
|
||||
*
|
||||
* See those two functions for details on the arguments.
|
||||
*
|
||||
@@ -603,7 +603,7 @@ gsk_render_node_write_to_file (GskRenderNode *node,
|
||||
* @error_func: (nullable) (scope call): Callback on parsing errors
|
||||
* @user_data: (closure error_func): user_data for @error_func
|
||||
*
|
||||
* Loads data previously created via gsk_render_node_serialize().
|
||||
* Loads data previously created via [method@Gsk.RenderNode.serialize].
|
||||
*
|
||||
* For a discussion of the supported format, see that function.
|
||||
*
|
||||
@@ -623,12 +623,12 @@ gsk_render_node_deserialize (GBytes *bytes,
|
||||
|
||||
/**
|
||||
* gsk_value_set_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @value: a [struct@GObject.Value] initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @node: a `GskRenderNode`
|
||||
*
|
||||
* Stores the given `GskRenderNode` inside `value`.
|
||||
*
|
||||
* The `GValue` will acquire a reference to the `node`.
|
||||
* The [struct@GObject.Value] will acquire a reference to the `node`.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
@@ -659,7 +659,7 @@ gsk_value_set_render_node (GValue *value,
|
||||
|
||||
/**
|
||||
* gsk_value_take_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @value: a [struct@GObject.Value] initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @node: (transfer full) (nullable): a `GskRenderNode`
|
||||
*
|
||||
* Stores the given `GskRenderNode` inside `value`.
|
||||
@@ -713,7 +713,7 @@ gsk_value_get_render_node (const GValue *value)
|
||||
|
||||
/**
|
||||
* gsk_value_dup_render_node:
|
||||
* @value: a `GValue` initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
* @value: a [struct@GObject.Value] initialized with type `GSK_TYPE_RENDER_NODE`
|
||||
*
|
||||
* Retrieves the `GskRenderNode` stored inside the given `value`, and acquires
|
||||
* a reference to it.
|
||||
|
||||
+22
-13
@@ -33,6 +33,12 @@
|
||||
|
||||
#include <hb-ot.h>
|
||||
|
||||
/* maximal number of rectangles we keep in a diff region before we throw
|
||||
* the towel and just use the bounding box of the parent node.
|
||||
* Meant to avoid performance corner cases.
|
||||
*/
|
||||
#define MAX_RECTS_IN_DIFF 30
|
||||
|
||||
static inline void
|
||||
gsk_cairo_rectangle (cairo_t *cr,
|
||||
const graphene_rect_t *rect)
|
||||
@@ -2601,32 +2607,35 @@ gsk_container_node_draw (GskRenderNode *node,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_render_node_add_to_region (GskRenderNode *node,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
rectangle_init_from_graphene (&rect, &node->bounds);
|
||||
cairo_region_union_rectangle (region, &rect);
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_container_node_compare_func (gconstpointer elem1, gconstpointer elem2, gpointer data)
|
||||
{
|
||||
return gsk_render_node_can_diff ((const GskRenderNode *) elem1, (const GskRenderNode *) elem2) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void
|
||||
static GskDiffResult
|
||||
gsk_container_node_keep_func (gconstpointer elem1, gconstpointer elem2, gpointer data)
|
||||
{
|
||||
gsk_render_node_diff ((GskRenderNode *) elem1, (GskRenderNode *) elem2, data);
|
||||
if (cairo_region_num_rectangles (data) > MAX_RECTS_IN_DIFF)
|
||||
return GSK_DIFF_ABORTED;
|
||||
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
static GskDiffResult
|
||||
gsk_container_node_change_func (gconstpointer elem, gsize idx, gpointer data)
|
||||
{
|
||||
gsk_render_node_add_to_region ((GskRenderNode *) elem, data);
|
||||
const GskRenderNode *node = elem;
|
||||
cairo_region_t *region = data;
|
||||
cairo_rectangle_int_t rect;
|
||||
|
||||
rectangle_init_from_graphene (&rect, &node->bounds);
|
||||
cairo_region_union_rectangle (region, &rect);
|
||||
if (cairo_region_num_rectangles (region) > MAX_RECTS_IN_DIFF)
|
||||
return GSK_DIFF_ABORTED;
|
||||
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
|
||||
static GskDiffSettings *
|
||||
|
||||
@@ -334,6 +334,9 @@ get_index_in_parent (GtkWidget *widget)
|
||||
GtkWidget *child;
|
||||
int idx;
|
||||
|
||||
if (parent == NULL)
|
||||
return -1;
|
||||
|
||||
idx = 0;
|
||||
for (child = gtk_widget_get_first_child (parent);
|
||||
child;
|
||||
|
||||
@@ -140,7 +140,7 @@ gtk_css_section_get_parent (const GtkCssSection *section)
|
||||
* If no such file exists, for example because the CSS was loaded via
|
||||
* [method@Gtk.CssProvider.load_from_data], then `NULL` is returned.
|
||||
*
|
||||
* Returns: (transfer none): the `GFile` from which the `section`
|
||||
* Returns: (transfer none) (nullable): the `GFile` from which the `section`
|
||||
* was parsed
|
||||
**/
|
||||
GFile *
|
||||
|
||||
@@ -36,7 +36,7 @@ G_BEGIN_DECLS
|
||||
* Defines a part of a CSS document.
|
||||
*
|
||||
* Because sections are nested into one another, you can use
|
||||
* gtk_css_section_get_parent() to get the containing region.
|
||||
* [method@CssSection.get_parent] to get the containing region.
|
||||
*/
|
||||
typedef struct _GtkCssSection GtkCssSection;
|
||||
|
||||
|
||||
+11
-11
@@ -44,10 +44,10 @@
|
||||
|
||||
/**
|
||||
* GtkActionableInterface:
|
||||
* @get_action_name: virtual function for gtk_actionable_get_action_name()
|
||||
* @set_action_name: virtual function for gtk_actionable_set_action_name()
|
||||
* @get_action_target_value: virtual function for gtk_actionable_get_action_target_value()
|
||||
* @set_action_target_value: virtual function for gtk_actionable_set_action_target_value()
|
||||
* @get_action_name: virtual function for [method@Actionable.get_action_name]
|
||||
* @set_action_name: virtual function for [method@Actionable.set_action_name]
|
||||
* @get_action_target_value: virtual function for [method@Actionable.get_action_target_value]
|
||||
* @set_action_target_value: virtual function for [method@Actionable.set_action_target_value]
|
||||
*
|
||||
* The interface vtable for `GtkActionable`.
|
||||
**/
|
||||
@@ -100,8 +100,8 @@ gtk_actionable_get_action_name (GtkActionable *actionable)
|
||||
* located) within the hierarchy of a `GtkApplicationWindow`.
|
||||
*
|
||||
* Names are of the form “win.save” or “app.quit” for actions on the
|
||||
* containing `GtkApplicationWindow` or its associated `GtkApplication`,
|
||||
* respectively. This is the same form used for actions in the `GMenu`
|
||||
* containing [class@ApplicationWindow] or its associated [class@Application],
|
||||
* respectively. This is the same form used for actions in the [class@Gio.Menu]
|
||||
* associated with the window.
|
||||
*/
|
||||
void
|
||||
@@ -134,7 +134,7 @@ gtk_actionable_get_action_target_value (GtkActionable *actionable)
|
||||
/**
|
||||
* gtk_actionable_set_action_target_value: (attributes org.gtk.Method.set_property=action-target)
|
||||
* @actionable: a `GtkActionable` widget
|
||||
* @target_value: (nullable): a `GVariant` to set as the target value
|
||||
* @target_value: (nullable): a [struct@GLib.Variant] to set as the target value
|
||||
*
|
||||
* Sets the target value of an actionable widget.
|
||||
*
|
||||
@@ -145,7 +145,7 @@ gtk_actionable_get_action_target_value (GtkActionable *actionable)
|
||||
* Second, it is used to determine if the widget should be rendered as
|
||||
* “active” — the widget is active if the state is equal to the given target.
|
||||
*
|
||||
* Consider the example of associating a set of buttons with a `GAction`
|
||||
* Consider the example of associating a set of buttons with a [iface@Gio.Action]
|
||||
* with string state in a typical “radio button” situation. Each button
|
||||
* will be associated with the same action, but with a different target
|
||||
* value for that action. Clicking on a particular button will activate
|
||||
@@ -168,12 +168,12 @@ gtk_actionable_set_action_target_value (GtkActionable *actionable,
|
||||
/**
|
||||
* gtk_actionable_set_action_target:
|
||||
* @actionable: a `GtkActionable` widget
|
||||
* @format_string: a GVariant format string
|
||||
* @format_string: a [struct@GLib.Variant] format string
|
||||
* @...: arguments appropriate for @format_string
|
||||
*
|
||||
* Sets the target of an actionable widget.
|
||||
*
|
||||
* This is a convenience function that calls g_variant_new() for
|
||||
* This is a convenience function that calls [ctor@GLib.Variant.new] for
|
||||
* @format_string and uses the result to call
|
||||
* [method@Gtk.Actionable.set_action_target_value].
|
||||
*
|
||||
@@ -202,7 +202,7 @@ gtk_actionable_set_action_target (GtkActionable *actionable,
|
||||
* actionable widget.
|
||||
*
|
||||
* @detailed_action_name is a string in the format accepted by
|
||||
* g_action_parse_detailed_name().
|
||||
* [func@Gio.Action.parse_detailed_name].
|
||||
*/
|
||||
void
|
||||
gtk_actionable_set_detailed_action_name (GtkActionable *actionable,
|
||||
|
||||
+16
-11
@@ -945,6 +945,7 @@ gtk_action_muxer_register_observer (GtkActionObservable *observable,
|
||||
gboolean enabled;
|
||||
const GVariantType *parameter_type;
|
||||
GVariant *state;
|
||||
gboolean is_duplicate;
|
||||
|
||||
if (!muxer->observed_actions)
|
||||
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action);
|
||||
@@ -961,22 +962,26 @@ gtk_action_muxer_register_observer (GtkActionObservable *observable,
|
||||
g_hash_table_insert (muxer->observed_actions, action->fullname, action);
|
||||
}
|
||||
|
||||
is_duplicate = g_slist_find (action->watchers, observer) != NULL;
|
||||
action->watchers = g_slist_prepend (action->watchers, observer);
|
||||
g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
|
||||
|
||||
if (action_muxer_query_action (muxer, name,
|
||||
&enabled, ¶meter_type,
|
||||
NULL, NULL, &state, TRUE))
|
||||
if (!is_duplicate)
|
||||
{
|
||||
gtk_action_muxer_action_added (muxer, name, parameter_type, enabled, state);
|
||||
g_clear_pointer (&state, g_variant_unref);
|
||||
}
|
||||
if (action_muxer_query_action (muxer, name,
|
||||
&enabled, ¶meter_type,
|
||||
NULL, NULL, &state, TRUE))
|
||||
{
|
||||
gtk_action_muxer_action_added (muxer, name, parameter_type, enabled, state);
|
||||
g_clear_pointer (&state, g_variant_unref);
|
||||
}
|
||||
|
||||
if (muxer->parent)
|
||||
{
|
||||
gtk_action_observable_register_observer (GTK_ACTION_OBSERVABLE (muxer->parent),
|
||||
name,
|
||||
GTK_ACTION_OBSERVER (muxer));
|
||||
if (muxer->parent)
|
||||
{
|
||||
gtk_action_observable_register_observer (GTK_ACTION_OBSERVABLE (muxer->parent),
|
||||
name,
|
||||
GTK_ACTION_OBSERVER (muxer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -435,9 +435,11 @@ gtk_application_window_measure (GtkWidget *widget,
|
||||
gtk_widget_measure (priv->menubar, GTK_ORIENTATION_VERTICAL,
|
||||
for_size, &menubar_height, NULL, NULL, NULL);
|
||||
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_application_window_parent_class)->measure (widget,
|
||||
orientation,
|
||||
for_size - menubar_height,
|
||||
for_size > -1 ?
|
||||
for_size - menubar_height : -1,
|
||||
minimum, natural,
|
||||
minimum_baseline, natural_baseline);
|
||||
|
||||
|
||||
+22
-4
@@ -546,7 +546,7 @@ gtk_bitset_union (GtkBitset *self,
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
@@ -571,7 +571,7 @@ gtk_bitset_intersect (GtkBitset *self,
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
@@ -596,7 +596,7 @@ gtk_bitset_subtract (GtkBitset *self,
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
@@ -626,7 +626,7 @@ gtk_bitset_difference (GtkBitset *self,
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
@@ -756,6 +756,24 @@ gtk_bitset_splice (GtkBitset *self,
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GtkBitsetIter) >= sizeof (roaring_uint32_iterator_t));
|
||||
|
||||
static GtkBitsetIter *
|
||||
gtk_bitset_iter_copy (GtkBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
return (GtkBitsetIter *) roaring_copy_uint32_iterator (riter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_bitset_iter_free (GtkBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
roaring_free_uint32_iterator (riter);
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GtkBitsetIter, gtk_bitset_iter, gtk_bitset_iter_copy, gtk_bitset_iter_free)
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_init_first:
|
||||
* @iter: (out): a pointer to an uninitialized `GtkBitsetIter`
|
||||
|
||||
+3
-2
@@ -148,6 +148,9 @@ struct _GtkBitsetIter
|
||||
gpointer private_data[10];
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GType gtk_bitset_iter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_init_first (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
@@ -171,8 +174,6 @@ GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_iter_get_value (const GtkBitsetIter *iter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_is_valid (const GtkBitsetIter *iter);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ gtk_buildable_set_buildable_id (GtkBuildable *buildable,
|
||||
* `GtkBuilder` sets the name based on the ID attribute
|
||||
* of the <object> tag used to construct the @buildable.
|
||||
*
|
||||
* Returns: the ID of the buildable object
|
||||
* Returns: (nullable): the ID of the buildable object
|
||||
**/
|
||||
const char *
|
||||
gtk_buildable_get_buildable_id (GtkBuildable *buildable)
|
||||
|
||||
@@ -2322,6 +2322,40 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
|
||||
{
|
||||
g_value_take_boxed (value, g_bytes_new (string, strlen (string)));
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, PANGO_TYPE_FONT_DESCRIPTION))
|
||||
{
|
||||
PangoFontDescription *desc;
|
||||
|
||||
desc = pango_font_description_from_string (string);
|
||||
if (desc)
|
||||
g_value_take_boxed (value, desc);
|
||||
else
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_INVALID_VALUE,
|
||||
"Could not parse '%s' as a %s",
|
||||
string, G_VALUE_TYPE_NAME (value));
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, PANGO_TYPE_ATTR_LIST))
|
||||
{
|
||||
PangoAttrList *attrs;
|
||||
|
||||
attrs = pango_attr_list_from_string (string);
|
||||
if (attrs)
|
||||
g_value_take_boxed (value, attrs);
|
||||
else
|
||||
{
|
||||
g_set_error (error,
|
||||
GTK_BUILDER_ERROR,
|
||||
GTK_BUILDER_ERROR_INVALID_VALUE,
|
||||
"Could not parse '%s' as a %s",
|
||||
string, G_VALUE_TYPE_NAME (value));
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error,
|
||||
|
||||
+335
-151
@@ -27,100 +27,228 @@
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RECORD_TYPE_ELEMENT,
|
||||
RECORD_TYPE_END_ELEMENT,
|
||||
RECORD_TYPE_TEXT,
|
||||
} RecordTreeType;
|
||||
RECORD_TYPE_ELEMENT,
|
||||
RECORD_TYPE_END_ELEMENT,
|
||||
RECORD_TYPE_TEXT,
|
||||
} RecordDataType;
|
||||
|
||||
typedef struct RecordDataTree RecordDataTree;
|
||||
/* All strings are owned by the string chunk */
|
||||
typedef struct {
|
||||
/* Must be first for g_slice_free_chain() */
|
||||
GList link;
|
||||
|
||||
/* All strings are owned by the string table */
|
||||
struct RecordDataTree {
|
||||
RecordDataTree *parent;
|
||||
RecordTreeType type;
|
||||
const char *string;
|
||||
int len;
|
||||
int count;
|
||||
int offset;
|
||||
int text_offset;
|
||||
gboolean include_len;
|
||||
} RecordDataString;
|
||||
|
||||
typedef struct {
|
||||
RecordDataType type;
|
||||
GList link;
|
||||
} RecordDataNode;
|
||||
|
||||
typedef struct RecordDataElement RecordDataElement;
|
||||
|
||||
struct RecordDataElement {
|
||||
RecordDataNode base;
|
||||
|
||||
RecordDataElement *parent;
|
||||
GQueue children;
|
||||
int n_attributes;
|
||||
const char *data;
|
||||
const char **attributes;
|
||||
const char **values;
|
||||
GList *children;
|
||||
gboolean preserve_whitespace;
|
||||
RecordDataString *name;
|
||||
RecordDataString *attributes[];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *string;
|
||||
int count;
|
||||
int offset;
|
||||
} RecordDataString;
|
||||
RecordDataNode base;
|
||||
|
||||
static RecordDataTree *
|
||||
record_data_tree_new (RecordDataTree *parent,
|
||||
RecordTreeType type,
|
||||
const char *data)
|
||||
{
|
||||
RecordDataTree *tree = g_slice_new0 (RecordDataTree);
|
||||
|
||||
tree->parent = parent;
|
||||
tree->type = type;
|
||||
tree->data = data;
|
||||
|
||||
if (parent)
|
||||
parent->children = g_list_prepend (parent->children, tree);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
static void
|
||||
record_data_tree_free (RecordDataTree *tree)
|
||||
{
|
||||
g_list_free_full (tree->children, (GDestroyNotify)record_data_tree_free);
|
||||
g_free (tree->attributes);
|
||||
g_free (tree->values);
|
||||
g_slice_free (RecordDataTree, tree);
|
||||
}
|
||||
|
||||
static void
|
||||
record_data_string_free (RecordDataString *s)
|
||||
{
|
||||
g_free (s->string);
|
||||
g_slice_free (RecordDataString, s);
|
||||
}
|
||||
|
||||
static const char *
|
||||
record_data_string_lookup (GHashTable *strings,
|
||||
const char *str,
|
||||
gssize len)
|
||||
{
|
||||
char *copy = NULL;
|
||||
RecordDataString *s;
|
||||
|
||||
if (len >= 0)
|
||||
{
|
||||
/* Ensure str is zero terminated */
|
||||
copy = g_strndup (str, len);
|
||||
str = copy;
|
||||
}
|
||||
|
||||
s = g_hash_table_lookup (strings, str);
|
||||
if (s)
|
||||
{
|
||||
g_free (copy);
|
||||
s->count++;
|
||||
return s->string;
|
||||
}
|
||||
|
||||
s = g_slice_new (RecordDataString);
|
||||
s->string = copy ? copy : g_strdup (str);
|
||||
s->count = 1;
|
||||
|
||||
g_hash_table_insert (strings, s->string, s);
|
||||
return s->string;
|
||||
}
|
||||
RecordDataString *string;
|
||||
} RecordDataText;
|
||||
|
||||
typedef struct {
|
||||
GHashTable *strings;
|
||||
RecordDataTree *root;
|
||||
RecordDataTree *current;
|
||||
GStringChunk *chunks;
|
||||
GQueue string_list;
|
||||
RecordDataElement *root;
|
||||
RecordDataElement *current;
|
||||
} RecordData;
|
||||
|
||||
static gpointer
|
||||
record_data_node_new (RecordDataElement *parent,
|
||||
RecordDataType type,
|
||||
gsize size)
|
||||
{
|
||||
RecordDataNode *node = g_slice_alloc0 (size);
|
||||
|
||||
node->type = type;
|
||||
node->link.data = node;
|
||||
|
||||
if (parent)
|
||||
g_queue_push_tail_link (&parent->children, &node->link);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
text_is_important (const char *name)
|
||||
{
|
||||
const char *elements[] = {
|
||||
"property",
|
||||
"attribute",
|
||||
"col",
|
||||
"action-widget",
|
||||
"item",
|
||||
"mime-type",
|
||||
"pattern",
|
||||
"suffix",
|
||||
"mark",
|
||||
NULL
|
||||
};
|
||||
|
||||
return g_strv_contains (elements, name);
|
||||
}
|
||||
|
||||
static RecordDataElement *
|
||||
record_data_element_new (RecordDataElement *parent,
|
||||
RecordDataString *name,
|
||||
gsize n_attributes)
|
||||
{
|
||||
RecordDataElement *element;
|
||||
|
||||
element = record_data_node_new (parent,
|
||||
RECORD_TYPE_ELEMENT,
|
||||
sizeof (RecordDataElement) +
|
||||
sizeof (RecordDataString) * n_attributes);
|
||||
element->parent = parent;
|
||||
element->name = name;
|
||||
element->preserve_whitespace = name && text_is_important (name->string);
|
||||
element->n_attributes = n_attributes;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
static void
|
||||
record_data_element_append_text (RecordDataElement *parent,
|
||||
RecordDataString *string)
|
||||
{
|
||||
RecordDataText *text;
|
||||
|
||||
text = record_data_node_new (parent,
|
||||
RECORD_TYPE_TEXT,
|
||||
sizeof (RecordDataText));
|
||||
text->string = string;
|
||||
}
|
||||
|
||||
static void
|
||||
record_data_node_free (RecordDataNode *node)
|
||||
{
|
||||
GList *l, *next;
|
||||
RecordDataText *text;
|
||||
RecordDataElement *element;
|
||||
|
||||
switch (node->type)
|
||||
{
|
||||
case RECORD_TYPE_ELEMENT:
|
||||
element = (RecordDataElement *)node;
|
||||
|
||||
l = element->children.head;
|
||||
while (l)
|
||||
{
|
||||
next = l->next;
|
||||
record_data_node_free (l->data);
|
||||
l = next;
|
||||
}
|
||||
|
||||
g_slice_free1 (sizeof (RecordDataElement) +
|
||||
sizeof (RecordDataString) * element->n_attributes, element);
|
||||
break;
|
||||
case RECORD_TYPE_TEXT:
|
||||
text = (RecordDataText *)node;
|
||||
g_slice_free (RecordDataText, text);
|
||||
break;
|
||||
case RECORD_TYPE_END_ELEMENT:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
record_data_string_equal (gconstpointer _a,
|
||||
gconstpointer _b)
|
||||
{
|
||||
const RecordDataString *a = _a;
|
||||
const RecordDataString *b = _b;
|
||||
|
||||
return a->len == b->len &&
|
||||
memcmp (a->string, b->string, a->len) == 0;
|
||||
}
|
||||
|
||||
/* Copied from g_bytes_hash() */
|
||||
static guint
|
||||
record_data_string_hash (gconstpointer _a)
|
||||
{
|
||||
const RecordDataString *a = _a;
|
||||
const signed char *p, *e;
|
||||
guint32 h = 5381;
|
||||
|
||||
for (p = (signed char *)a->string, e = (signed char *)a->string + a->len; p != e; p++)
|
||||
h = (h << 5) + h + *p;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static int
|
||||
record_data_string_compare (gconstpointer _a,
|
||||
gconstpointer _b,
|
||||
gpointer user_data)
|
||||
{
|
||||
const RecordDataString *a = _a;
|
||||
const RecordDataString *b = _b;
|
||||
|
||||
return b->count - a->count;
|
||||
}
|
||||
|
||||
static RecordDataString *
|
||||
record_data_string_lookup (RecordData *data,
|
||||
const char *str,
|
||||
gssize len)
|
||||
{
|
||||
RecordDataString *s, tmp;
|
||||
gboolean include_len = len >= 0;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen (str);
|
||||
|
||||
tmp.string = str;
|
||||
tmp.len = len;
|
||||
|
||||
s = g_hash_table_lookup (data->strings, &tmp);
|
||||
if (s)
|
||||
{
|
||||
s->count++;
|
||||
s->include_len |= include_len;
|
||||
return s;
|
||||
}
|
||||
|
||||
s = g_slice_new (RecordDataString);
|
||||
/* The string is zero terminated */
|
||||
s->string = g_string_chunk_insert_len (data->chunks, str, len);
|
||||
s->len = len;
|
||||
s->count = 1;
|
||||
s->include_len = include_len;
|
||||
s->link.data = s;
|
||||
s->link.next = NULL;
|
||||
s->link.prev = NULL;
|
||||
|
||||
g_hash_table_add (data->strings, s);
|
||||
g_queue_push_tail_link (&data->string_list, &s->link);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
record_start_element (GMarkupParseContext *context,
|
||||
const char *element_name,
|
||||
@@ -131,21 +259,20 @@ record_start_element (GMarkupParseContext *context,
|
||||
{
|
||||
gsize n_attrs = g_strv_length ((char **)names);
|
||||
RecordData *data = user_data;
|
||||
RecordDataTree *child;
|
||||
RecordDataElement *child;
|
||||
RecordDataString *name, **attr_names, **attr_values;
|
||||
int i;
|
||||
|
||||
child = record_data_tree_new (data->current, RECORD_TYPE_ELEMENT,
|
||||
record_data_string_lookup (data->strings, element_name, -1));
|
||||
name = record_data_string_lookup (data, element_name, -1);
|
||||
child = record_data_element_new (data->current, name, n_attrs);
|
||||
data->current = child;
|
||||
|
||||
child->n_attributes = n_attrs;
|
||||
child->attributes = g_new (const char *, n_attrs);
|
||||
child->values = g_new (const char *, n_attrs);
|
||||
|
||||
attr_names = &child->attributes[0];
|
||||
attr_values = &child->attributes[n_attrs];
|
||||
for (i = 0; i < n_attrs; i++)
|
||||
{
|
||||
child->attributes[i] = record_data_string_lookup (data->strings, names[i], -1);
|
||||
child->values[i] = record_data_string_lookup (data->strings, values[i], -1);
|
||||
attr_names[i] = record_data_string_lookup (data, names[i], -1);
|
||||
attr_values[i] = record_data_string_lookup (data, values[i], -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +287,23 @@ record_end_element (GMarkupParseContext *context,
|
||||
data->current = data->current->parent;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_whitespace (const char *text,
|
||||
gsize text_len)
|
||||
{
|
||||
const char *end;
|
||||
const char *p;
|
||||
|
||||
end = text + text_len;
|
||||
for (p = text; p < end; p = g_utf8_next_char (p))
|
||||
{
|
||||
if (!g_unichar_isspace (g_utf8_get_char (p)))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
record_text (GMarkupParseContext *context,
|
||||
const char *text,
|
||||
@@ -168,9 +312,16 @@ record_text (GMarkupParseContext *context,
|
||||
GError **error)
|
||||
{
|
||||
RecordData *data = user_data;
|
||||
RecordDataString *string;
|
||||
|
||||
record_data_tree_new (data->current, RECORD_TYPE_TEXT,
|
||||
record_data_string_lookup (data->strings, text, text_len));
|
||||
if (text_len == 0)
|
||||
return;
|
||||
|
||||
if (!data->current->preserve_whitespace && is_whitespace (text, text_len))
|
||||
return;
|
||||
|
||||
string = record_data_string_lookup (data, text, text_len);
|
||||
record_data_element_append_text (data->current, string);
|
||||
}
|
||||
|
||||
static const GMarkupParser record_parser =
|
||||
@@ -182,16 +333,6 @@ static const GMarkupParser record_parser =
|
||||
NULL, // error, fails immediately
|
||||
};
|
||||
|
||||
static int
|
||||
compare_string (gconstpointer _a,
|
||||
gconstpointer _b)
|
||||
{
|
||||
const RecordDataString *a = _a;
|
||||
const RecordDataString *b = _b;
|
||||
|
||||
return b->count - a->count;
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_uint32 (GString *str,
|
||||
guint32 v)
|
||||
@@ -240,54 +381,60 @@ marshal_uint32 (GString *str,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_string (GString *marshaled,
|
||||
GHashTable *strings,
|
||||
const char *string)
|
||||
static int
|
||||
marshal_uint32_len (guint32 v)
|
||||
{
|
||||
RecordDataString *s;
|
||||
if (v < 128)
|
||||
return 1;
|
||||
|
||||
s = g_hash_table_lookup (strings, string);
|
||||
g_assert (s != NULL);
|
||||
if (v < (1<<14))
|
||||
return 2;
|
||||
|
||||
marshal_uint32 (marshaled, s->offset);
|
||||
if (v < (1<<21))
|
||||
return 3;
|
||||
|
||||
if (v < (1<<28))
|
||||
return 4;
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_tree (GString *marshaled,
|
||||
GHashTable *strings,
|
||||
RecordDataTree *tree)
|
||||
RecordDataNode *node)
|
||||
{
|
||||
GList *l;
|
||||
int i;
|
||||
RecordDataText *text;
|
||||
RecordDataElement *element;
|
||||
RecordDataString **attr_names, **attr_values;
|
||||
|
||||
/* Special case the root */
|
||||
if (tree->parent == NULL)
|
||||
{
|
||||
for (l = g_list_last (tree->children); l != NULL; l = l->prev)
|
||||
marshal_tree (marshaled, strings, l->data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (tree->type)
|
||||
switch (node->type)
|
||||
{
|
||||
case RECORD_TYPE_ELEMENT:
|
||||
element = (RecordDataElement *)node;
|
||||
|
||||
marshal_uint32 (marshaled, RECORD_TYPE_ELEMENT);
|
||||
marshal_string (marshaled, strings, tree->data);
|
||||
marshal_uint32 (marshaled, tree->n_attributes);
|
||||
for (i = 0; i < tree->n_attributes; i++)
|
||||
marshal_uint32 (marshaled, element->name->offset);
|
||||
marshal_uint32 (marshaled, element->n_attributes);
|
||||
|
||||
attr_names = &element->attributes[0];
|
||||
attr_values = &element->attributes[element->n_attributes];
|
||||
for (i = 0; i < element->n_attributes; i++)
|
||||
{
|
||||
marshal_string (marshaled, strings, tree->attributes[i]);
|
||||
marshal_string (marshaled, strings, tree->values[i]);
|
||||
marshal_uint32 (marshaled, attr_names[i]->offset);
|
||||
marshal_uint32 (marshaled, attr_values[i]->offset);
|
||||
}
|
||||
for (l = g_list_last (tree->children); l != NULL; l = l->prev)
|
||||
marshal_tree (marshaled, strings, l->data);
|
||||
|
||||
for (l = element->children.head; l != NULL; l = l->next)
|
||||
marshal_tree (marshaled, l->data);
|
||||
|
||||
marshal_uint32 (marshaled, RECORD_TYPE_END_ELEMENT);
|
||||
break;
|
||||
case RECORD_TYPE_TEXT:
|
||||
text = (RecordDataText *)node;
|
||||
marshal_uint32 (marshaled, RECORD_TYPE_TEXT);
|
||||
marshal_string (marshaled, strings, tree->data);
|
||||
marshal_uint32 (marshaled, text->string->text_offset);
|
||||
break;
|
||||
case RECORD_TYPE_END_ELEMENT:
|
||||
default:
|
||||
@@ -295,6 +442,17 @@ marshal_tree (GString *marshaled,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_root (GString *marshaled,
|
||||
RecordDataNode *node)
|
||||
{
|
||||
GList *l;
|
||||
RecordDataElement *element = (RecordDataElement *)node;
|
||||
|
||||
for (l = element->children.head; l != NULL; l = l->next)
|
||||
marshal_tree (marshaled, l->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_buildable_parser_precompile:
|
||||
* @text: chunk of text to parse
|
||||
@@ -313,20 +471,22 @@ _gtk_buildable_parser_precompile (const char *text,
|
||||
{
|
||||
GMarkupParseContext *ctx;
|
||||
RecordData data = { 0 };
|
||||
GList *string_table, *l;
|
||||
GList *l;
|
||||
GString *marshaled;
|
||||
int offset;
|
||||
|
||||
data.strings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)record_data_string_free);
|
||||
data.root = record_data_tree_new (NULL, RECORD_TYPE_ELEMENT, NULL);
|
||||
data.strings = g_hash_table_new (record_data_string_hash, record_data_string_equal);
|
||||
data.chunks = g_string_chunk_new (512);
|
||||
data.root = record_data_element_new (NULL, NULL, 0);
|
||||
data.current = data.root;
|
||||
|
||||
ctx = g_markup_parse_context_new (&record_parser, G_MARKUP_TREAT_CDATA_AS_TEXT,
|
||||
&data, NULL);
|
||||
ctx = g_markup_parse_context_new (&record_parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &data, NULL);
|
||||
|
||||
if (!g_markup_parse_context_parse (ctx, text, text_len, error))
|
||||
if (!g_markup_parse_context_parse (ctx, text, text_len, error) ||
|
||||
!g_markup_parse_context_end_parse (ctx, error))
|
||||
{
|
||||
record_data_tree_free (data.root);
|
||||
record_data_node_free (&data.root->base);
|
||||
g_string_chunk_free (data.chunks);
|
||||
g_hash_table_destroy (data.strings);
|
||||
g_markup_parse_context_free (ctx);
|
||||
return NULL;
|
||||
@@ -334,34 +494,45 @@ _gtk_buildable_parser_precompile (const char *text,
|
||||
|
||||
g_markup_parse_context_free (ctx);
|
||||
|
||||
string_table = g_hash_table_get_values (data.strings);
|
||||
|
||||
string_table = g_list_sort (string_table, compare_string);
|
||||
g_queue_sort (&data.string_list, record_data_string_compare, NULL);
|
||||
|
||||
offset = 0;
|
||||
for (l = string_table; l != NULL; l = l->next)
|
||||
for (l = data.string_list.head; l != NULL; l = l->next)
|
||||
{
|
||||
RecordDataString *s = l->data;
|
||||
|
||||
if (s->include_len)
|
||||
{
|
||||
s->text_offset = offset;
|
||||
offset += marshal_uint32_len (s->len);
|
||||
}
|
||||
|
||||
s->offset = offset;
|
||||
offset += strlen (s->string) + 1;
|
||||
offset += s->len + 1;
|
||||
}
|
||||
|
||||
marshaled = g_string_new ("");
|
||||
marshaled = g_string_sized_new (4 + offset + 32);
|
||||
/* Magic marker */
|
||||
g_string_append_len (marshaled, "GBU\0", 4);
|
||||
marshal_uint32 (marshaled, offset);
|
||||
|
||||
for (l = string_table; l != NULL; l = l->next)
|
||||
for (l = data.string_list.head; l != NULL; l = l->next)
|
||||
{
|
||||
RecordDataString *s = l->data;
|
||||
g_string_append_len (marshaled, s->string, strlen (s->string) + 1);
|
||||
|
||||
if (s->include_len)
|
||||
marshal_uint32 (marshaled, s->len);
|
||||
|
||||
g_string_append_len (marshaled, s->string, s->len + 1);
|
||||
}
|
||||
|
||||
g_list_free (string_table);
|
||||
marshal_root (marshaled, &data.root->base);
|
||||
|
||||
marshal_tree (marshaled, data.strings, data.root);
|
||||
|
||||
record_data_tree_free (data.root);
|
||||
g_slice_free_chain (RecordDataString,
|
||||
(RecordDataString *)data.string_list.head,
|
||||
link.next);
|
||||
record_data_node_free (&data.root->base);
|
||||
g_string_chunk_free (data.chunks);
|
||||
g_hash_table_destroy (data.strings);
|
||||
|
||||
return g_string_free_to_bytes (marshaled);
|
||||
@@ -412,6 +583,18 @@ demarshal_string (const char **tree,
|
||||
return strings + offset;
|
||||
}
|
||||
|
||||
static const char *
|
||||
demarshal_text (const char **tree,
|
||||
const char *strings,
|
||||
guint32 *len)
|
||||
{
|
||||
guint32 offset = demarshal_uint32 (tree);
|
||||
const char *str = strings + offset;
|
||||
|
||||
*len = demarshal_uint32 (&str);
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
propagate_error (GtkBuildableParseContext *context,
|
||||
GError **dest,
|
||||
@@ -489,14 +672,15 @@ replay_text (GtkBuildableParseContext *context,
|
||||
const char *strings,
|
||||
GError **error)
|
||||
{
|
||||
guint32 len;
|
||||
const char *text;
|
||||
GError *tmp_error = NULL;
|
||||
|
||||
text = demarshal_string (tree, strings);
|
||||
text = demarshal_text (tree, strings, &len);
|
||||
|
||||
(*context->internal_callbacks->text) (NULL,
|
||||
text,
|
||||
strlen (text),
|
||||
len,
|
||||
context,
|
||||
&tmp_error);
|
||||
|
||||
|
||||
@@ -296,6 +296,7 @@ gtk_color_button_init (GtkColorButton *button)
|
||||
"accessible-role", GTK_ACCESSIBLE_ROLE_IMG,
|
||||
"selectable", FALSE,
|
||||
"has-menu", FALSE,
|
||||
"can-drag", FALSE,
|
||||
NULL);
|
||||
gtk_widget_set_can_focus (button->swatch, FALSE);
|
||||
gtk_widget_remove_css_class (button->swatch, "activatable");
|
||||
|
||||
+42
-13
@@ -65,6 +65,7 @@ struct _GtkColorSwatch
|
||||
|
||||
GtkWidget *popover;
|
||||
GtkDropTarget *dest;
|
||||
GtkDragSource *source;
|
||||
};
|
||||
|
||||
struct _GtkColorSwatchClass
|
||||
@@ -81,7 +82,8 @@ enum
|
||||
PROP_RGBA,
|
||||
PROP_SELECTABLE,
|
||||
PROP_HAS_MENU,
|
||||
PROP_CAN_DROP
|
||||
PROP_CAN_DROP,
|
||||
PROP_CAN_DRAG
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
|
||||
@@ -429,6 +431,9 @@ swatch_get_property (GObject *object,
|
||||
case PROP_CAN_DROP:
|
||||
g_value_set_boolean (value, swatch->dest != NULL);
|
||||
break;
|
||||
case PROP_CAN_DRAG:
|
||||
g_value_set_boolean (value, swatch->source != NULL);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -457,6 +462,9 @@ swatch_set_property (GObject *object,
|
||||
case PROP_CAN_DROP:
|
||||
gtk_color_swatch_set_can_drop (swatch, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_CAN_DRAG:
|
||||
gtk_color_swatch_set_can_drag (swatch, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -470,7 +478,7 @@ swatch_finalize (GObject *object)
|
||||
|
||||
g_free (swatch->icon);
|
||||
gtk_widget_unparent (swatch->overlay_widget);
|
||||
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -512,11 +520,14 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
|
||||
g_object_class_install_property (object_class, PROP_CAN_DROP,
|
||||
g_param_spec_boolean ("can-drop", P_("Can Drop"), P_("Whether the swatch should accept drops"),
|
||||
FALSE, GTK_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class, PROP_CAN_DRAG,
|
||||
g_param_spec_boolean ("can-drag", P_("Can Drag"), P_("Whether the swatch should allow drags"),
|
||||
TRUE, GTK_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GtkColorSwatch|menu.popup:
|
||||
*
|
||||
* Opens the context menu.
|
||||
* Opens the context menu.
|
||||
*/
|
||||
gtk_widget_class_install_action (widget_class, "menu.popup", NULL, swatch_popup_menu);
|
||||
|
||||
@@ -568,6 +579,8 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
|
||||
G_CALLBACK (key_controller_key_pressed), swatch);
|
||||
gtk_widget_add_controller (GTK_WIDGET (swatch), controller);
|
||||
|
||||
gtk_color_swatch_set_can_drag (swatch, TRUE);
|
||||
|
||||
gtk_widget_add_css_class (GTK_WIDGET (swatch), "activatable");
|
||||
|
||||
swatch->overlay_widget = g_object_new (GTK_TYPE_IMAGE,
|
||||
@@ -598,18 +611,10 @@ void
|
||||
gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
if (!swatch->has_color)
|
||||
{
|
||||
GtkDragSource *source;
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (gtk_color_swatch_drag_prepare), swatch);
|
||||
|
||||
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (source));
|
||||
}
|
||||
|
||||
swatch->has_color = TRUE;
|
||||
swatch->color = *color;
|
||||
if (swatch->source)
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (swatch->source), GTK_PHASE_CAPTURE);
|
||||
|
||||
if (INTENSITY (swatch->color.red, swatch->color.green, swatch->color.blue) > 0.5)
|
||||
{
|
||||
@@ -681,6 +686,30 @@ gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
|
||||
g_object_notify (G_OBJECT (swatch), "can-drop");
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_can_drag (GtkColorSwatch *swatch,
|
||||
gboolean can_drag)
|
||||
{
|
||||
if (can_drag == (swatch->source != NULL))
|
||||
return;
|
||||
|
||||
if (can_drag && !swatch->source)
|
||||
{
|
||||
swatch->source = gtk_drag_source_new ();
|
||||
g_signal_connect (swatch->source, "prepare", G_CALLBACK (gtk_color_swatch_drag_prepare), swatch);
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (swatch->source),
|
||||
swatch->has_color ? GTK_PHASE_CAPTURE : GTK_PHASE_NONE);
|
||||
gtk_widget_add_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->source));
|
||||
}
|
||||
if (!can_drag && swatch->source)
|
||||
{
|
||||
gtk_widget_remove_controller (GTK_WIDGET (swatch), GTK_EVENT_CONTROLLER (swatch->source));
|
||||
swatch->source = NULL;
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (swatch), "can-drag");
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
|
||||
gboolean use_alpha)
|
||||
|
||||
@@ -42,6 +42,8 @@ void gtk_color_swatch_set_hsva (GtkColorSwatch *swatch,
|
||||
double a);
|
||||
void gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
|
||||
gboolean can_drop);
|
||||
void gtk_color_swatch_set_can_drag (GtkColorSwatch *swatch,
|
||||
gboolean can_drag);
|
||||
void gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
|
||||
const char *icon);
|
||||
void gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
|
||||
|
||||
@@ -942,7 +942,7 @@ _gtk_css_transform_value_parse (GtkCssParser *parser)
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GtkCssTransform transform;
|
||||
GtkCssTransform transform = { 0, };
|
||||
|
||||
if (gtk_css_parser_has_function (parser, "matrix"))
|
||||
{
|
||||
|
||||
+188
-66
@@ -65,6 +65,25 @@ enum {
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
typedef struct _QueuedEvent QueuedEvent;
|
||||
struct _QueuedEvent
|
||||
{
|
||||
GtkDirectoryList *list;
|
||||
GFile *file;
|
||||
GFileInfo *info;
|
||||
GFileMonitorEvent event;
|
||||
};
|
||||
|
||||
static void
|
||||
free_queued_event (gpointer data)
|
||||
{
|
||||
QueuedEvent *event = data;
|
||||
|
||||
g_clear_object (&event->file);
|
||||
g_clear_object (&event->info);
|
||||
g_free (event);
|
||||
}
|
||||
|
||||
struct _GtkDirectoryList
|
||||
{
|
||||
GObject parent_instance;
|
||||
@@ -78,6 +97,7 @@ struct _GtkDirectoryList
|
||||
GCancellable *cancellable;
|
||||
GError *error; /* Error while loading */
|
||||
GSequence *items; /* Use GPtrArray or GListStore here? */
|
||||
GQueue events;
|
||||
};
|
||||
|
||||
struct _GtkDirectoryListClass
|
||||
@@ -140,7 +160,6 @@ gtk_directory_list_set_property (GObject *object,
|
||||
case PROP_ATTRIBUTES:
|
||||
gtk_directory_list_set_attributes (self, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_FILE:
|
||||
gtk_directory_list_set_file (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -238,6 +257,9 @@ gtk_directory_list_dispose (GObject *object)
|
||||
g_clear_error (&self->error);
|
||||
g_clear_pointer (&self->items, g_sequence_free);
|
||||
|
||||
g_queue_foreach (&self->events, (GFunc) free_queued_event, NULL);
|
||||
g_queue_clear (&self->events);
|
||||
|
||||
G_OBJECT_CLASS (gtk_directory_list_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@@ -331,6 +353,7 @@ gtk_directory_list_init (GtkDirectoryList *self)
|
||||
self->items = g_sequence_new (g_object_unref);
|
||||
self->io_priority = G_PRIORITY_DEFAULT;
|
||||
self->monitored = TRUE;
|
||||
g_queue_init (&self->events);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,24 +542,123 @@ gtk_directory_list_start_loading (GtkDirectoryList *self)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
|
||||
}
|
||||
|
||||
static GSequenceIter *
|
||||
find_file (GSequence *sequence,
|
||||
GFile *file)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (sequence);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
GFileInfo *item = G_FILE_INFO (g_sequence_get (iter));
|
||||
GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
|
||||
|
||||
if (g_file_equal (f, file))
|
||||
return iter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_event (QueuedEvent *event)
|
||||
{
|
||||
GtkDirectoryList *self = event->list;
|
||||
GFile *file = event->file;
|
||||
GFileInfo *info = event->info;
|
||||
GSequenceIter *iter;
|
||||
unsigned int position;
|
||||
|
||||
switch ((int)event->event)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
iter = find_file (self->items, file);
|
||||
if (iter)
|
||||
{
|
||||
position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_set (iter, g_object_ref (info));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, g_object_ref (info));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
iter = find_file (self->items, file);
|
||||
if (iter)
|
||||
{
|
||||
position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_remove (iter);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
iter = find_file (self->items, file);
|
||||
if (iter)
|
||||
{
|
||||
position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_set (iter, g_object_ref (info));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_events (GtkDirectoryList *self)
|
||||
{
|
||||
QueuedEvent *event;
|
||||
|
||||
do
|
||||
{
|
||||
event = g_queue_peek_tail (&self->events);
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
if (!handle_event (event))
|
||||
return;
|
||||
|
||||
event = g_queue_pop_tail (&self->events);
|
||||
free_queued_event (event);
|
||||
}
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
got_new_file_info_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GFile *file = G_FILE (source);
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
GFileInfo *info;
|
||||
guint position;
|
||||
QueuedEvent *event = data;
|
||||
GtkDirectoryList *self = event->list;
|
||||
GFile *file = event->file;
|
||||
|
||||
info = g_file_query_info_finish (file, res, NULL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
position = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, info);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
event->info = g_file_query_info_finish (file, res, NULL);
|
||||
handle_events (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -544,53 +666,12 @@ got_existing_file_info_cb (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GFile *file = G_FILE (source);
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
GFileInfo *info;
|
||||
GSequenceIter *iter;
|
||||
QueuedEvent *event = data;
|
||||
GtkDirectoryList *self = event->list;
|
||||
GFile *file = event->file;
|
||||
|
||||
info = g_file_query_info_finish (file, res, NULL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (self->items);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
GFileInfo *item = g_sequence_get (iter);
|
||||
GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
|
||||
if (g_file_equal (f, file))
|
||||
{
|
||||
guint position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_set (iter, g_object_ref (info));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_directory_list_remove_file (GtkDirectoryList *self,
|
||||
GFile *file)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
for (iter = g_sequence_get_begin_iter (self->items);
|
||||
!g_sequence_iter_is_end (iter);
|
||||
iter = g_sequence_iter_next (iter))
|
||||
{
|
||||
GFileInfo *item = g_sequence_get (iter);
|
||||
GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
|
||||
if (g_file_equal (f, file))
|
||||
{
|
||||
guint position = g_sequence_iter_get_position (iter);
|
||||
g_sequence_remove (iter);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
event->info = g_file_query_info_finish (file, res, NULL);
|
||||
handle_events (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -601,30 +682,74 @@ directory_changed (GFileMonitor *monitor,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
|
||||
QueuedEvent *ev;
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
ev = g_new0 (QueuedEvent, 1);
|
||||
ev->list = self;
|
||||
ev->event = event;
|
||||
ev->file = g_object_ref (file);
|
||||
g_queue_push_head (&self->events, ev);
|
||||
|
||||
g_file_query_info_async (file,
|
||||
self->attributes,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
self->io_priority,
|
||||
self->cancellable,
|
||||
got_new_file_info_cb,
|
||||
self);
|
||||
ev);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
gtk_directory_list_remove_file (self, file);
|
||||
ev = g_new0 (QueuedEvent, 1);
|
||||
ev->list = self;
|
||||
ev->event = event;
|
||||
ev->file = g_object_ref (file);
|
||||
g_queue_push_head (&self->events, ev);
|
||||
|
||||
handle_events (self);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
|
||||
ev = g_new0 (QueuedEvent, 1);
|
||||
ev->list = self;
|
||||
ev->event = event;
|
||||
ev->file = g_object_ref (file);
|
||||
g_queue_push_head (&self->events, ev);
|
||||
|
||||
g_file_query_info_async (file,
|
||||
self->attributes,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
self->io_priority,
|
||||
self->cancellable,
|
||||
got_existing_file_info_cb,
|
||||
self);
|
||||
ev);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_RENAMED:
|
||||
ev = g_new0 (QueuedEvent, 1);
|
||||
ev->list = self;
|
||||
ev->event = G_FILE_MONITOR_EVENT_DELETED;
|
||||
ev->file = g_object_ref (file);
|
||||
g_queue_push_head (&self->events, ev);
|
||||
|
||||
ev = g_new0 (QueuedEvent, 1);
|
||||
ev->list = self;
|
||||
ev->event = G_FILE_MONITOR_EVENT_CREATED;
|
||||
ev->file = g_object_ref (other_file);
|
||||
g_queue_push_head (&self->events, ev);
|
||||
|
||||
g_file_query_info_async (other_file,
|
||||
self->attributes,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
self->io_priority,
|
||||
self->cancellable,
|
||||
got_existing_file_info_cb,
|
||||
ev);
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_CHANGED:
|
||||
@@ -632,9 +757,6 @@ directory_changed (GFileMonitor *monitor,
|
||||
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
|
||||
case G_FILE_MONITOR_EVENT_UNMOUNTED:
|
||||
case G_FILE_MONITOR_EVENT_MOVED:
|
||||
case G_FILE_MONITOR_EVENT_RENAMED:
|
||||
case G_FILE_MONITOR_EVENT_MOVED_IN:
|
||||
case G_FILE_MONITOR_EVENT_MOVED_OUT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -644,7 +766,7 @@ static void
|
||||
gtk_directory_list_start_monitoring (GtkDirectoryList *self)
|
||||
{
|
||||
g_assert (self->monitor == NULL);
|
||||
self->monitor = g_file_monitor_directory (self->file, G_FILE_MONITOR_NONE, NULL, NULL);
|
||||
self->monitor = g_file_monitor_directory (self->file, G_FILE_MONITOR_WATCH_MOVES, NULL, NULL);
|
||||
g_signal_connect (self->monitor, "changed", G_CALLBACK (directory_changed), self);
|
||||
}
|
||||
|
||||
|
||||
+25
-1
@@ -386,6 +386,7 @@ gtk_drag_icon_class_init (GtkDragIconClass *klass)
|
||||
static void
|
||||
gtk_drag_icon_init (GtkDragIcon *self)
|
||||
{
|
||||
gtk_widget_set_can_target (GTK_WIDGET (self), FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,15 +532,38 @@ gtk_drag_icon_create_widget_for_value (const GValue *value)
|
||||
{
|
||||
return gtk_label_new (g_value_get_string (value));
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE))
|
||||
{
|
||||
GtkWidget *image;
|
||||
|
||||
image = gtk_image_new_from_paintable (g_value_get_object (value));
|
||||
gtk_widget_add_css_class (image, "large-icons");
|
||||
|
||||
return image;
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
|
||||
{
|
||||
GtkWidget *swatch;
|
||||
|
||||
swatch = gtk_color_swatch_new ();
|
||||
gtk_color_swatch_set_can_drag (GTK_COLOR_SWATCH (swatch), FALSE);
|
||||
gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (swatch), FALSE);
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (swatch), g_value_get_boxed (value));
|
||||
|
||||
return swatch;
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, G_TYPE_FILE))
|
||||
{
|
||||
GFileInfo *info;
|
||||
GtkWidget *image;
|
||||
|
||||
info = g_file_query_info (G_FILE (g_value_get_object (value)), "standard::icon", 0, NULL, NULL);
|
||||
image = gtk_image_new_from_gicon (g_file_info_get_icon (info));
|
||||
gtk_widget_add_css_class (image, "large-icons");
|
||||
g_object_unref (info);
|
||||
|
||||
return image;
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, GTK_TYPE_TEXT_BUFFER))
|
||||
{
|
||||
GtkTextBuffer *buffer = g_value_get_object (value);
|
||||
@@ -568,7 +592,7 @@ gtk_drag_icon_create_widget_for_value (const GValue *value)
|
||||
node = gsk_value_get_render_node (value);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
gsk_render_node_get_bounds (node, &bounds);
|
||||
paintable = gtk_render_node_paintable_new (node, &bounds);
|
||||
image = gtk_image_new_from_paintable (paintable);
|
||||
|
||||
+9
-8
@@ -80,6 +80,7 @@
|
||||
* GDK_TYPE_PIXBUF,
|
||||
* }, 2);
|
||||
*
|
||||
* g_signal_connect (target, "drop", G_CALLBACK (on_drop), self);
|
||||
* gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (target));
|
||||
* }
|
||||
* ```
|
||||
@@ -303,7 +304,7 @@ gtk_drop_target_load (GtkDropTarget *self)
|
||||
|
||||
self->cancellable = g_cancellable_new ();
|
||||
|
||||
gdk_drop_read_value_async (self->drop,
|
||||
gdk_drop_read_value_async (self->drop,
|
||||
type,
|
||||
G_PRIORITY_DEFAULT,
|
||||
self->cancellable,
|
||||
@@ -355,13 +356,13 @@ make_action_unique (GdkDragAction actions)
|
||||
|
||||
if (actions & GDK_ACTION_MOVE)
|
||||
return GDK_ACTION_MOVE;
|
||||
|
||||
|
||||
if (actions & GDK_ACTION_LINK)
|
||||
return GDK_ACTION_LINK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static GdkDragAction
|
||||
gtk_drop_target_enter (GtkDropTarget *self,
|
||||
double x,
|
||||
@@ -370,7 +371,7 @@ gtk_drop_target_enter (GtkDropTarget *self,
|
||||
return make_action_unique (self->actions & gdk_drop_get_actions (self->drop));
|
||||
}
|
||||
|
||||
static GdkDragAction
|
||||
static GdkDragAction
|
||||
gtk_drop_target_motion (GtkDropTarget *self,
|
||||
double x,
|
||||
double y)
|
||||
@@ -900,7 +901,7 @@ GdkContentFormats *
|
||||
gtk_drop_target_get_formats (GtkDropTarget *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_DROP_TARGET (self), NULL);
|
||||
|
||||
|
||||
return self->formats;
|
||||
}
|
||||
|
||||
@@ -929,7 +930,7 @@ gtk_drop_target_set_gtypes (GtkDropTarget *self,
|
||||
builder = gdk_content_formats_builder_new ();
|
||||
for (i = 0; i < n_types; i++)
|
||||
gdk_content_formats_builder_add_gtype (builder, types[i]);
|
||||
|
||||
|
||||
self->formats = gdk_content_formats_builder_free_to_formats (builder);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMATS]);
|
||||
@@ -970,7 +971,7 @@ gtk_drop_target_set_actions (GtkDropTarget *self,
|
||||
GdkDragAction actions)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DROP_TARGET (self));
|
||||
|
||||
|
||||
if (self->actions == actions)
|
||||
return;
|
||||
|
||||
@@ -1007,7 +1008,7 @@ gtk_drop_target_set_preload (GtkDropTarget *self,
|
||||
gboolean preload)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_DROP_TARGET (self));
|
||||
|
||||
|
||||
if (self->preload == preload)
|
||||
return;
|
||||
|
||||
|
||||
@@ -285,6 +285,31 @@ typedef enum
|
||||
GTK_MOVEMENT_HORIZONTAL_PAGES
|
||||
} GtkMovementStep;
|
||||
|
||||
/**
|
||||
* GtkNaturalWrapMode:
|
||||
* @GTK_NATURAL_WRAP_INHERIT: Inherit the minimum size request.
|
||||
* In particular, this should be used with %PANGO_WRAP_CHAR.
|
||||
* @GTK_NATURAL_WRAP_NONE: Try not to wrap the text. This mode is the
|
||||
* closest to GTK3's behavior but can lead to a wide label leaving
|
||||
* lots of empty space below the text.
|
||||
* @GTK_NATURAL_WRAP_WORD: Attempt to wrap at word boundaries. This
|
||||
* is useful in particular when using %PANGO_WRAP_WORD_CHAR as the
|
||||
* wrap mode.
|
||||
*
|
||||
* Options for selecting a different wrap mode for natural size
|
||||
* requests.
|
||||
*
|
||||
* See for example the [property@Gtk.Label:natural-wrap-mode] property.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GTK_NATURAL_WRAP_INHERIT,
|
||||
GTK_NATURAL_WRAP_NONE,
|
||||
GTK_NATURAL_WRAP_WORD
|
||||
} GtkNaturalWrapMode;
|
||||
|
||||
/**
|
||||
* GtkScrollStep:
|
||||
* @GTK_SCROLL_STEPS: Scroll in steps.
|
||||
|
||||
+2
-3
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
@@ -124,7 +123,7 @@
|
||||
*
|
||||
* `GtkBuilder` has support for creating expressions. The syntax here can be used where
|
||||
* a `GtkExpression` object is needed like in a `<property>` tag for an expression
|
||||
* property, or in a `<binding>` tag to bind a property to an expression.
|
||||
* property, or in a `<binding name="property">` tag to bind a property to an expression.
|
||||
*
|
||||
* To create an property expression, use the `<lookup>` element. It can have a `type`
|
||||
* attribute to specify the object type, and a `name` attribute to specify the property
|
||||
@@ -1372,7 +1371,7 @@ gtk_property_expression_new_for_pspec (GtkExpression *expression,
|
||||
* Gets the expression specifying the object of
|
||||
* a property expression.
|
||||
*
|
||||
* Returns: (transfer none): the object expression
|
||||
* Returns: (transfer none) (nullable): the object expression
|
||||
*/
|
||||
GtkExpression *
|
||||
gtk_property_expression_get_expression (GtkExpression *expression)
|
||||
|
||||
@@ -50,6 +50,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
GtkExpression * gtk_expression_ref (GtkExpression *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_expression_unref (GtkExpression *self);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkExpression, gtk_expression_unref)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_expression_get_value_type (GtkExpression *self);
|
||||
|
||||
@@ -523,7 +523,7 @@ gtk_file_chooser_set_file (GtkFileChooser *chooser,
|
||||
* If the file chooser is in folder mode, this function returns
|
||||
* the selected folder.
|
||||
*
|
||||
* Returns: (transfer full): a selected `GFile`. You own the
|
||||
* Returns: (transfer full) (nullable): a selected `GFile`. You own the
|
||||
* returned file; use g_object_unref() to release it.
|
||||
*/
|
||||
GFile *
|
||||
@@ -794,7 +794,7 @@ gtk_file_chooser_set_choice (GtkFileChooser *chooser,
|
||||
*
|
||||
* Gets the currently selected option in the 'choice' with the given ID.
|
||||
*
|
||||
* Returns: the ID of the currently selected option
|
||||
* Returns: (nullable): the ID of the currently selected option
|
||||
*/
|
||||
const char *
|
||||
gtk_file_chooser_get_choice (GtkFileChooser *chooser,
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "gtktogglebutton.h"
|
||||
#include "gtkheaderbar.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkfilefilterprivate.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
@@ -50,6 +51,9 @@
|
||||
|
||||
typedef struct {
|
||||
GtkFileChooserNative *self;
|
||||
|
||||
GtkWidget *grab_widget;
|
||||
|
||||
IFileDialogEvents *events;
|
||||
|
||||
HWND parent;
|
||||
@@ -318,6 +322,12 @@ filechooser_win32_thread_data_free (FilechooserWin32ThreadData *data)
|
||||
if (data->events)
|
||||
IFileDialogEvents_Release (data->events);
|
||||
|
||||
if (data->grab_widget)
|
||||
{
|
||||
gtk_grab_remove (data->grab_widget);
|
||||
g_object_unref (data->grab_widget);
|
||||
}
|
||||
|
||||
g_clear_object (&data->current_folder);
|
||||
g_clear_object (&data->current_file);
|
||||
g_free (data->current_name);
|
||||
@@ -969,6 +979,12 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (data->modal)
|
||||
{
|
||||
data->grab_widget = g_object_ref_sink (gtk_label_new (""));
|
||||
gtk_grab_add (GTK_WIDGET (data->grab_widget));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ gtk_flatten_list_model_get_model (GtkFlattenListModel *self)
|
||||
*
|
||||
* Returns the model containing the item at the given position.
|
||||
*
|
||||
* Returns: (transfer none): the model containing the item at @position
|
||||
* Returns: (transfer none) (nullable): the model containing the item at @position
|
||||
*/
|
||||
GListModel *
|
||||
gtk_flatten_list_model_get_model_for_item (GtkFlattenListModel *self,
|
||||
|
||||
@@ -433,6 +433,8 @@ gtk_font_button_font_chooser_set_font_map (GtkFontChooser *chooser,
|
||||
|
||||
context = gtk_widget_get_pango_context (font_button->font_label);
|
||||
pango_context_set_font_map (context, font_map);
|
||||
if (font_button->font_dialog)
|
||||
gtk_font_chooser_set_font_map (GTK_FONT_CHOOSER (font_button->font_dialog), font_map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+233
-199
@@ -64,12 +64,8 @@
|
||||
#include "gtkstringsorter.h"
|
||||
|
||||
#include <hb-ot.h>
|
||||
#if defined(HAVE_PANGOFT) && defined(HAVE_HARFBUZZ)
|
||||
#include <pango/pangofc-font.h>
|
||||
#endif
|
||||
|
||||
#include "language-names.h"
|
||||
#include "script-names.h"
|
||||
#include "open-type-layout.h"
|
||||
|
||||
/**
|
||||
@@ -155,6 +151,8 @@ struct _GtkFontChooserWidget
|
||||
GList *feature_items;
|
||||
|
||||
GAction *tweak_action;
|
||||
|
||||
hb_map_t *glyphmap;
|
||||
};
|
||||
|
||||
struct _GtkFontChooserWidgetClass
|
||||
@@ -362,7 +360,6 @@ user_filter_cb (gpointer item,
|
||||
!pango_font_family_is_monospace (family))
|
||||
return FALSE;
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
if (self->filter_by_language &&
|
||||
self->filter_language)
|
||||
{
|
||||
@@ -370,6 +367,7 @@ user_filter_cb (gpointer item,
|
||||
PangoContext *context;
|
||||
PangoFont *font;
|
||||
gboolean ret;
|
||||
PangoLanguage **langs;
|
||||
|
||||
desc = pango_font_face_describe (face);
|
||||
pango_font_description_set_size (desc, 20);
|
||||
@@ -377,27 +375,19 @@ user_filter_cb (gpointer item,
|
||||
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
|
||||
font = pango_context_load_font (context, desc);
|
||||
|
||||
ret = TRUE;
|
||||
ret = FALSE;
|
||||
|
||||
if (PANGO_IS_FC_FONT (font))
|
||||
langs = pango_font_get_languages (font);
|
||||
if (langs)
|
||||
{
|
||||
PangoLanguage **langs;
|
||||
int i;
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
langs = pango_fc_font_get_languages (PANGO_FC_FONT (font));
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
if (langs)
|
||||
for (i = 0; langs[i]; i++)
|
||||
{
|
||||
if (langs[i] == self->filter_language)
|
||||
{
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; langs[i]; i++)
|
||||
{
|
||||
if (langs[i] == self->filter_language)
|
||||
{
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (font);
|
||||
@@ -405,7 +395,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -549,10 +538,16 @@ maybe_update_preview_text (GtkFontChooserWidget *self,
|
||||
PangoFontFace *face,
|
||||
PangoFontDescription *desc)
|
||||
{
|
||||
#if defined(HAVE_PANGOFT) && defined(HAVE_HARFBUZZ)
|
||||
PangoContext *context;
|
||||
PangoFont *font;
|
||||
const char *sample;
|
||||
PangoLanguage **languages;
|
||||
GHashTable *langs = NULL;
|
||||
PangoLanguage *default_lang;
|
||||
PangoLanguage *alt_default = NULL;
|
||||
PangoLanguage *lang = NULL;
|
||||
int i;
|
||||
const char *p;
|
||||
|
||||
/* If the user has typed text into the entry, we don't touch it */
|
||||
if (self->preview_text_set)
|
||||
@@ -576,88 +571,77 @@ maybe_update_preview_text (GtkFontChooserWidget *self,
|
||||
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
|
||||
font = pango_context_load_font (context, desc);
|
||||
|
||||
if (PANGO_IS_FC_FONT (font))
|
||||
default_lang = pango_language_get_default ();
|
||||
p = pango_language_to_string (default_lang);
|
||||
|
||||
/* The default language tends to be of the form en-us.
|
||||
* Since fontconfig languages just have the language part,
|
||||
* and we want to use direct pointer comparisons, we need
|
||||
* an PangoLanguage for the shortened default language.
|
||||
*/
|
||||
if (strchr (p, '-'))
|
||||
{
|
||||
PangoLanguage **languages;
|
||||
GHashTable *langs = NULL;
|
||||
PangoLanguage *default_lang;
|
||||
PangoLanguage *alt_default = NULL;
|
||||
PangoLanguage *lang = NULL;
|
||||
int i;
|
||||
const char *p;
|
||||
char q[10];
|
||||
for (i = 0; p[i] != '-' && i < 9; i++)
|
||||
q[i] = p[i];
|
||||
q[i] = '\0';
|
||||
alt_default = pango_language_from_string (q);
|
||||
}
|
||||
|
||||
default_lang = pango_language_get_default ();
|
||||
p = pango_language_to_string (default_lang);
|
||||
languages = pango_font_get_languages (font);
|
||||
|
||||
/* The default language tends to be of the form en-us.
|
||||
* Since fontconfig languages just have the language part,
|
||||
* and we want to use direct pointer comparisons, we need
|
||||
* an PangoLanguage for the shortened default language.
|
||||
*/
|
||||
if (strchr (p, '-'))
|
||||
{
|
||||
char q[10];
|
||||
for (i = 0; p[i] != '-' && i < 9; i++)
|
||||
q[i] = p[i];
|
||||
q[i] = '\0';
|
||||
alt_default = pango_language_from_string (q);
|
||||
}
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
languages = pango_fc_font_get_languages (PANGO_FC_FONT (font));
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
/* If the font supports the default language, just use it. */
|
||||
if (languages)
|
||||
for (i = 0; languages[i]; i++)
|
||||
/* If the font supports the default language, just use it. */
|
||||
if (languages)
|
||||
for (i = 0; languages[i]; i++)
|
||||
{
|
||||
if (languages[i] == default_lang || languages[i] == alt_default)
|
||||
{
|
||||
if (languages[i] == default_lang || languages[i] == alt_default)
|
||||
{
|
||||
lang = default_lang;
|
||||
goto found;
|
||||
}
|
||||
lang = default_lang;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we make a list of representative languages */
|
||||
langs = g_hash_table_new (NULL, NULL);
|
||||
/* Otherwise, we make a list of representative languages */
|
||||
langs = g_hash_table_new (NULL, NULL);
|
||||
|
||||
for (i = 0; languages[i]; i++)
|
||||
if (languages)
|
||||
for (i = 0; languages[i]; i++)
|
||||
{
|
||||
const PangoScript *scripts;
|
||||
int num, j;
|
||||
|
||||
scripts = pango_language_get_scripts (languages[i], &num);
|
||||
for (j = 0; j < num; j++)
|
||||
{
|
||||
lang = pango_script_get_sample_language (scripts[j]);
|
||||
if (lang)
|
||||
g_hash_table_add (langs, lang);
|
||||
}
|
||||
}
|
||||
|
||||
/* ... and compare it to the users default and preferred languages */
|
||||
if (g_hash_table_contains (langs, default_lang) ||
|
||||
g_hash_table_contains (langs, alt_default))
|
||||
{
|
||||
lang = default_lang;
|
||||
}
|
||||
else
|
||||
{
|
||||
PangoLanguage **preferred;
|
||||
|
||||
preferred = pango_language_get_preferred ();
|
||||
if (preferred)
|
||||
{
|
||||
const PangoScript *scripts;
|
||||
int num, j;
|
||||
|
||||
scripts = pango_language_get_scripts (languages[i], &num);
|
||||
for (j = 0; j < num; j++)
|
||||
for (i = 0; preferred[i]; i++)
|
||||
{
|
||||
lang = pango_script_get_sample_language (scripts[j]);
|
||||
if (lang)
|
||||
g_hash_table_add (langs, lang);
|
||||
}
|
||||
}
|
||||
|
||||
/* ... and compare it to the users default and preferred languages */
|
||||
if (g_hash_table_contains (langs, default_lang) ||
|
||||
g_hash_table_contains (langs, alt_default))
|
||||
{
|
||||
lang = default_lang;
|
||||
}
|
||||
else
|
||||
{
|
||||
PangoLanguage **preferred;
|
||||
|
||||
preferred = pango_language_get_preferred ();
|
||||
if (preferred)
|
||||
{
|
||||
for (i = 0; preferred[i]; i++)
|
||||
if (g_hash_table_contains (langs, preferred[i]))
|
||||
{
|
||||
if (g_hash_table_contains (langs, preferred[i]))
|
||||
{
|
||||
lang = preferred[i];
|
||||
break;
|
||||
}
|
||||
lang = preferred[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_unref (langs);
|
||||
|
||||
found:
|
||||
@@ -667,7 +651,6 @@ found:
|
||||
}
|
||||
|
||||
g_object_unref (font);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1027,7 +1010,6 @@ axis_free (gpointer v)
|
||||
g_free (a);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
static void
|
||||
select_added (GListModel *model,
|
||||
guint position,
|
||||
@@ -1051,6 +1033,10 @@ add_languages_from_font (GtkFontChooserWidget *self,
|
||||
PangoFontDescription *desc;
|
||||
PangoFont *font;
|
||||
PangoContext *context;
|
||||
GtkSelectionModel *model = gtk_list_view_get_model (GTK_LIST_VIEW (self->language_list));
|
||||
PangoLanguage *default_lang = pango_language_get_default ();
|
||||
PangoLanguage **langs;
|
||||
int i;
|
||||
|
||||
if (PANGO_IS_FONT_FAMILY (item))
|
||||
face = pango_font_family_get_face (PANGO_FONT_FAMILY (item), NULL);
|
||||
@@ -1066,44 +1052,35 @@ add_languages_from_font (GtkFontChooserWidget *self,
|
||||
context = gtk_widget_get_pango_context (GTK_WIDGET (self));
|
||||
font = pango_context_load_font (context, desc);
|
||||
|
||||
if (PANGO_IS_FC_FONT (font))
|
||||
langs = pango_font_get_languages (font);
|
||||
if (langs)
|
||||
{
|
||||
GtkSelectionModel *model = gtk_list_view_get_model (GTK_LIST_VIEW (self->language_list));
|
||||
PangoLanguage *default_lang = pango_language_get_default ();
|
||||
PangoLanguage **langs;
|
||||
int i;
|
||||
for (i = 0; langs[i]; i++)
|
||||
{
|
||||
if (!g_hash_table_contains (self->language_table, langs[i]))
|
||||
{
|
||||
g_hash_table_add (self->language_table, langs[i]);
|
||||
if (get_language_name (langs[i]))
|
||||
{
|
||||
const char *l = pango_language_to_string (langs[i]);
|
||||
gulong id = 0;
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
langs = pango_fc_font_get_languages (PANGO_FC_FONT (font));
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
if (langs)
|
||||
for (i = 0; langs[i]; i++)
|
||||
{
|
||||
if (!g_hash_table_contains (self->language_table, langs[i]))
|
||||
{
|
||||
g_hash_table_add (self->language_table, langs[i]);
|
||||
if (get_language_name (langs[i]))
|
||||
{
|
||||
const char *l = pango_language_to_string (langs[i]);
|
||||
gulong id = 0;
|
||||
/* Pre-select the default language */
|
||||
if (pango_language_matches (default_lang, l))
|
||||
id = g_signal_connect (model, "items-changed", G_CALLBACK (select_added), NULL);
|
||||
|
||||
/* Pre-select the default language */
|
||||
if (pango_language_matches (default_lang, l))
|
||||
id = g_signal_connect (model, "items-changed", G_CALLBACK (select_added), NULL);
|
||||
gtk_string_list_append (self->languages, l);
|
||||
|
||||
gtk_string_list_append (self->languages, l);
|
||||
|
||||
if (id)
|
||||
g_signal_handler_disconnect (model, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (id)
|
||||
g_signal_handler_disconnect (model, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (font);
|
||||
pango_font_description_free (desc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
gtk_font_chooser_widget_ensure_matching_selection (GtkFontChooserWidget *self);
|
||||
@@ -1130,7 +1107,6 @@ add_to_fontlist (GtkWidget *widget,
|
||||
|
||||
n = gtk_slice_list_model_get_size (model);
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
for (i = n; i < n + 10; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (child_model, i);
|
||||
@@ -1139,7 +1115,6 @@ add_to_fontlist (GtkWidget *widget,
|
||||
add_languages_from_font (self, item);
|
||||
g_object_unref (item);
|
||||
}
|
||||
#endif
|
||||
|
||||
n += 10;
|
||||
|
||||
@@ -1179,7 +1154,6 @@ update_fontlist (GtkFontChooserWidget *self)
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
static void
|
||||
setup_lang_item (GtkSignalListItemFactory *factory,
|
||||
gpointer item,
|
||||
@@ -1269,7 +1243,6 @@ setup_language_list (GtkFontChooserWidget *self)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gtk_font_chooser_widget_init (GtkFontChooserWidget *self)
|
||||
@@ -1310,12 +1283,7 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *self)
|
||||
|
||||
gtk_custom_filter_set_filter_func (self->user_filter, user_filter_cb, self, NULL);
|
||||
|
||||
#ifdef HAVE_PANGOFT
|
||||
setup_language_list (self);
|
||||
#else
|
||||
gtk_widget_hide (GTK_WIDGET (self->language_button));
|
||||
gtk_widget_hide (GTK_WIDGET (self->language_frame));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1501,26 +1469,23 @@ add_font_variations (GtkFontChooserWidget *fontchooser,
|
||||
{
|
||||
GHashTableIter iter;
|
||||
Axis *axis;
|
||||
const char *sep = "";
|
||||
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
|
||||
g_hash_table_iter_init (&iter, fontchooser->axes);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
|
||||
{
|
||||
char tag[5];
|
||||
double value;
|
||||
char buf[128];
|
||||
|
||||
value = gtk_adjustment_get_value (axis->adjustment);
|
||||
|
||||
if (value == axis->default_value)
|
||||
continue;
|
||||
|
||||
tag[0] = (axis->tag >> 24) & 0xff;
|
||||
tag[1] = (axis->tag >> 16) & 0xff;
|
||||
tag[2] = (axis->tag >> 8) & 0xff;
|
||||
tag[3] = (axis->tag >> 0) & 0xff;
|
||||
tag[4] = '\0';
|
||||
g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof(buf), value));
|
||||
sep = ",";
|
||||
hb_variation_to_string (&(hb_variation_t) { axis->tag, value }, buf, sizeof (buf));
|
||||
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, ',');
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,10 +1514,7 @@ adjustment_changed (GtkAdjustment *adjustment,
|
||||
static gboolean
|
||||
should_show_axis (hb_ot_var_axis_info_t *ax)
|
||||
{
|
||||
if (ax->flags & HB_OT_VAR_AXIS_FLAG_HIDDEN)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
return (ax->flags & HB_OT_VAR_AXIS_FLAG_HIDDEN) == 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1566,11 +1528,11 @@ static struct {
|
||||
guint32 tag;
|
||||
const char *name;
|
||||
} axis_names[] = {
|
||||
{ HB_OT_TAG_VAR_AXIS_WIDTH, N_("Width") },
|
||||
{ HB_OT_TAG_VAR_AXIS_WEIGHT, N_("Weight") },
|
||||
{ HB_OT_TAG_VAR_AXIS_ITALIC, N_("Italic") },
|
||||
{ HB_OT_TAG_VAR_AXIS_SLANT, N_("Slant") },
|
||||
{ HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE, N_("Optical Size") },
|
||||
{ HB_OT_TAG_VAR_AXIS_WIDTH, NC_("Font variation axis", "Width") },
|
||||
{ HB_OT_TAG_VAR_AXIS_WEIGHT, NC_("Font variation axis", "Weight") },
|
||||
{ HB_OT_TAG_VAR_AXIS_ITALIC, NC_("Font variation axis", "Italic") },
|
||||
{ HB_OT_TAG_VAR_AXIS_SLANT, NC_("Font variation axis", "Slant") },
|
||||
{ HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE, NC_("Font variation axis", "Optical Size") },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
@@ -1601,7 +1563,7 @@ add_axis (GtkFontChooserWidget *fontchooser,
|
||||
{
|
||||
if (axis_names[i].tag == ax->tag)
|
||||
{
|
||||
name = _(axis_names[i].name);
|
||||
name = g_dpgettext2 (NULL, "Font variation axis", axis_names[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1643,6 +1605,33 @@ add_axis (GtkFontChooserWidget *fontchooser,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if HB_VERSION_ATLEAST (3, 3, 0)
|
||||
static void
|
||||
get_axes_and_values (hb_font_t *font,
|
||||
unsigned int n_axes,
|
||||
hb_ot_var_axis_info_t *axes,
|
||||
float *coords)
|
||||
{
|
||||
const float *dcoords;
|
||||
unsigned int length = n_axes;
|
||||
|
||||
hb_ot_var_get_axis_infos (hb_font_get_face (font), 0, &length, axes);
|
||||
|
||||
dcoords = hb_font_get_var_coords_design (font, &length);
|
||||
if (dcoords)
|
||||
memcpy (coords, dcoords, sizeof (float) * length);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < n_axes; i++)
|
||||
{
|
||||
hb_ot_var_axis_info_t *axis = &axes[i];
|
||||
coords[axis->axis_index] = axis->default_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* FIXME: This doesn't work if the font has an avar table */
|
||||
static float
|
||||
denorm_coord (hb_ot_var_axis_info_t *axis, int coord)
|
||||
@@ -1655,16 +1644,40 @@ denorm_coord (hb_ot_var_axis_info_t *axis, int coord)
|
||||
return axis->default_value + r * (axis->max_value - axis->default_value);
|
||||
}
|
||||
|
||||
static void
|
||||
get_axes_and_values (hb_font_t *font,
|
||||
unsigned int n_axes,
|
||||
hb_ot_var_axis_info_t *axes,
|
||||
float *coords)
|
||||
{
|
||||
const int *ncoords;
|
||||
unsigned int length = n_axes;
|
||||
|
||||
hb_ot_var_get_axis_infos (hb_font_get_face (font), 0, &length, axes);
|
||||
|
||||
ncoords = hb_font_get_var_coords_normalized (font, &length);
|
||||
|
||||
for (int i = 0; i < n_axes; i++)
|
||||
{
|
||||
hb_ot_var_axis_info_t *axis = &axes[i];
|
||||
int idx = axis->axis_index;
|
||||
if (ncoords)
|
||||
coords[idx] = denorm_coord (axis, ncoords[idx]);
|
||||
else
|
||||
coords[idx] = axis->default_value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchooser)
|
||||
{
|
||||
PangoFont *pango_font;
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
const int *coords;
|
||||
unsigned int n_coords;
|
||||
unsigned int n_axes;
|
||||
hb_ot_var_axis_info_t *axes;
|
||||
float *coords;
|
||||
gboolean has_axis = FALSE;
|
||||
int i;
|
||||
|
||||
@@ -1685,24 +1698,17 @@ gtk_font_chooser_widget_update_font_variations (GtkFontChooserWidget *fontchoose
|
||||
if (!hb_ot_var_has_data (hb_face))
|
||||
return FALSE;
|
||||
|
||||
coords = hb_font_get_var_coords_normalized (hb_font, &n_coords);
|
||||
|
||||
n_axes = hb_ot_var_get_axis_count (hb_face);
|
||||
axes = g_new0 (hb_ot_var_axis_info_t, n_axes);
|
||||
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes);
|
||||
axes = g_alloca (sizeof (hb_ot_var_axis_info_t) * n_axes);
|
||||
coords = g_alloca (sizeof (float) * n_axes);
|
||||
get_axes_and_values (hb_font, n_axes, axes, coords);
|
||||
|
||||
for (i = 0; i < n_axes; i++)
|
||||
{
|
||||
float value;
|
||||
if (coords && i < n_coords)
|
||||
value = denorm_coord (&axes[i], coords[i]);
|
||||
else
|
||||
value = axes[i].default_value;
|
||||
if (add_axis (fontchooser, hb_font, &axes[i], value, i + 4))
|
||||
if (add_axis (fontchooser, hb_font, &axes[i], coords[axes[i].axis_index], i + 4))
|
||||
has_axis = TRUE;
|
||||
}
|
||||
|
||||
g_free (axes);
|
||||
g_object_unref (pango_font);
|
||||
|
||||
return has_axis;
|
||||
@@ -1827,11 +1833,12 @@ feat_pressed (GtkGestureClick *gesture,
|
||||
}
|
||||
|
||||
static char *
|
||||
find_affected_text (hb_tag_t feature_tag,
|
||||
hb_font_t *hb_font,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t lang_tag,
|
||||
int max_chars)
|
||||
find_affected_text (GtkFontChooserWidget *fontchooser,
|
||||
hb_tag_t feature_tag,
|
||||
hb_font_t *hb_font,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t lang_tag,
|
||||
int max_chars)
|
||||
{
|
||||
hb_face_t *hb_face;
|
||||
unsigned int script_index = 0;
|
||||
@@ -1881,24 +1888,35 @@ find_affected_text (hb_tag_t feature_tag,
|
||||
glyphs_after,
|
||||
glyphs_output);
|
||||
|
||||
gid = -1;
|
||||
while (hb_set_next (glyphs_input, &gid)) {
|
||||
hb_codepoint_t ch;
|
||||
if (n_chars == max_chars)
|
||||
{
|
||||
g_string_append (chars, "…");
|
||||
break;
|
||||
}
|
||||
for (ch = 0; ch < 0xffff; ch++) {
|
||||
hb_codepoint_t glyph = 0;
|
||||
hb_font_get_nominal_glyph (hb_font, ch, &glyph);
|
||||
if (glyph == gid) {
|
||||
g_string_append_unichar (chars, (gunichar)ch);
|
||||
n_chars++;
|
||||
break;
|
||||
}
|
||||
if (!fontchooser->glyphmap)
|
||||
{
|
||||
fontchooser->glyphmap = hb_map_create ();
|
||||
for (hb_codepoint_t ch = 0; ch < 0xffff; ch++)
|
||||
{
|
||||
hb_codepoint_t glyph = 0;
|
||||
if (hb_font_get_nominal_glyph (hb_font, ch, &glyph) &&
|
||||
!hb_map_has (fontchooser->glyphmap, glyph))
|
||||
hb_map_set (fontchooser->glyphmap, glyph, ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (hb_set_next (glyphs_input, &gid))
|
||||
{
|
||||
hb_codepoint_t ch;
|
||||
|
||||
if (n_chars == max_chars)
|
||||
{
|
||||
g_string_append (chars, "…");
|
||||
break;
|
||||
}
|
||||
ch = hb_map_get (fontchooser->glyphmap, gid);
|
||||
if (ch != HB_MAP_VALUE_INVALID)
|
||||
{
|
||||
g_string_append_unichar (chars, (gunichar)ch);
|
||||
n_chars++;
|
||||
}
|
||||
}
|
||||
|
||||
hb_set_destroy (glyphs_input);
|
||||
}
|
||||
}
|
||||
@@ -1907,7 +1925,8 @@ find_affected_text (hb_tag_t feature_tag,
|
||||
}
|
||||
|
||||
static void
|
||||
update_feature_example (FeatureItem *item,
|
||||
update_feature_example (GtkFontChooserWidget *fontchooser,
|
||||
FeatureItem *item,
|
||||
hb_font_t *hb_font,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t lang_tag,
|
||||
@@ -1962,9 +1981,9 @@ update_feature_example (FeatureItem *item,
|
||||
else if (strcmp (item->name, "frac") == 0)
|
||||
input = g_strdup ("1/2 2/3 7/8");
|
||||
else if (strcmp (item->name, "nalt") == 0)
|
||||
input = find_affected_text (item->tag, hb_font, script_tag, lang_tag, 3);
|
||||
input = find_affected_text (fontchooser, item->tag, hb_font, script_tag, lang_tag, 3);
|
||||
else
|
||||
input = find_affected_text (item->tag, hb_font, script_tag, lang_tag, 10);
|
||||
input = find_affected_text (fontchooser, item->tag, hb_font, script_tag, lang_tag, 10);
|
||||
|
||||
if (input[0] != '\0')
|
||||
{
|
||||
@@ -2244,7 +2263,7 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser)
|
||||
gtk_widget_show (item->top);
|
||||
gtk_widget_show (gtk_widget_get_parent (item->top));
|
||||
|
||||
update_feature_example (item, hb_font, script_tag, lang_tag, fontchooser->font_desc);
|
||||
update_feature_example (fontchooser, item, hb_font, script_tag, lang_tag, fontchooser->font_desc);
|
||||
|
||||
if (GTK_IS_CHECK_BUTTON (item->feat))
|
||||
{
|
||||
@@ -2260,6 +2279,12 @@ gtk_font_chooser_widget_update_font_features (GtkFontChooserWidget *fontchooser)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fontchooser->glyphmap)
|
||||
{
|
||||
hb_map_destroy (fontchooser->glyphmap);
|
||||
fontchooser->glyphmap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (pango_font);
|
||||
@@ -2272,6 +2297,7 @@ update_font_features (GtkFontChooserWidget *fontchooser)
|
||||
{
|
||||
GString *s;
|
||||
GList *l;
|
||||
char buf[128];
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
@@ -2287,17 +2313,24 @@ update_font_features (GtkFontChooserWidget *fontchooser)
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat)) &&
|
||||
strcmp (item->name, "xxxx") != 0)
|
||||
{
|
||||
g_string_append_printf (s, "%s\"%s\" %d", s->len > 0 ? ", " : "", item->name, 1);
|
||||
hb_feature_to_string (&(hb_feature_t) { item->tag, 1, 0, -1 }, buf, sizeof (buf));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, ',');
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
}
|
||||
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
||||
{
|
||||
guint32 value;
|
||||
|
||||
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (item->feat)))
|
||||
continue;
|
||||
|
||||
g_string_append_printf (s, "%s\"%s\" %d",
|
||||
s->len > 0 ? ", " : "", item->name,
|
||||
gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat)));
|
||||
value = gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat));
|
||||
hb_feature_to_string (&(hb_feature_t) { item->tag, value, 0, -1 }, buf, sizeof (buf));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, ',');
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2335,7 +2368,8 @@ gtk_font_chooser_widget_merge_font_desc (GtkFontChooserWidget *fontchooser
|
||||
{
|
||||
double font_size = (double) pango_font_description_get_size (fontchooser->font_desc) / PANGO_SCALE;
|
||||
/* XXX: This clamps, which can cause it to reloop into here, do we need
|
||||
* to block its signal handler? */
|
||||
* to block its signal handler?
|
||||
*/
|
||||
gtk_range_set_value (GTK_RANGE (fontchooser->size_slider), font_size);
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (fontchooser->size_spin), font_size);
|
||||
}
|
||||
|
||||
+5
-1
@@ -833,6 +833,10 @@ gtk_gl_area_class_init (GtkGLAreaClass *klass)
|
||||
*
|
||||
* If set to %TRUE the widget will allocate and enable a depth buffer for the
|
||||
* target framebuffer.
|
||||
*
|
||||
* Setting this property will enable GL's depth testing as a side effect. If
|
||||
* you don't need depth testing, you should call `glDisable(GL_DEPTH_TEST)`
|
||||
* in your `GtkGLArea::render` handler.
|
||||
*/
|
||||
obj_props[PROP_HAS_DEPTH_BUFFER] =
|
||||
g_param_spec_boolean ("has-depth-buffer",
|
||||
@@ -1317,7 +1321,7 @@ gtk_gl_area_set_auto_render (GtkGLArea *area,
|
||||
*
|
||||
* Retrieves the `GdkGLContext` used by @area.
|
||||
*
|
||||
* Returns: (transfer none): the `GdkGLContext`
|
||||
* Returns: (transfer none) (nullable): the `GdkGLContext`
|
||||
*/
|
||||
GdkGLContext *
|
||||
gtk_gl_area_get_context (GtkGLArea *area)
|
||||
|
||||
+9
-2
@@ -4993,8 +4993,15 @@ gtk_icon_view_unselect_path (GtkIconView *icon_view,
|
||||
* want to convert the returned list into a list of `GtkTreeRowReferences`.
|
||||
* To do this, you can use gtk_tree_row_reference_new().
|
||||
*
|
||||
* To free the return value, use:
|
||||
* To free the return value, use `g_list_free_full`:
|
||||
* |[<!-- language="C" -->
|
||||
* GtkWidget *icon_view = gtk_icon_view_new ();
|
||||
* // Use icon_view
|
||||
*
|
||||
* GList *list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (icon_view));
|
||||
*
|
||||
* // use list
|
||||
*
|
||||
* g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
|
||||
* ]|
|
||||
*
|
||||
@@ -6519,7 +6526,7 @@ gtk_icon_view_get_dest_item_at_pos (GtkIconView *icon_view,
|
||||
* Creates a `GdkPaintable` representation of the item at @path.
|
||||
* This image is used for a drag icon.
|
||||
*
|
||||
* Returns: (transfer full): a newly-allocated `GdkPaintable` of the drag icon.
|
||||
* Returns: (transfer full) (nullable): a newly-allocated `GdkPaintable` of the drag icon.
|
||||
**/
|
||||
GdkPaintable *
|
||||
gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
|
||||
|
||||
@@ -305,7 +305,7 @@ static void
|
||||
quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
|
||||
{
|
||||
GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
|
||||
GtkWidget* surface_widget = GTK_WIDGET (gdk_surface_get_widget (qc->client_surface));
|
||||
GtkWidget* surface_widget;
|
||||
int sx, sy;
|
||||
double wx, wy;
|
||||
|
||||
@@ -317,6 +317,11 @@ quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
|
||||
if (!qc->focused)
|
||||
return;
|
||||
|
||||
surface_widget = GTK_WIDGET (gdk_surface_get_widget (qc->client_surface));
|
||||
|
||||
if (!surface_widget)
|
||||
return;
|
||||
|
||||
gdk_surface_get_origin (qc->client_surface, &sx, &sy);
|
||||
gtk_widget_translate_coordinates(qc->client_widget, surface_widget,
|
||||
area->x, area->y, &wx, &wy);
|
||||
|
||||
+133
-21
@@ -55,6 +55,7 @@
|
||||
#include "gtkjoinedmenuprivate.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
@@ -272,6 +273,7 @@ struct _GtkLabel
|
||||
guint ellipsize : 3;
|
||||
guint use_markup : 1;
|
||||
guint wrap_mode : 3;
|
||||
guint natural_wrap_mode : 3;
|
||||
guint single_line_mode : 1;
|
||||
guint in_click : 1;
|
||||
guint track_links : 1;
|
||||
@@ -380,6 +382,7 @@ enum {
|
||||
PROP_JUSTIFY,
|
||||
PROP_WRAP,
|
||||
PROP_WRAP_MODE,
|
||||
PROP_NATURAL_WRAP_MODE,
|
||||
PROP_SELECTABLE,
|
||||
PROP_MNEMONIC_KEYVAL,
|
||||
PROP_MNEMONIC_WIDGET,
|
||||
@@ -484,6 +487,9 @@ gtk_label_set_property (GObject *object,
|
||||
case PROP_WRAP_MODE:
|
||||
gtk_label_set_wrap_mode (self, g_value_get_enum (value));
|
||||
break;
|
||||
case PROP_NATURAL_WRAP_MODE:
|
||||
gtk_label_set_natural_wrap_mode (self, g_value_get_enum (value));
|
||||
break;
|
||||
case PROP_SELECTABLE:
|
||||
gtk_label_set_selectable (self, g_value_get_boolean (value));
|
||||
break;
|
||||
@@ -551,6 +557,9 @@ gtk_label_get_property (GObject *object,
|
||||
case PROP_WRAP_MODE:
|
||||
g_value_set_enum (value, self->wrap_mode);
|
||||
break;
|
||||
case PROP_NATURAL_WRAP_MODE:
|
||||
g_value_set_enum (value, self->natural_wrap_mode);
|
||||
break;
|
||||
case PROP_SELECTABLE:
|
||||
g_value_set_boolean (value, gtk_label_get_selectable (self));
|
||||
break;
|
||||
@@ -604,6 +613,7 @@ gtk_label_init (GtkLabel *self)
|
||||
self->jtype = GTK_JUSTIFY_LEFT;
|
||||
self->wrap = FALSE;
|
||||
self->wrap_mode = PANGO_WRAP_WORD;
|
||||
self->natural_wrap_mode = GTK_NATURAL_WRAP_INHERIT;
|
||||
self->ellipsize = PANGO_ELLIPSIZE_NONE;
|
||||
|
||||
self->use_underline = FALSE;
|
||||
@@ -1158,6 +1168,34 @@ get_height_for_width (GtkLabel *self,
|
||||
g_object_unref (layout);
|
||||
}
|
||||
|
||||
static int
|
||||
my_pango_layout_get_width_for_height (PangoLayout *layout,
|
||||
int for_height,
|
||||
int min,
|
||||
int max)
|
||||
{
|
||||
int mid, text_width, text_height;
|
||||
|
||||
min = PANGO_PIXELS_CEIL (min);
|
||||
max = PANGO_PIXELS_CEIL (max);
|
||||
|
||||
while (min < max)
|
||||
{
|
||||
mid = (min + max) / 2;
|
||||
pango_layout_set_width (layout, mid * PANGO_SCALE);
|
||||
pango_layout_get_size (layout, &text_width, &text_height);
|
||||
text_width = PANGO_PIXELS_CEIL (text_width);
|
||||
if (text_width > mid)
|
||||
min = text_width;
|
||||
else if (text_height > for_height)
|
||||
min = mid + 1;
|
||||
else
|
||||
max = mid;
|
||||
}
|
||||
|
||||
return min * PANGO_SCALE;
|
||||
}
|
||||
|
||||
static void
|
||||
get_width_for_height (GtkLabel *self,
|
||||
int height,
|
||||
@@ -1183,7 +1221,7 @@ get_width_for_height (GtkLabel *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
int min, max, mid, text_width, text_height;
|
||||
int min, max;
|
||||
|
||||
/* Can't use a measuring layout here, because we need to force
|
||||
* ellipsizing mode */
|
||||
@@ -1198,24 +1236,19 @@ get_width_for_height (GtkLabel *self,
|
||||
pango_layout_set_width (layout, -1);
|
||||
pango_layout_get_size (layout, &max, NULL);
|
||||
|
||||
min = PANGO_PIXELS_CEIL (min);
|
||||
max = PANGO_PIXELS_CEIL (max);
|
||||
while (min < max)
|
||||
/* first, do natural width */
|
||||
if (self->natural_wrap_mode == GTK_NATURAL_WRAP_NONE)
|
||||
{
|
||||
mid = (min + max) / 2;
|
||||
pango_layout_set_width (layout, mid * PANGO_SCALE);
|
||||
pango_layout_get_size (layout, &text_width, &text_height);
|
||||
text_width = PANGO_PIXELS_CEIL (text_width);
|
||||
if (text_width > mid)
|
||||
min = mid = text_width;
|
||||
else if (text_height > height)
|
||||
min = mid + 1;
|
||||
else
|
||||
max = mid;
|
||||
*natural_width = max;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->natural_wrap_mode == GTK_NATURAL_WRAP_WORD)
|
||||
pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
|
||||
*natural_width = my_pango_layout_get_width_for_height (layout, height, min, max);
|
||||
}
|
||||
|
||||
*natural_width = min * PANGO_SCALE;
|
||||
|
||||
/* then, do minimum width */
|
||||
if (self->ellipsize != PANGO_ELLIPSIZE_NONE)
|
||||
{
|
||||
g_object_unref (layout);
|
||||
@@ -1223,10 +1256,15 @@ get_width_for_height (GtkLabel *self,
|
||||
pango_layout_get_size (layout, minimum_width, NULL);
|
||||
*minimum_width = MAX (*minimum_width, minimum_default);
|
||||
}
|
||||
else
|
||||
else if (self->natural_wrap_mode == GTK_NATURAL_WRAP_INHERIT)
|
||||
{
|
||||
*minimum_width = *natural_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
pango_layout_set_wrap (layout, self->wrap_mode);
|
||||
*minimum_width = my_pango_layout_get_width_for_height (layout, height, min, *natural_width);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (layout);
|
||||
@@ -2356,6 +2394,9 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
* This only affects the formatting if line wrapping is on (see the
|
||||
* [property@Gtk.Label:wrap] property). The default is %PANGO_WRAP_WORD,
|
||||
* which means wrap on word boundaries.
|
||||
*
|
||||
* For sizing behavior, also consider the [property@Gtk.Label:natural-wrap-mode]
|
||||
* property.
|
||||
*/
|
||||
label_props[PROP_WRAP_MODE] =
|
||||
g_param_spec_enum ("wrap-mode",
|
||||
@@ -2365,6 +2406,27 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
PANGO_WRAP_WORD,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkLabel:natural-wrap-mode: (attributes org.gtk.Property.get=gtk_label_get_natural_wrap_mode org.gtk.Property.set=gtk_label_set_natural_wrap_mode)
|
||||
*
|
||||
* Select the line wrapping for the natural size request.
|
||||
*
|
||||
* This only affects the natural size requested. For the actual wrapping used,
|
||||
* see the [property@Gtk.Label:wrap-mode] property.
|
||||
*
|
||||
* The default is %GTK_NATURAL_WRAP_INHERIT, which inherits the behavior of the
|
||||
* [property@Gtk.Label:wrap-mode] property.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
label_props[PROP_NATURAL_WRAP_MODE] =
|
||||
g_param_spec_enum ("natural-wrap-mode",
|
||||
P_("Natural wrap mode"),
|
||||
P_("If wrap is set, controls linewrapping for natural size requests"),
|
||||
GTK_TYPE_NATURAL_WRAP_MODE,
|
||||
GTK_NATURAL_WRAP_INHERIT,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkLabel:selectable: (attributes org.gtk.Property.get=gtk_label_get_selectable og.gtk.Property.set=gtk_label_set_selectable)
|
||||
*
|
||||
@@ -2431,7 +2493,7 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
*
|
||||
* If this property is set to -1, the width will be calculated automatically.
|
||||
*
|
||||
* See the section on [text layout](#text-layout) for details of how
|
||||
* See the section on [text layout](class.Label.html#text-layout) for details of how
|
||||
* [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
|
||||
* determine the width of ellipsized and wrapped labels.
|
||||
*/
|
||||
@@ -2467,7 +2529,7 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
*
|
||||
* If this property is set to -1, the width will be calculated automatically.
|
||||
*
|
||||
* See the section on [text layout](#text-layout) for details of how
|
||||
* See the section on [text layout](class.Label.html#text-layout) for details of how
|
||||
* [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
|
||||
* determine the width of ellipsized and wrapped labels.
|
||||
*/
|
||||
@@ -3979,6 +4041,9 @@ gtk_label_get_wrap (GtkLabel *self)
|
||||
* This only affects the label if line wrapping is on. (See
|
||||
* [method@Gtk.Label.set_wrap]) The default is %PANGO_WRAP_WORD
|
||||
* which means wrap on word boundaries.
|
||||
*
|
||||
* For sizing behavior, also consider the [property@Gtk.Label:natural-wrap-mode]
|
||||
* property.
|
||||
*/
|
||||
void
|
||||
gtk_label_set_wrap_mode (GtkLabel *self,
|
||||
@@ -4003,16 +4068,63 @@ gtk_label_set_wrap_mode (GtkLabel *self,
|
||||
*
|
||||
* See [method@Gtk.Label.set_wrap_mode].
|
||||
*
|
||||
* Returns: %TRUE if the lines of the label are automatically wrapped.
|
||||
* Returns: the line wrap mode
|
||||
*/
|
||||
PangoWrapMode
|
||||
gtk_label_get_wrap_mode (GtkLabel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_LABEL (self), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_LABEL (self), PANGO_WRAP_WORD);
|
||||
|
||||
return self->wrap_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_label_set_natural_wrap_mode: (attributes org.gtk.Method.set_property=natural-wrap-mode)
|
||||
* @self: a `GtkLabel`
|
||||
* @wrap_mode: the line wrapping mode
|
||||
*
|
||||
* Select the line wrapping for the natural size request.
|
||||
*
|
||||
* This only affects the natural size requested, for the actual wrapping used,
|
||||
* see the [property@Gtk.Label:wrap-mode] property.
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
void
|
||||
gtk_label_set_natural_wrap_mode (GtkLabel *self,
|
||||
GtkNaturalWrapMode wrap_mode)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LABEL (self));
|
||||
|
||||
if (self->natural_wrap_mode != wrap_mode)
|
||||
{
|
||||
self->natural_wrap_mode = wrap_mode;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), label_props[PROP_NATURAL_WRAP_MODE]);
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_label_get_natural_wrap_mode: (attributes org.gtk.Method.get_property=natural-wrap-mode)
|
||||
* @self: a `GtkLabel`
|
||||
*
|
||||
* Returns line wrap mode used by the label.
|
||||
*
|
||||
* See [method@Gtk.Label.set_natural_wrap_mode].
|
||||
*
|
||||
* Returns: the natural line wrap mode
|
||||
*
|
||||
* Since: 4.6
|
||||
*/
|
||||
GtkNaturalWrapMode
|
||||
gtk_label_get_natural_wrap_mode (GtkLabel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_LABEL (self), GTK_NATURAL_WRAP_INHERIT);
|
||||
|
||||
return self->natural_wrap_mode;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_clear_layout (GtkLabel *self)
|
||||
{
|
||||
|
||||
@@ -122,6 +122,11 @@ void gtk_label_set_wrap_mode (GtkLabel *self,
|
||||
PangoWrapMode wrap_mode);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
PangoWrapMode gtk_label_get_wrap_mode (GtkLabel *self);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
void gtk_label_set_natural_wrap_mode (GtkLabel *self,
|
||||
GtkNaturalWrapMode wrap_mode);
|
||||
GDK_AVAILABLE_IN_4_6
|
||||
GtkNaturalWrapMode gtk_label_get_natural_wrap_mode(GtkLabel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_label_set_selectable (GtkLabel *self,
|
||||
gboolean setting);
|
||||
|
||||
+1
-1
@@ -1078,7 +1078,7 @@ gtk_list_box_set_adjustment (GtkListBox *box,
|
||||
* Gets the adjustment (if any) that the widget uses to
|
||||
* for vertical scrolling.
|
||||
*
|
||||
* Returns: (transfer none): the adjustment
|
||||
* Returns: (transfer none) (nullable): the adjustment
|
||||
*/
|
||||
GtkAdjustment *
|
||||
gtk_list_box_get_adjustment (GtkListBox *box)
|
||||
|
||||
+1
-1
@@ -535,7 +535,7 @@ gtk_lock_button_new (GPermission *permission)
|
||||
*
|
||||
* Obtains the `GPermission` object that controls @button.
|
||||
*
|
||||
* Returns: (transfer none): the `GPermission` of @button
|
||||
* Returns: (transfer none) (nullable): the `GPermission` of @button
|
||||
*/
|
||||
GPermission *
|
||||
gtk_lock_button_get_permission (GtkLockButton *button)
|
||||
|
||||
+14
-3
@@ -68,6 +68,7 @@
|
||||
#include "gtknative.h"
|
||||
#include "gtkpopcountprivate.h"
|
||||
|
||||
#include "inspector/init.h"
|
||||
#include "inspector/window.h"
|
||||
|
||||
#include "gdk/gdkeventsprivate.h"
|
||||
@@ -566,6 +567,8 @@ do_post_parse_initialization (void)
|
||||
g_signal_connect (display_manager, "notify::default-display",
|
||||
G_CALLBACK (default_display_notify_cb),
|
||||
NULL);
|
||||
|
||||
gtk_inspector_register_extension ();
|
||||
}
|
||||
|
||||
#ifdef G_PLATFORM_WIN32
|
||||
@@ -750,9 +753,15 @@ gtk_is_initialized (void)
|
||||
* you can use it to update the default text direction as follows:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* setlocale (LC_ALL, new_locale);
|
||||
* direction = gtk_get_locale_direction ();
|
||||
* gtk_widget_set_default_direction (direction);
|
||||
* #include <locale.h>
|
||||
*
|
||||
* static void
|
||||
* update_locale (const char *new_locale)
|
||||
* {
|
||||
* setlocale (LC_ALL, new_locale);
|
||||
* GtkTextDirection direction = gtk_get_locale_direction ();
|
||||
* gtk_widget_set_default_direction (direction);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Returns: the `GtkTextDirection` of the current locale
|
||||
@@ -951,6 +960,7 @@ rewrite_event_for_surface (GdkEvent *event,
|
||||
case GDK_TOUCHPAD_SWIPE:
|
||||
gdk_touchpad_event_get_deltas (event, &dx, &dy);
|
||||
return gdk_touchpad_event_new_swipe (new_surface,
|
||||
gdk_event_get_event_sequence (event),
|
||||
gdk_event_get_device (event),
|
||||
gdk_event_get_time (event),
|
||||
gdk_event_get_modifier_state (event),
|
||||
@@ -961,6 +971,7 @@ rewrite_event_for_surface (GdkEvent *event,
|
||||
case GDK_TOUCHPAD_PINCH:
|
||||
gdk_touchpad_event_get_deltas (event, &dx, &dy);
|
||||
return gdk_touchpad_event_new_pinch (new_surface,
|
||||
gdk_event_get_event_sequence (event),
|
||||
gdk_event_get_device (event),
|
||||
gdk_event_get_time (event),
|
||||
gdk_event_get_modifier_state (event),
|
||||
|
||||
@@ -45,8 +45,7 @@
|
||||
*
|
||||
* widgets = gtk_widget_observe_children (widget);
|
||||
*
|
||||
* controllers = gtk_map_list_model_new (G_TYPE_LIST_MODEL,
|
||||
* widgets,
|
||||
* controllers = gtk_map_list_model_new (widgets,
|
||||
* map_to_controllers,
|
||||
* NULL, NULL);
|
||||
*
|
||||
|
||||
+4
-2
@@ -1028,6 +1028,7 @@ gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
|
||||
*/
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (menu_button->button),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, menu_button, NULL,
|
||||
GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, menu_button, NULL,
|
||||
-1);
|
||||
|
||||
image_widget = g_object_new (GTK_TYPE_IMAGE,
|
||||
@@ -1059,7 +1060,7 @@ gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
|
||||
*
|
||||
* Gets the name of the icon shown in the button.
|
||||
*
|
||||
* Returns: the name of the icon shown in the button
|
||||
* Returns: (nullable): the name of the icon shown in the button
|
||||
*/
|
||||
const char *
|
||||
gtk_menu_button_get_icon_name (GtkMenuButton *menu_button)
|
||||
@@ -1164,6 +1165,7 @@ gtk_menu_button_set_label (GtkMenuButton *menu_button,
|
||||
|
||||
gtk_accessible_update_relation (GTK_ACCESSIBLE (menu_button->button),
|
||||
GTK_ACCESSIBLE_RELATION_LABELLED_BY, menu_button->label_widget, NULL,
|
||||
GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, menu_button->label_widget, NULL,
|
||||
-1);
|
||||
|
||||
menu_button->image_widget = NULL;
|
||||
@@ -1182,7 +1184,7 @@ gtk_menu_button_set_label (GtkMenuButton *menu_button,
|
||||
*
|
||||
* Gets the label shown in the button
|
||||
*
|
||||
* Returns: the label shown in the button
|
||||
* Returns: (nullable): the label shown in the button
|
||||
*/
|
||||
const char *
|
||||
gtk_menu_button_get_label (GtkMenuButton *menu_button)
|
||||
|
||||
@@ -286,7 +286,7 @@ gtk_menu_tracker_item_update_visibility (GtkMenuTrackerItem *self)
|
||||
if (visible != self->is_visible)
|
||||
{
|
||||
self->is_visible = visible;
|
||||
g_object_notify (G_OBJECT (self), "is-visible");
|
||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_IS_VISIBLE]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,9 +300,17 @@ gtk_menu_tracker_item_action_added (GtkActionObserver *observer,
|
||||
{
|
||||
GtkMenuTrackerItem *self = GTK_MENU_TRACKER_ITEM (observer);
|
||||
GVariant *action_target;
|
||||
gboolean old_sensitive;
|
||||
gboolean old_toggled;
|
||||
GtkMenuTrackerItemRole old_role;
|
||||
guint n_changed;
|
||||
|
||||
GTK_NOTE(ACTIONS, g_message ("menutracker: action %s added", action_name));
|
||||
|
||||
old_sensitive = self->sensitive;
|
||||
old_toggled = self->toggled;
|
||||
old_role = self->role;
|
||||
|
||||
action_target = g_menu_item_get_attribute_value (self->item, G_MENU_ATTRIBUTE_TARGET, NULL);
|
||||
|
||||
self->can_activate = (action_target == NULL && parameter_type == NULL) ||
|
||||
@@ -340,18 +348,29 @@ gtk_menu_tracker_item_action_added (GtkActionObserver *observer,
|
||||
self->role = GTK_MENU_TRACKER_ITEM_ROLE_CHECK;
|
||||
}
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
/* Avoid freeze/thaw_notify as they are quite expensive in runtime/memory
|
||||
* unless we have more than one property to update. Additionally, only
|
||||
* notify on properties that have changed to avoid extraneous signal
|
||||
* emission. This code can get run a lot!
|
||||
*/
|
||||
n_changed = (old_role != self->role)
|
||||
+ (old_toggled != self->toggled)
|
||||
+ (old_sensitive != self->sensitive);
|
||||
|
||||
if (self->sensitive)
|
||||
if (n_changed > 1)
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
|
||||
if (self->sensitive != old_sensitive)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_SENSITIVE]);
|
||||
|
||||
if (self->toggled)
|
||||
if (self->toggled != old_toggled)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_TOGGLED]);
|
||||
|
||||
if (self->role != GTK_MENU_TRACKER_ITEM_ROLE_NORMAL)
|
||||
if (self->role != old_role)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), gtk_menu_tracker_item_pspecs[PROP_ROLE]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
if (n_changed > 1)
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
|
||||
if (action_target)
|
||||
g_variant_unref (action_target);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user