Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ff7c86b65 | |||
| 79a0f183ec | |||
| e8c8be8e37 | |||
| bfc80c32ea | |||
| 5f48764ac8 | |||
| cc6fcbfc09 | |||
| ea7185bdb1 | |||
| 429dfcf483 | |||
| be3f352b59 | |||
| 5b8896f1db | |||
| 4e27de7df9 | |||
| 2712f536c2 | |||
| a1f7073ff5 | |||
| 9770872d12 | |||
| de24b4f91b | |||
| 650fd9c291 | |||
| b509809f34 | |||
| 60ff231fac | |||
| 958005317b | |||
| 15c36aaa1e | |||
| 482b73c376 | |||
| 4a8bf6e13d | |||
| 3e2e6633b0 | |||
| 4724f9907c | |||
| 26e84a7b8c | |||
| d5838f14f9 | |||
| 5c532104e4 | |||
| 2f42e1fb89 | |||
| b5200bd076 | |||
| aa5bd38137 | |||
| 0eba833595 | |||
| 1e0ea21297 | |||
| e91e75173d | |||
| 927fdb9a83 | |||
| 041f410838 | |||
| c71c8919fe | |||
| 3f28399f7d | |||
| 3c15fa96bc | |||
| 0a0a059397 | |||
| 18e83fe16d | |||
| 90d7ed5dd1 | |||
| 3c6e7569ff | |||
| 4e2ec2d68d | |||
| 1af72eac21 | |||
| 640273a0e2 | |||
| a14a0c6315 | |||
| 38481680e1 | |||
| 12a540c284 | |||
| 289bf078bf | |||
| 58ab9ddc40 | |||
| c78036fc51 | |||
| 120f2768e6 | |||
| 592b33cb48 | |||
| 7a9bc1f1d8 | |||
| 9cc6f3ee29 | |||
| 9efaa0b51d | |||
| f0967fa5e4 | |||
| f8529983f9 | |||
| 919c08d4fd | |||
| e9b06b6346 | |||
| 949c783187 | |||
| 814a4a781a | |||
| 676f875bf6 | |||
| 140c5c5333 | |||
| cebf2b2009 | |||
| 86b437a1b6 | |||
| 773ae0cd0f | |||
| 564793d5b5 | |||
| 9142aa0f51 | |||
| af9a578d68 | |||
| ecb072fdd0 | |||
| ef053ebb4a | |||
| 8d18d93742 | |||
| 10fcdd88e3 | |||
| 5d9509c51b | |||
| c9cac5fbc3 | |||
| aa9054a5f1 | |||
| 9ebf3fac73 | |||
| 569294070b | |||
| be35c46ce9 | |||
| dbbcb13721 | |||
| edeaf9c040 | |||
| 61f709811c | |||
| f7c4375509 | |||
| 52fb900ced | |||
| 031944ad30 | |||
| bf8b974f68 | |||
| 6ad2a049e7 | |||
| 3d85d53e5d | |||
| 094a346539 | |||
| 162814f969 | |||
| e39b5c99f1 | |||
| 8883243aaa | |||
| 89511eecf1 | |||
| 2c304ca80d | |||
| bf4102e664 | |||
| b86153cee3 | |||
| 7985d277b3 | |||
| 752da5c2a5 | |||
| de4b8d547b | |||
| 1048ad1a01 | |||
| 4d11158d97 | |||
| 293b81cad2 | |||
| 65c38111f9 | |||
| ec8db379a6 | |||
| 1484b4ae9f | |||
| 4cecbf1654 | |||
| 234ba90e2b | |||
| bdd2244f75 | |||
| cd7ec8ac92 | |||
| 11f3b7730c | |||
| f63e6394ac | |||
| bbca4c38df | |||
| 28f5d26719 | |||
| bf2620f041 | |||
| 870b82b541 | |||
| 5968b10b0b |
@@ -1,3 +1,58 @@
|
||||
Overview of Changes in 4.1.0
|
||||
============================
|
||||
|
||||
* GtkCheckButton:
|
||||
- Add back an activate signal
|
||||
|
||||
* GtkSearchBar, GtkSearchEntry:
|
||||
- Capture events in the bubble phase
|
||||
|
||||
* GtkEmojiChooser:
|
||||
- Adapt to small screen sizes
|
||||
|
||||
* GtkVideo:
|
||||
- Fix issues with GL support
|
||||
|
||||
* Themes:
|
||||
- Set sort arrows in CSS
|
||||
- Set menu button arrows in CSS
|
||||
- Make scrollbars larger
|
||||
- Supprt circular menubuttons
|
||||
|
||||
* CSS:
|
||||
- Implement transform-origin
|
||||
- Support overlines on text
|
||||
- Support colors in cross-fade()
|
||||
- More complete text-decoration-line support
|
||||
|
||||
* Text layout:
|
||||
- Use subpixel positioning with new enough cairo
|
||||
|
||||
* Inspector:
|
||||
- Fix slowness in navigation
|
||||
- Redo the controllers and shortcuts pages
|
||||
|
||||
* Accessibility:
|
||||
- Create AT context objects lazily
|
||||
|
||||
* Wayland:
|
||||
- Fix decoration negotiation under kwin
|
||||
|
||||
* GSK:
|
||||
- Optimize gradient shaders
|
||||
- Implement repeating gradients in shaders
|
||||
|
||||
* Translation updates
|
||||
- Czech
|
||||
- Greek
|
||||
- Hungarian
|
||||
- Persian
|
||||
- Punjabi
|
||||
- Romanian
|
||||
- Swedish
|
||||
- Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.0.2
|
||||
============================
|
||||
|
||||
|
||||
@@ -279,11 +279,31 @@ drag_prepare_texture (GtkDragSource *source,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
GtkSnapshot *snapshot;
|
||||
double width, height;
|
||||
GskRenderNode *node;
|
||||
GskRenderer *renderer;
|
||||
GdkTexture *texture;
|
||||
GdkContentProvider *ret;
|
||||
|
||||
if (!GDK_IS_PAINTABLE (paintable))
|
||||
return NULL;
|
||||
|
||||
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
|
||||
snapshot = gtk_snapshot_new ();
|
||||
width = gdk_paintable_get_intrinsic_width (paintable);
|
||||
height = gdk_paintable_get_intrinsic_height (paintable);
|
||||
gdk_paintable_snapshot (paintable, snapshot, width, height);
|
||||
node = gtk_snapshot_free_to_node (snapshot);
|
||||
|
||||
renderer = gtk_native_get_renderer (gtk_widget_get_native (widget));
|
||||
texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
ret = gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, texture);
|
||||
|
||||
g_object_unref (texture);
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
|
||||
@@ -700,6 +700,16 @@ out:
|
||||
g_free (source_dir);
|
||||
}
|
||||
|
||||
static void
|
||||
dark_mode_cb (GtkToggleButton *button,
|
||||
GParamSpec *pspec,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
g_object_set (gtk_widget_get_settings (GTK_WIDGET (self)),
|
||||
"gtk-application-prefer-dark-theme", gtk_toggle_button_get_active (button),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
node_editor_window_finalize (GObject *object)
|
||||
{
|
||||
@@ -814,6 +824,7 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
|
||||
gtk_widget_class_bind_template_callback (widget_class, export_image_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, testcase_save_clicked_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, testcase_name_entry_changed_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, dark_mode_cb);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
|
||||
@@ -139,6 +139,15 @@
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="dark_bg_button">
|
||||
<property name="valign">center</property>
|
||||
<property name="has-frame">0</property>
|
||||
<property name="icon-name">display-brightness-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Use a dark background</property>
|
||||
<signal name="notify::active" handler="dark_mode_cb" swapped="0"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -80,6 +80,31 @@ and in some cases a number as arguments.
|
||||
|
||||
## Images
|
||||
|
||||
CSS allows to specify images in various forms, the most simple one being
|
||||
a url for an image file. Beyond that, images can be specified as
|
||||
|
||||
`linear-gradient(Angle, ColorStops)`
|
||||
`repeating-linear-gradient(Angle, ColorStops)`
|
||||
: creates a linear gradient.
|
||||
|
||||
`radial-gradient(Shape, ColorStops)`
|
||||
`repeating-radial-gradient(Shape, ColorStops)`
|
||||
: creates a radial gradient.
|
||||
|
||||
`conic-gradient(Angle, ColorStops)`
|
||||
: creates a conic gradient.
|
||||
|
||||
`cross-fade(Percentage Image,…)`
|
||||
: combines two or more images.
|
||||
|
||||
`image(Image,… Color)`
|
||||
: falls back to the first valid image, or to a solid color.
|
||||
|
||||
`filter(Image, Filters)`
|
||||
: applies filters to an image.
|
||||
|
||||
For more details, see [CSS Image Level 4](https://www.w3.org/TR/css-images-4/).
|
||||
|
||||
GTK extends the CSS syntax for images and also uses it for specifying icons.
|
||||
To load a themed icon, use
|
||||
|
||||
|
||||
@@ -1831,7 +1831,6 @@ GtkIMContextSimple
|
||||
gtk_im_context_simple_new
|
||||
gtk_im_context_simple_add_table
|
||||
gtk_im_context_simple_add_compose_file
|
||||
GTK_MAX_COMPOSE_LEN
|
||||
<SUBSECTION Standard>
|
||||
GTK_IM_CONTEXT_SIMPLE
|
||||
GTK_IS_IM_CONTEXT_SIMPLE
|
||||
|
||||
@@ -1,293 +0,0 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "exampleapp.h"
|
||||
#include "exampleappwin.h"
|
||||
|
||||
struct _ExampleAppWindow
|
||||
{
|
||||
GtkApplicationWindow parent;
|
||||
|
||||
GSettings *settings;
|
||||
GtkWidget *stack;
|
||||
GtkWidget *search;
|
||||
GtkWidget *searchbar;
|
||||
GtkWidget *searchentry;
|
||||
GtkWidget *gears;
|
||||
GtkWidget *sidebar;
|
||||
GtkWidget *words;
|
||||
GtkWidget *lines;
|
||||
GtkWidget *lines_label;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
|
||||
static void
|
||||
search_text_changed (GtkEntry *entry,
|
||||
ExampleAppWindow *win)
|
||||
{
|
||||
const char *text;
|
||||
GtkWidget *tab;
|
||||
GtkWidget *view;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, match_start, match_end;
|
||||
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
||||
|
||||
if (text[0] == '\0')
|
||||
return;
|
||||
|
||||
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
|
||||
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
|
||||
/* Very simple-minded search implementation */
|
||||
gtk_text_buffer_get_start_iter (buffer, &start);
|
||||
if (gtk_text_iter_forward_search (&start, text, GTK_TEXT_SEARCH_CASE_INSENSITIVE,
|
||||
&match_start, &match_end, NULL))
|
||||
{
|
||||
gtk_text_buffer_select_range (buffer, &match_start, &match_end);
|
||||
gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), &match_start,
|
||||
0.0, FALSE, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_word (GtkButton *button,
|
||||
ExampleAppWindow *win)
|
||||
{
|
||||
const char *word;
|
||||
|
||||
word = gtk_button_get_label (button);
|
||||
gtk_editable_set_text (GTK_EDITABLE (win->searchentry), word);
|
||||
}
|
||||
|
||||
static void
|
||||
update_words (ExampleAppWindow *win)
|
||||
{
|
||||
GHashTable *strings;
|
||||
GHashTableIter iter;
|
||||
GtkWidget *tab, *view, *row;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, end;
|
||||
char *word, *key;
|
||||
GtkWidget *child;
|
||||
|
||||
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
|
||||
|
||||
if (tab == NULL)
|
||||
return;
|
||||
|
||||
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
|
||||
strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
gtk_text_buffer_get_start_iter (buffer, &start);
|
||||
while (!gtk_text_iter_is_end (&start))
|
||||
{
|
||||
while (!gtk_text_iter_starts_word (&start))
|
||||
{
|
||||
if (!gtk_text_iter_forward_char (&start))
|
||||
goto done;
|
||||
}
|
||||
end = start;
|
||||
if (!gtk_text_iter_forward_word_end (&end))
|
||||
goto done;
|
||||
word = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
g_hash_table_add (strings, g_utf8_strdown (word, -1));
|
||||
g_free (word);
|
||||
start = end;
|
||||
}
|
||||
|
||||
done:
|
||||
while ((child = gtk_widget_get_first_child (win->words)))
|
||||
gtk_list_box_remove (GTK_LIST_BOX (win->words), child);
|
||||
|
||||
g_hash_table_iter_init (&iter, strings);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
|
||||
{
|
||||
row = gtk_button_new_with_label (key);
|
||||
g_signal_connect (row, "clicked",
|
||||
G_CALLBACK (find_word), win);
|
||||
gtk_box_append (GTK_BOX (win->words), row);
|
||||
}
|
||||
|
||||
g_hash_table_unref (strings);
|
||||
}
|
||||
|
||||
static void
|
||||
update_lines (ExampleAppWindow *win)
|
||||
{
|
||||
GtkWidget *tab, *view;
|
||||
GtkTextBuffer *buffer;
|
||||
int count;
|
||||
char *lines;
|
||||
|
||||
tab = gtk_stack_get_visible_child (GTK_STACK (win->stack));
|
||||
|
||||
if (tab == NULL)
|
||||
return;
|
||||
|
||||
view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab));
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
|
||||
count = gtk_text_buffer_get_line_count (buffer);
|
||||
lines = g_strdup_printf ("%d", count);
|
||||
gtk_label_set_text (GTK_LABEL (win->lines), lines);
|
||||
g_free (lines);
|
||||
}
|
||||
|
||||
static void
|
||||
visible_child_changed (GObject *stack,
|
||||
GParamSpec *pspec,
|
||||
ExampleAppWindow *win)
|
||||
{
|
||||
if (gtk_widget_in_destruction (GTK_WIDGET (stack)))
|
||||
return;
|
||||
|
||||
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (win->searchbar), FALSE);
|
||||
update_words (win);
|
||||
update_lines (win);
|
||||
}
|
||||
|
||||
static void
|
||||
words_changed (GObject *sidebar,
|
||||
GParamSpec *pspec,
|
||||
ExampleAppWindow *win)
|
||||
{
|
||||
update_words (win);
|
||||
}
|
||||
|
||||
static void
|
||||
example_app_window_init (ExampleAppWindow *win)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GMenuModel *menu;
|
||||
GAction *action;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (win));
|
||||
win->settings = g_settings_new ("org.gtk.exampleapp");
|
||||
|
||||
g_settings_bind (win->settings, "transition",
|
||||
win->stack, "transition-type",
|
||||
G_SETTINGS_BIND_DEFAULT);
|
||||
|
||||
g_settings_bind (win->settings, "show-words",
|
||||
win->sidebar, "reveal-child",
|
||||
G_SETTINGS_BIND_DEFAULT);
|
||||
|
||||
g_object_bind_property (win->search, "active",
|
||||
win->searchbar, "search-mode-enabled",
|
||||
G_BINDING_BIDIRECTIONAL);
|
||||
|
||||
g_signal_connect (win->sidebar, "notify::reveal-child",
|
||||
G_CALLBACK (words_changed), win);
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/org/gtk/exampleapp/gears-menu.ui");
|
||||
menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu"));
|
||||
gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (win->gears), menu);
|
||||
g_object_unref (builder);
|
||||
|
||||
action = g_settings_create_action (win->settings, "show-words");
|
||||
g_action_map_add_action (G_ACTION_MAP (win), action);
|
||||
g_object_unref (action);
|
||||
|
||||
action = (GAction*) g_property_action_new ("show-lines", win->lines, "visible");
|
||||
g_action_map_add_action (G_ACTION_MAP (win), action);
|
||||
g_object_unref (action);
|
||||
|
||||
g_object_bind_property (win->lines, "visible",
|
||||
win->lines_label, "visible",
|
||||
G_BINDING_DEFAULT);
|
||||
|
||||
g_object_set (gtk_settings_get_default (), "gtk-shell-shows-app-menu", FALSE, NULL);
|
||||
gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
example_app_window_dispose (GObject *object)
|
||||
{
|
||||
ExampleAppWindow *win;
|
||||
|
||||
win = EXAMPLE_APP_WINDOW (object);
|
||||
|
||||
g_clear_object (&win->settings);
|
||||
|
||||
G_OBJECT_CLASS (example_app_window_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
example_app_window_class_init (ExampleAppWindowClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->dispose = example_app_window_dispose;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/exampleapp/window.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, search);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchbar);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchentry);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, gears);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, words);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, sidebar);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, lines_label);
|
||||
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed);
|
||||
}
|
||||
|
||||
ExampleAppWindow *
|
||||
example_app_window_new (ExampleApp *app)
|
||||
{
|
||||
return g_object_new (EXAMPLE_APP_WINDOW_TYPE, "application", app, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
example_app_window_open (ExampleAppWindow *win,
|
||||
GFile *file)
|
||||
{
|
||||
char *basename;
|
||||
GtkWidget *scrolled, *view;
|
||||
char *contents;
|
||||
gsize length;
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextTag *tag;
|
||||
GtkTextIter start_iter, end_iter;
|
||||
|
||||
basename = g_file_get_basename (file);
|
||||
|
||||
scrolled = gtk_scrolled_window_new ();
|
||||
gtk_widget_set_hexpand (scrolled, TRUE);
|
||||
gtk_widget_set_vexpand (scrolled, TRUE);
|
||||
view = gtk_text_view_new ();
|
||||
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
|
||||
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), view);
|
||||
gtk_stack_add_titled (GTK_STACK (win->stack), scrolled, basename, basename);
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
||||
|
||||
if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
|
||||
{
|
||||
gtk_text_buffer_set_text (buffer, contents, length);
|
||||
g_free (contents);
|
||||
}
|
||||
|
||||
tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
|
||||
g_settings_bind (win->settings, "font",
|
||||
tag, "font",
|
||||
G_SETTINGS_BIND_DEFAULT);
|
||||
|
||||
gtk_text_buffer_get_start_iter (buffer, &start_iter);
|
||||
gtk_text_buffer_get_end_iter (buffer, &end_iter);
|
||||
gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);
|
||||
|
||||
g_free (basename);
|
||||
|
||||
gtk_widget_set_sensitive (win->search, TRUE);
|
||||
|
||||
update_words (win);
|
||||
update_lines (win);
|
||||
}
|
||||
@@ -173,7 +173,7 @@ stash_desktop_startup_notification_id (void)
|
||||
if (!g_utf8_validate (desktop_startup_id, -1, NULL))
|
||||
g_warning ("DESKTOP_STARTUP_ID contains invalid UTF-8");
|
||||
else
|
||||
startup_notification_id = g_strdup (desktop_startup_id ? desktop_startup_id : "");
|
||||
startup_notification_id = g_strdup (desktop_startup_id);
|
||||
}
|
||||
|
||||
/* Clear the environment variable so it won't be inherited by
|
||||
|
||||
@@ -149,12 +149,6 @@ gdk_toplevel_size_validate (GdkToplevelSize *size)
|
||||
{
|
||||
int geometry_width, geometry_height;
|
||||
|
||||
if (size->min_width > size->bounds_width ||
|
||||
size->min_height > size->bounds_height)
|
||||
g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds bounds (%d, %d)",
|
||||
size->min_width, size->min_height,
|
||||
size->bounds_width, size->bounds_height);
|
||||
|
||||
geometry_width = size->width;
|
||||
geometry_height = size->height;
|
||||
if (size->shadow.is_valid)
|
||||
@@ -162,15 +156,4 @@ gdk_toplevel_size_validate (GdkToplevelSize *size)
|
||||
geometry_width -= size->shadow.left + size->shadow.right;
|
||||
geometry_height -= size->shadow.top + size->shadow.bottom;
|
||||
}
|
||||
if (geometry_width > size->bounds_width ||
|
||||
geometry_height > size->bounds_height)
|
||||
g_warning ("GdkToplevelSize: geometry size (%d, %d) exceeds bounds (%d, %d)",
|
||||
size->width, size->height,
|
||||
size->bounds_width, size->bounds_height);
|
||||
|
||||
if (size->min_width > size->width ||
|
||||
size->min_height > size->height)
|
||||
g_warning ("GdkToplevelSize: min_size (%d, %d) exceeds size (%d, %d)",
|
||||
size->min_width, size->min_height,
|
||||
size->width, size->height);
|
||||
}
|
||||
|
||||
+46
-5
@@ -39,6 +39,7 @@
|
||||
#include "gdkscreen-x11.h"
|
||||
#include "gdkselectioninputstream-x11.h"
|
||||
#include "gdkselectionoutputstream-x11.h"
|
||||
#include "gdktextlistconverter-x11.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@@ -103,6 +104,49 @@ static const struct {
|
||||
|
||||
G_DEFINE_TYPE (GdkX11Drop, gdk_x11_drop, GDK_TYPE_DROP)
|
||||
|
||||
static GInputStream *
|
||||
text_list_convert (GdkDisplay *display,
|
||||
GInputStream *stream,
|
||||
const char *encoding,
|
||||
int format)
|
||||
{
|
||||
GInputStream *converter_stream;
|
||||
GConverter *converter;
|
||||
|
||||
converter = gdk_x11_text_list_converter_to_utf8_new (display, encoding, format);
|
||||
converter_stream = g_converter_input_stream_new (stream, converter);
|
||||
|
||||
g_object_unref (converter);
|
||||
g_object_unref (stream);
|
||||
|
||||
return converter_stream;
|
||||
}
|
||||
|
||||
static GInputStream *
|
||||
no_convert (GdkDisplay *display,
|
||||
GInputStream *stream,
|
||||
const char *encoding,
|
||||
int format)
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *x_target;
|
||||
const char *mime_type;
|
||||
GInputStream * (* convert) (GdkDisplay *, GInputStream *, const char *, int);
|
||||
const char *type;
|
||||
int format;
|
||||
} special_targets[] = {
|
||||
{ "UTF8_STRING", "text/plain;charset=utf-8", no_convert, "UTF8_STRING", 8 },
|
||||
{ "COMPOUND_TEXT", "text/plain;charset=utf-8", text_list_convert, "COMPOUND_TEXT", 8 },
|
||||
{ "TEXT", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
|
||||
{ "STRING", "text/plain;charset=utf-8", text_list_convert, "STRING", 8 },
|
||||
{ "TARGETS", NULL, NULL, "ATOM", 32 },
|
||||
{ "TIMESTAMP", NULL, NULL, "INTEGER", 32 },
|
||||
{ "SAVE_TARGETS", NULL, NULL, "NULL", 32 }
|
||||
};
|
||||
|
||||
static void
|
||||
gdk_x11_drop_read_got_stream (GObject *source,
|
||||
GAsyncResult *res,
|
||||
@@ -145,9 +189,9 @@ gdk_x11_drop_read_got_stream (GObject *source,
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
gsize i;
|
||||
const char *mime_type = ((GSList *) g_task_get_task_data (task))->data;
|
||||
GdkDrop *drop = GDK_DROP (g_task_get_source_object (task));
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
|
||||
{
|
||||
@@ -155,15 +199,12 @@ gdk_x11_drop_read_got_stream (GObject *source,
|
||||
{
|
||||
g_assert (special_targets[i].mime_type != NULL);
|
||||
|
||||
GDK_DISPLAY_NOTE (CLIPBOARD, g_printerr ("%s: reading with converter from %s to %s\n",
|
||||
cb->selection, mime_type, special_targets[i].mime_type));
|
||||
mime_type = g_intern_string (special_targets[i].mime_type);
|
||||
g_task_set_task_data (task, g_slist_prepend (NULL, (gpointer) mime_type), (GDestroyNotify) g_slist_free);
|
||||
stream = special_targets[i].convert (cb, stream, type, format);
|
||||
stream = special_targets[i].convert (gdk_drop_get_display (drop), stream, type, format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GDK_NOTE (DND, g_printerr ("reading DND as %s now\n",
|
||||
(const char *)((GSList *) g_task_get_task_data (task))->data));
|
||||
|
||||
@@ -1383,7 +1383,7 @@ gdk_x11_keymap_translate_keyboard_state (GdkKeymap *keymap,
|
||||
|
||||
tmp_keyval = translate_keysym (keymap_x11, hardware_keycode,
|
||||
group, state,
|
||||
level, effective_group);
|
||||
effective_group, level);
|
||||
}
|
||||
|
||||
if (consumed_modifiers)
|
||||
|
||||
@@ -718,7 +718,7 @@ gsk_vulkan_image_upload_regions (GskVulkanImage *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
for (gsize r = 0; r < regions[i].height; i++)
|
||||
for (gsize r = 0; r < regions[i].height; r++)
|
||||
memcpy (m + r * regions[i].width * 4, regions[i].data + r * regions[i].stride, regions[i].width * 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,10 +68,8 @@ action_handle_method (GtkAtSpiContext *self,
|
||||
|
||||
g_variant_get (parameters, "(i)", &idx);
|
||||
|
||||
const Action *action = &actions[idx];
|
||||
|
||||
if (idx >= 0 && idx < n_actions)
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", action->name));
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", actions[idx].name));
|
||||
else
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_IO_ERROR,
|
||||
@@ -129,10 +127,8 @@ action_handle_method (GtkAtSpiContext *self,
|
||||
|
||||
g_variant_get (parameters, "(i)", &idx);
|
||||
|
||||
const Action *action = &actions[idx];
|
||||
|
||||
if (idx >= 0 && idx < n_actions)
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", action->keybinding));
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", actions[idx].keybinding));
|
||||
else
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
G_IO_ERROR,
|
||||
|
||||
@@ -310,14 +310,10 @@ click_pressed_cb (GtkGestureClick *gesture,
|
||||
{
|
||||
GtkButton *button = GTK_BUTTON (widget);
|
||||
GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
|
||||
GdkEventSequence *sequence;
|
||||
|
||||
if (gtk_widget_get_focus_on_click (widget) && !gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), sequence, GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
if (!priv->activate_timeout)
|
||||
priv->button_down = TRUE;
|
||||
}
|
||||
|
||||
@@ -278,8 +278,6 @@ click_pressed_cb (GtkGestureClick *gesture,
|
||||
{
|
||||
if (gtk_widget_get_focus_on_click (widget) && !gtk_widget_has_focus (widget))
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -295,6 +293,8 @@ click_released_cb (GtkGestureClick *gesture,
|
||||
if (priv->active && (priv->group_prev || priv->group_next))
|
||||
return;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
gtk_check_button_set_active (self, !priv->active);
|
||||
|
||||
if (priv->action_helper)
|
||||
|
||||
+2
-2
@@ -39,7 +39,7 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkgestureclick.h"
|
||||
|
||||
@@ -1128,7 +1128,7 @@ header_drag_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (!self->in_column_resize && !self->in_column_reorder)
|
||||
{
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, 0))
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
GtkWidget *header;
|
||||
|
||||
+567
-177
@@ -26,16 +26,17 @@
|
||||
#include "gtkcomposetable.h"
|
||||
#include "gtkimcontextsimple.h"
|
||||
|
||||
#include "gtkimcontextsimpleprivate.h"
|
||||
|
||||
|
||||
#define GTK_COMPOSE_TABLE_MAGIC "GtkComposeTable"
|
||||
#define GTK_COMPOSE_TABLE_VERSION (1)
|
||||
#define GTK_COMPOSE_TABLE_VERSION (2)
|
||||
|
||||
/* Maximum length of sequences we parse */
|
||||
|
||||
#define MAX_COMPOSE_LEN 20
|
||||
|
||||
typedef struct {
|
||||
gunichar *sequence;
|
||||
gunichar value[2];
|
||||
char *comment;
|
||||
gunichar *sequence;
|
||||
char *value;
|
||||
} GtkComposeData;
|
||||
|
||||
|
||||
@@ -43,7 +44,7 @@ static void
|
||||
gtk_compose_data_free (GtkComposeData *compose_data)
|
||||
{
|
||||
g_free (compose_data->sequence);
|
||||
g_free (compose_data->comment);
|
||||
g_free (compose_data->value);
|
||||
g_slice_free (GtkComposeData, compose_data);
|
||||
}
|
||||
|
||||
@@ -76,58 +77,82 @@ parse_compose_value (GtkComposeData *compose_data,
|
||||
const char *val,
|
||||
const char *line)
|
||||
{
|
||||
char **words = g_strsplit (val, "\"", 3);
|
||||
gunichar uch;
|
||||
char *word;
|
||||
const char *p;
|
||||
gsize len;
|
||||
GString *value;
|
||||
gunichar ch;
|
||||
char *endp;
|
||||
|
||||
if (g_strv_length (words) < 3)
|
||||
len = strlen (val);
|
||||
if (val[0] != '"' || val[len - 1] != '"')
|
||||
{
|
||||
g_warning ("Need to double-quote the value: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
uch = g_utf8_get_char (words[1]);
|
||||
word = g_strndup (val + 1, len - 2);
|
||||
|
||||
if (uch == 0)
|
||||
{
|
||||
g_warning ("Invalid value: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
else if (uch == '\\')
|
||||
{
|
||||
uch = words[1][1];
|
||||
value = g_string_new ("");
|
||||
|
||||
/* The escaped string "\"" is separated with '\\' and '"'. */
|
||||
if (uch == '\0' && words[2][0] == '"')
|
||||
uch = '"';
|
||||
/* The escaped octal */
|
||||
else if (uch >= '0' && uch <= '8')
|
||||
uch = g_ascii_strtoll(words[1] + 1, NULL, 8);
|
||||
/* If we need to handle other escape sequences. */
|
||||
else if (uch != '\\')
|
||||
p = word;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '\\')
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
if (p[1] == '"')
|
||||
{
|
||||
g_string_append_c (value, '"');
|
||||
p += 2;
|
||||
}
|
||||
else if (p[1] == '\\')
|
||||
{
|
||||
g_string_append_c (value, '\\');
|
||||
p += 2;
|
||||
}
|
||||
else if (p[1] >= '0' && p[1] < '8')
|
||||
{
|
||||
ch = g_ascii_strtoll (p + 1, &endp, 8);
|
||||
if (ch == 0)
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
g_string_append_unichar (value, ch);
|
||||
p = endp;
|
||||
}
|
||||
else if (p[1] == 'x' || p[1] == 'X')
|
||||
{
|
||||
ch = g_ascii_strtoll (p + 2, &endp, 16);
|
||||
if (ch == 0)
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
g_string_append_unichar (value, ch);
|
||||
p = endp;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Invalid escape sequence: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = g_utf8_get_char (p);
|
||||
g_string_append_unichar (value, ch);
|
||||
p = g_utf8_next_char (p);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_utf8_get_char (g_utf8_next_char (words[1])) > 0)
|
||||
{
|
||||
g_warning ("GTK supports to output one char only: %s: %s", val, line);
|
||||
goto fail;
|
||||
}
|
||||
compose_data->value = g_string_free (value, FALSE);
|
||||
|
||||
compose_data->value[1] = uch;
|
||||
|
||||
if (uch == '"')
|
||||
compose_data->comment = g_strdup (g_strstrip (words[2] + 1));
|
||||
else
|
||||
compose_data->comment = g_strdup (g_strstrip (words[2]));
|
||||
|
||||
g_strfreev (words);
|
||||
g_free (word);
|
||||
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
g_strfreev (words);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -189,10 +214,10 @@ parse_compose_sequence (GtkComposeData *compose_data,
|
||||
}
|
||||
|
||||
g_strfreev (words);
|
||||
if (0 == n || n >= GTK_MAX_COMPOSE_LEN)
|
||||
if (0 == n || n > MAX_COMPOSE_LEN)
|
||||
{
|
||||
g_warning ("The max number of sequences is %d: %s",
|
||||
GTK_MAX_COMPOSE_LEN, line);
|
||||
g_warning ("Suspicious compose sequence length (%d). Are you sure this is right?: %s",
|
||||
n, line);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -214,7 +239,10 @@ parse_compose_line (GList **compose_list,
|
||||
return;
|
||||
|
||||
if (g_str_has_prefix (line, "include "))
|
||||
return;
|
||||
{
|
||||
g_warning ("include in Compose files not supported: %s", line);
|
||||
return;
|
||||
}
|
||||
|
||||
components = g_strsplit (line, ":", 2);
|
||||
|
||||
@@ -244,6 +272,8 @@ fail:
|
||||
gtk_compose_data_free (compose_data);
|
||||
}
|
||||
|
||||
extern const GtkComposeTableCompact gtk_compose_table_compact;
|
||||
|
||||
static GList *
|
||||
gtk_compose_list_parse_file (const char *compose_file)
|
||||
{
|
||||
@@ -279,18 +309,19 @@ gtk_compose_list_check_duplicated (GList *compose_list)
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
static guint16 keysyms[GTK_MAX_COMPOSE_LEN + 1];
|
||||
static guint16 keysyms[MAX_COMPOSE_LEN + 1];
|
||||
int i;
|
||||
int n_compose = 0;
|
||||
gboolean compose_finish;
|
||||
gunichar output_char;
|
||||
char buf[8] = { 0, };
|
||||
|
||||
compose_data = list->data;
|
||||
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
keysyms[i] = 0;
|
||||
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
{
|
||||
gunichar codepoint = compose_data->sequence[i];
|
||||
keysyms[i] = (guint16) codepoint;
|
||||
@@ -301,20 +332,21 @@ gtk_compose_list_check_duplicated (GList *compose_list)
|
||||
n_compose++;
|
||||
}
|
||||
|
||||
if (gtk_check_compact_table (>k_compose_table_compact,
|
||||
keysyms,
|
||||
n_compose,
|
||||
&compose_finish,
|
||||
NULL,
|
||||
&output_char) &&
|
||||
if (gtk_compose_table_compact_check (>k_compose_table_compact,
|
||||
keysyms, n_compose,
|
||||
&compose_finish,
|
||||
NULL,
|
||||
&output_char) &&
|
||||
compose_finish)
|
||||
{
|
||||
if (compose_data->value[1] == output_char)
|
||||
g_unichar_to_utf8 (output_char, buf);
|
||||
if (strcmp (compose_data->value, buf) == 0)
|
||||
removed_list = g_list_prepend (removed_list, compose_data);
|
||||
}
|
||||
else if (gtk_check_algorithmically (keysyms, n_compose, &output_char))
|
||||
{
|
||||
if (compose_data->value[1] == output_char)
|
||||
g_unichar_to_utf8 (output_char, buf);
|
||||
if (strcmp (compose_data->value, buf) == 0)
|
||||
removed_list = g_list_prepend (removed_list, compose_data);
|
||||
}
|
||||
}
|
||||
@@ -343,7 +375,7 @@ gtk_compose_list_check_uint16 (GList *compose_list)
|
||||
int i;
|
||||
|
||||
compose_data = list->data;
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN; i++)
|
||||
{
|
||||
gunichar codepoint = compose_data->sequence[i];
|
||||
|
||||
@@ -384,7 +416,7 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
for (i = 0; i < GTK_MAX_COMPOSE_LEN + 1; i++)
|
||||
for (i = 0; i < MAX_COMPOSE_LEN + 1; i++)
|
||||
{
|
||||
codepoint = compose_data->sequence[i];
|
||||
if (codepoint == 0)
|
||||
@@ -401,17 +433,6 @@ gtk_compose_list_format_for_gtk (GList *compose_list,
|
||||
if (p_n_index_stride)
|
||||
*p_n_index_stride = max_compose_len + 2;
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
codepoint = compose_data->value[1];
|
||||
if (codepoint > 0xffff)
|
||||
{
|
||||
compose_data->value[0] = codepoint / 0x10000;
|
||||
compose_data->value[1] = codepoint - codepoint / 0x10000 * 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
return compose_list;
|
||||
}
|
||||
|
||||
@@ -436,61 +457,6 @@ gtk_compose_data_compare (gpointer a,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_compose_list_print (GList *compose_list,
|
||||
int max_compose_len,
|
||||
int n_index_stride)
|
||||
{
|
||||
GList *list;
|
||||
int i, j;
|
||||
GtkComposeData *compose_data;
|
||||
int total_size = 0;
|
||||
gunichar upper;
|
||||
gunichar lower;
|
||||
const char *comment;
|
||||
const char *keyval;
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
g_printf (" ");
|
||||
|
||||
for (i = 0; i < max_compose_len; i++)
|
||||
{
|
||||
if (compose_data->sequence[i] == 0)
|
||||
{
|
||||
for (j = i; j < max_compose_len; j++)
|
||||
{
|
||||
if (j == max_compose_len - 1)
|
||||
g_printf ("0,\n");
|
||||
else
|
||||
g_printf ("0, ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
keyval = gdk_keyval_name (compose_data->sequence[i]);
|
||||
if (i == max_compose_len - 1)
|
||||
g_printf ("%s,\n", keyval ? keyval : "(null)");
|
||||
else
|
||||
g_printf ("%s, ", keyval ? keyval : "(null)");
|
||||
}
|
||||
upper = compose_data->value[0];
|
||||
lower = compose_data->value[1];
|
||||
comment = compose_data->comment;
|
||||
|
||||
if (list == g_list_last (compose_list))
|
||||
g_printf (" %#06X, %#06X /* %s */\n", upper, lower, comment);
|
||||
else
|
||||
g_printf (" %#06X, %#06X, /* %s */\n", upper, lower, comment);
|
||||
|
||||
total_size += n_index_stride;
|
||||
}
|
||||
|
||||
g_printerr ("TOTAL_SIZE: %d\nMAX_COMPOSE_LEN: %d\nN_INDEX_STRIDE: %d\n",
|
||||
total_size, max_compose_len, n_index_stride);
|
||||
}
|
||||
|
||||
/* Implemented from g_str_hash() */
|
||||
static guint32
|
||||
gtk_compose_table_data_hash (gconstpointer v, int length)
|
||||
@@ -546,6 +512,7 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
|
||||
guint16 max_seq_len = compose_table->max_seq_len;
|
||||
guint16 index_stride = max_seq_len + 2;
|
||||
guint16 n_seqs = compose_table->n_seqs;
|
||||
guint16 n_chars = compose_table->n_chars;
|
||||
guint32 i;
|
||||
|
||||
g_return_val_if_fail (compose_table != NULL, NULL);
|
||||
@@ -553,44 +520,34 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
|
||||
g_return_val_if_fail (index_stride > 0, NULL);
|
||||
|
||||
length = strlen (header);
|
||||
total_length = length + sizeof (guint16) * (3 + index_stride * n_seqs);
|
||||
total_length = length + sizeof (guint16) * (4 + index_stride * n_seqs) + n_chars;
|
||||
if (count)
|
||||
*count = total_length;
|
||||
|
||||
p = contents = g_slice_alloc (total_length);
|
||||
p = contents = g_malloc (total_length);
|
||||
|
||||
memcpy (p, header, length);
|
||||
p += length;
|
||||
|
||||
/* Copy by byte for endian */
|
||||
#define BYTE_COPY_FROM_BUF(element) \
|
||||
bytes = GUINT16_TO_BE ((element)); \
|
||||
memcpy (p, &bytes, length); \
|
||||
p += length; \
|
||||
if (p - contents > total_length) \
|
||||
{ \
|
||||
g_warning ("data size %lld is bigger than %" G_GSIZE_FORMAT, \
|
||||
(long long) (p - contents), total_length); \
|
||||
g_free (contents); \
|
||||
if (count) \
|
||||
{ \
|
||||
*count = 0; \
|
||||
} \
|
||||
return NULL; \
|
||||
}
|
||||
#define APPEND_GUINT16(elt) \
|
||||
bytes = GUINT16_TO_BE (elt); \
|
||||
memcpy (p, &bytes, sizeof (guint16)); \
|
||||
p += sizeof (guint16);
|
||||
|
||||
length = sizeof (guint16);
|
||||
|
||||
BYTE_COPY_FROM_BUF (version);
|
||||
BYTE_COPY_FROM_BUF (max_seq_len);
|
||||
BYTE_COPY_FROM_BUF (n_seqs);
|
||||
APPEND_GUINT16 (version);
|
||||
APPEND_GUINT16 (max_seq_len);
|
||||
APPEND_GUINT16 (n_seqs);
|
||||
APPEND_GUINT16 (n_chars);
|
||||
|
||||
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
|
||||
{
|
||||
BYTE_COPY_FROM_BUF (compose_table->data[i]);
|
||||
APPEND_GUINT16 (compose_table->data[i]);
|
||||
}
|
||||
|
||||
#undef BYTE_COPY_FROM_BUF
|
||||
if (compose_table->n_chars > 0)
|
||||
memcpy (p, compose_table->char_data, compose_table->n_chars);
|
||||
|
||||
#undef APPEND_GUINT16
|
||||
|
||||
return contents;
|
||||
}
|
||||
@@ -614,16 +571,17 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
GStatBuf original_buf;
|
||||
GStatBuf cache_buf;
|
||||
gsize total_length;
|
||||
gsize length;
|
||||
GError *error = NULL;
|
||||
guint16 bytes;
|
||||
guint16 version;
|
||||
guint16 max_seq_len;
|
||||
guint16 index_stride;
|
||||
guint16 n_seqs;
|
||||
guint16 n_chars;
|
||||
guint32 i;
|
||||
guint16 *gtk_compose_seqs = NULL;
|
||||
GtkComposeTable *retval;
|
||||
char *char_data = NULL;
|
||||
|
||||
hash = g_str_hash (compose_file);
|
||||
if ((path = gtk_compose_hash_get_cache_path (hash)) == NULL)
|
||||
@@ -642,16 +600,10 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
/* Copy by byte for endian */
|
||||
#define BYTE_COPY_TO_BUF(element) \
|
||||
memcpy (&bytes, p, length); \
|
||||
element = GUINT16_FROM_BE (bytes); \
|
||||
p += length; \
|
||||
if (p - contents > total_length) \
|
||||
{ \
|
||||
g_warning ("Broken cache content %s in %s", path, #element); \
|
||||
goto out_load_cache; \
|
||||
}
|
||||
#define GET_GUINT16(elt) \
|
||||
memcpy (&bytes, p, sizeof (guint16)); \
|
||||
elt = GUINT16_FROM_BE (bytes); \
|
||||
p += sizeof (guint16);
|
||||
|
||||
p = contents;
|
||||
if (g_ascii_strncasecmp (p, GTK_COMPOSE_TABLE_MAGIC,
|
||||
@@ -660,6 +612,7 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
g_warning ("The file is not a GtkComposeTable cache file %s", path);
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
p += strlen (GTK_COMPOSE_TABLE_MAGIC);
|
||||
if (p - contents > total_length)
|
||||
{
|
||||
@@ -667,9 +620,7 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
length = sizeof (guint16);
|
||||
|
||||
BYTE_COPY_TO_BUF (version);
|
||||
GET_GUINT16 (version);
|
||||
if (version != GTK_COMPOSE_TABLE_VERSION)
|
||||
{
|
||||
g_warning ("cache version is different %u != %u",
|
||||
@@ -677,8 +628,9 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
goto out_load_cache;
|
||||
}
|
||||
|
||||
BYTE_COPY_TO_BUF (max_seq_len);
|
||||
BYTE_COPY_TO_BUF (n_seqs);
|
||||
GET_GUINT16 (max_seq_len);
|
||||
GET_GUINT16 (n_seqs);
|
||||
GET_GUINT16 (n_chars);
|
||||
|
||||
if (max_seq_len == 0 || n_seqs == 0)
|
||||
{
|
||||
@@ -691,13 +643,22 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
|
||||
for (i = 0; i < (guint32) index_stride * n_seqs; i++)
|
||||
{
|
||||
BYTE_COPY_TO_BUF (gtk_compose_seqs[i]);
|
||||
GET_GUINT16 (gtk_compose_seqs[i]);
|
||||
}
|
||||
|
||||
if (n_chars > 0)
|
||||
{
|
||||
char_data = g_new (char, n_chars + 1);
|
||||
memcpy (char_data, p, n_chars);
|
||||
char_data[n_chars] = '\0';
|
||||
}
|
||||
|
||||
retval = g_new0 (GtkComposeTable, 1);
|
||||
retval->data = gtk_compose_seqs;
|
||||
retval->max_seq_len = max_seq_len;
|
||||
retval->n_seqs = n_seqs;
|
||||
retval->char_data = char_data;
|
||||
retval->n_chars = n_chars;
|
||||
retval->id = hash;
|
||||
|
||||
g_free (contents);
|
||||
@@ -705,10 +666,11 @@ gtk_compose_table_load_cache (const char *compose_file)
|
||||
|
||||
return retval;
|
||||
|
||||
#undef BYTE_COPY_TO_BUF
|
||||
#undef GET_GUINT16
|
||||
|
||||
out_load_cache:
|
||||
g_free (gtk_compose_seqs);
|
||||
g_free (char_data);
|
||||
g_free (contents);
|
||||
g_free (path);
|
||||
return NULL;
|
||||
@@ -739,7 +701,7 @@ gtk_compose_table_save_cache (GtkComposeTable *compose_table)
|
||||
}
|
||||
|
||||
out_save_cache:
|
||||
g_slice_free1 (length, contents);
|
||||
g_free (contents);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
@@ -756,6 +718,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
GList *list;
|
||||
GtkComposeData *compose_data;
|
||||
GtkComposeTable *retval = NULL;
|
||||
gunichar codepoint;
|
||||
GString *char_data;
|
||||
|
||||
g_return_val_if_fail (compose_list != NULL, NULL);
|
||||
|
||||
@@ -763,6 +727,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
|
||||
gtk_compose_seqs = g_new0 (guint16, length * n_index_stride);
|
||||
|
||||
char_data = g_string_new ("");
|
||||
|
||||
for (list = compose_list; list != NULL; list = list->next)
|
||||
{
|
||||
compose_data = list->data;
|
||||
@@ -776,8 +742,24 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
}
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->sequence[i];
|
||||
}
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->value[0];
|
||||
gtk_compose_seqs[n++] = (guint16) compose_data->value[1];
|
||||
|
||||
if (g_utf8_strlen (compose_data->value, -1) > 1)
|
||||
{
|
||||
if (char_data->len > 0)
|
||||
g_string_append_c (char_data, 0);
|
||||
|
||||
codepoint = char_data->len | (1 << 31);
|
||||
|
||||
g_string_append (char_data, compose_data->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
codepoint = g_utf8_get_char (compose_data->value);
|
||||
g_assert ((codepoint & (1 << 31)) == 0);
|
||||
}
|
||||
|
||||
gtk_compose_seqs[n++] = (codepoint & 0xffff0000) >> 16;
|
||||
gtk_compose_seqs[n++] = codepoint & 0xffff;
|
||||
}
|
||||
|
||||
retval = g_new0 (GtkComposeTable, 1);
|
||||
@@ -785,6 +767,8 @@ gtk_compose_table_new_with_list (GList *compose_list,
|
||||
retval->max_seq_len = max_compose_len;
|
||||
retval->n_seqs = length;
|
||||
retval->id = hash;
|
||||
retval->n_chars = char_data->len;
|
||||
retval->char_data = g_string_free (char_data, FALSE);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -816,9 +800,6 @@ gtk_compose_table_new_with_file (const char *compose_file)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_getenv ("GTK_COMPOSE_TABLE_PRINT") != NULL)
|
||||
gtk_compose_list_print (compose_list, max_compose_len, n_index_stride);
|
||||
|
||||
compose_table = gtk_compose_table_new_with_list (compose_list,
|
||||
max_compose_len,
|
||||
n_index_stride,
|
||||
@@ -841,9 +822,10 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
guint16 *gtk_compose_seqs = NULL;
|
||||
|
||||
g_return_val_if_fail (data != NULL, compose_tables);
|
||||
g_return_val_if_fail (max_seq_len <= GTK_MAX_COMPOSE_LEN, compose_tables);
|
||||
g_return_val_if_fail (max_seq_len >= 0, compose_tables);
|
||||
g_return_val_if_fail (n_seqs >= 0, compose_tables);
|
||||
|
||||
n_index_stride = MIN (max_seq_len, GTK_MAX_COMPOSE_LEN) + 2;
|
||||
n_index_stride = max_seq_len + 2;
|
||||
if (!g_size_checked_mul (&length, n_index_stride, n_seqs))
|
||||
{
|
||||
g_critical ("Overflow in the compose sequences");
|
||||
@@ -864,12 +846,14 @@ gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
compose_table->max_seq_len = max_seq_len;
|
||||
compose_table->n_seqs = n_seqs;
|
||||
compose_table->id = hash;
|
||||
compose_table->char_data = NULL;
|
||||
compose_table->n_chars = 0;
|
||||
|
||||
return g_slist_prepend (compose_tables, compose_table);
|
||||
}
|
||||
|
||||
GSList *
|
||||
gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file)
|
||||
{
|
||||
guint32 hash;
|
||||
@@ -891,3 +875,409 @@ gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
gtk_compose_table_save_cache (compose_table);
|
||||
return g_slist_prepend (compose_tables, compose_table);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq (const void *key, const void *value)
|
||||
{
|
||||
int i = 0;
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
while (keysyms[i])
|
||||
{
|
||||
if (keysyms[i] < seq[i])
|
||||
return -1;
|
||||
else if (keysyms[i] > seq[i])
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_compose_table_check:
|
||||
* @table: the table to check
|
||||
* @compose_buffer: the key vals to match
|
||||
* @n_compose: number of non-zero key vals in @compose_buffer
|
||||
* @compose_finish: (out): return location for whether there may be longer matches
|
||||
* @compose_match: (out): return location for whether there is a match
|
||||
* @output: (out) (caller-allocates): return location for the match values
|
||||
*
|
||||
* Looks for matches for a key sequence in @table.
|
||||
*
|
||||
* Returns: %TRUE if there were any matches, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
gtk_compose_table_check (const GtkComposeTable *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
GString *output)
|
||||
{
|
||||
int row_stride = table->max_seq_len + 2;
|
||||
guint16 *seq;
|
||||
|
||||
*compose_finish = FALSE;
|
||||
*compose_match = FALSE;
|
||||
|
||||
g_string_set_size (output, 0);
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq = bsearch (compose_buffer,
|
||||
table->data, table->n_seqs,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
guint16 *prev_seq;
|
||||
|
||||
/* Back up to the first sequence that matches to make sure
|
||||
* we find the exact match if there is one.
|
||||
*/
|
||||
while (seq > table->data)
|
||||
{
|
||||
prev_seq = seq - row_stride;
|
||||
if (compare_seq (compose_buffer, prev_seq) != 0)
|
||||
break;
|
||||
seq = prev_seq;
|
||||
}
|
||||
|
||||
if (n_compose == table->max_seq_len ||
|
||||
seq[n_compose] == 0) /* complete sequence */
|
||||
{
|
||||
guint16 *next_seq;
|
||||
gunichar value;
|
||||
|
||||
value = (seq[table->max_seq_len] << 16) | seq[table->max_seq_len + 1];
|
||||
if ((value & (1 << 31)) != 0)
|
||||
g_string_append (output, &table->char_data[value & ~(1 << 31)]);
|
||||
else
|
||||
g_string_append_unichar (output, value);
|
||||
|
||||
*compose_match = TRUE;
|
||||
|
||||
/* We found a tentative match. See if there are any longer
|
||||
* sequences containing this subsequence
|
||||
*/
|
||||
next_seq = seq + row_stride;
|
||||
if (next_seq < table->data + row_stride * table->n_seqs)
|
||||
{
|
||||
if (compare_seq (compose_buffer, next_seq) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*compose_finish = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq_index (const void *key, const void *value)
|
||||
{
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
if (keysyms[0] < seq[0])
|
||||
return -1;
|
||||
else if (keysyms[0] > seq[0])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char)
|
||||
{
|
||||
int row_stride;
|
||||
guint16 *seq_index;
|
||||
guint16 *seq;
|
||||
int i;
|
||||
gboolean match;
|
||||
gunichar value;
|
||||
|
||||
if (compose_finish)
|
||||
*compose_finish = FALSE;
|
||||
if (compose_match)
|
||||
*compose_match = FALSE;
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq_index = bsearch (compose_buffer,
|
||||
table->data,
|
||||
table->n_index_size,
|
||||
sizeof (guint16) * table->n_index_stride,
|
||||
compare_seq_index);
|
||||
|
||||
if (!seq_index)
|
||||
return FALSE;
|
||||
|
||||
if (n_compose == 1)
|
||||
return TRUE;
|
||||
|
||||
seq = NULL;
|
||||
match = FALSE;
|
||||
value = 0;
|
||||
|
||||
for (i = n_compose - 1; i < table->max_seq_len; i++)
|
||||
{
|
||||
row_stride = i + 1;
|
||||
|
||||
if (seq_index[i + 1] - seq_index[i] > 0)
|
||||
{
|
||||
seq = bsearch (compose_buffer + 1,
|
||||
table->data + seq_index[i],
|
||||
(seq_index[i + 1] - seq_index[i]) / row_stride,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
if (i == n_compose - 1)
|
||||
{
|
||||
value = seq[row_stride - 1];
|
||||
match = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
if (compose_finish)
|
||||
*compose_finish = TRUE;
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Checks if a keysym is a dead key.
|
||||
* Dead key keysym values are defined in ../gdk/gdkkeysyms.h and the
|
||||
* first is GDK_KEY_dead_grave. As X.Org is updated, more dead keys
|
||||
* are added and we need to update the upper limit.
|
||||
*/
|
||||
#define IS_DEAD_KEY(k) \
|
||||
((k) >= GDK_KEY_dead_grave && (k) <= GDK_KEY_dead_greek)
|
||||
|
||||
/* This function receives a sequence of Unicode characters and tries to
|
||||
* normalize it (NFC). We check for the case where the resulting string
|
||||
* has length 1 (single character).
|
||||
* NFC normalisation normally rearranges diacritic marks, unless these
|
||||
* belong to the same Canonical Combining Class.
|
||||
* If they belong to the same canonical combining class, we produce all
|
||||
* permutations of the diacritic marks, then attempt to normalize.
|
||||
*/
|
||||
static gboolean
|
||||
check_normalize_nfc (gunichar *combination_buffer,
|
||||
int n_compose)
|
||||
{
|
||||
gunichar *combination_buffer_temp;
|
||||
char *combination_utf8_temp = NULL;
|
||||
char *nfc_temp = NULL;
|
||||
int n_combinations;
|
||||
gunichar temp_swap;
|
||||
int i;
|
||||
|
||||
combination_buffer_temp = g_alloca (n_compose * sizeof (gunichar));
|
||||
|
||||
n_combinations = 1;
|
||||
|
||||
for (i = 1; i < n_compose; i++)
|
||||
n_combinations *= i;
|
||||
|
||||
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
|
||||
* We check if base character belongs to Greek Unicode block,
|
||||
* and if so, we replace tilde with perispomeni.
|
||||
*/
|
||||
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
|
||||
{
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
if (combination_buffer[i] == 0x303)
|
||||
combination_buffer[i] = 0x342;
|
||||
}
|
||||
|
||||
memcpy (combination_buffer_temp, combination_buffer, n_compose * sizeof (gunichar) );
|
||||
|
||||
for (i = 0; i < n_combinations; i++)
|
||||
{
|
||||
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
|
||||
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, n_compose, NULL, NULL, NULL);
|
||||
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (g_utf8_strlen (nfc_temp, -1) == 1)
|
||||
{
|
||||
memcpy (combination_buffer, combination_buffer_temp, n_compose * sizeof (gunichar) );
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
if (n_compose > 2)
|
||||
{
|
||||
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output_char)
|
||||
|
||||
{
|
||||
int i;
|
||||
gunichar *combination_buffer;
|
||||
char *combination_utf8, *nfc;
|
||||
|
||||
combination_buffer = alloca (sizeof (gunichar) * (n_compose + 1));
|
||||
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
|
||||
;
|
||||
if (i == n_compose)
|
||||
return TRUE;
|
||||
|
||||
if (i > 0 && i == n_compose - 1)
|
||||
{
|
||||
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
combination_buffer[n_compose] = 0;
|
||||
i--;
|
||||
while (i >= 0)
|
||||
{
|
||||
switch (compose_buffer[i])
|
||||
{
|
||||
#define CASE(keysym, unicode) \
|
||||
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
|
||||
|
||||
CASE (grave, 0x0300);
|
||||
CASE (acute, 0x0301);
|
||||
CASE (circumflex, 0x0302);
|
||||
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
|
||||
CASE (macron, 0x0304);
|
||||
CASE (breve, 0x0306);
|
||||
CASE (abovedot, 0x0307);
|
||||
CASE (diaeresis, 0x0308);
|
||||
CASE (abovering, 0x30A);
|
||||
CASE (hook, 0x0309);
|
||||
CASE (doubleacute, 0x030B);
|
||||
CASE (caron, 0x030C);
|
||||
CASE (cedilla, 0x0327);
|
||||
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
|
||||
CASE (iota, 0x0345);
|
||||
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (belowdot, 0x0323);
|
||||
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
|
||||
CASE (stroke, 0x335);
|
||||
CASE (abovecomma, 0x0313); /* Equivalent to psili */
|
||||
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
|
||||
CASE (doublegrave, 0x30F);
|
||||
CASE (belowring, 0x325);
|
||||
CASE (belowmacron, 0x331);
|
||||
CASE (belowcircumflex, 0x32D);
|
||||
CASE (belowtilde, 0x330);
|
||||
CASE (belowbreve, 0x32e);
|
||||
CASE (belowdiaeresis, 0x324);
|
||||
CASE (invertedbreve, 0x32f);
|
||||
CASE (belowcomma, 0x326);
|
||||
CASE (lowline, 0x332);
|
||||
CASE (aboveverticalline, 0x30D);
|
||||
CASE (belowverticalline, 0x329);
|
||||
CASE (longsolidusoverlay, 0x338);
|
||||
CASE (a, 0x363);
|
||||
CASE (A, 0x363);
|
||||
CASE (e, 0x364);
|
||||
CASE (E, 0x364);
|
||||
CASE (i, 0x365);
|
||||
CASE (I, 0x365);
|
||||
CASE (o, 0x366);
|
||||
CASE (O, 0x366);
|
||||
CASE (u, 0x367);
|
||||
CASE (U, 0x367);
|
||||
CASE (small_schwa, 0x1DEA);
|
||||
CASE (capital_schwa, 0x1DEA);
|
||||
#undef CASE
|
||||
default:
|
||||
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
/* If the buffer normalizes to a single character, then modify the order
|
||||
* of combination_buffer accordingly, if necessary, and return TRUE.
|
||||
*/
|
||||
if (check_normalize_nfc (combination_buffer, n_compose))
|
||||
{
|
||||
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
|
||||
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (output_char)
|
||||
*output_char = g_utf8_get_char (nfc);
|
||||
|
||||
g_free (combination_utf8);
|
||||
g_free (nfc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
+28
-7
@@ -29,8 +29,10 @@ typedef struct _GtkComposeTableCompact GtkComposeTableCompact;
|
||||
struct _GtkComposeTable
|
||||
{
|
||||
guint16 *data;
|
||||
char *char_data;
|
||||
int max_seq_len;
|
||||
int n_seqs;
|
||||
int n_chars;
|
||||
guint32 id;
|
||||
};
|
||||
|
||||
@@ -42,13 +44,32 @@ struct _GtkComposeTableCompact
|
||||
int n_index_stride;
|
||||
};
|
||||
|
||||
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
|
||||
GSList *gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
const guint16 *data,
|
||||
int max_seq_len,
|
||||
int n_seqs);
|
||||
GSList *gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file);
|
||||
GtkComposeTable * gtk_compose_table_new_with_file (const char *compose_file);
|
||||
GSList * gtk_compose_table_list_add_array (GSList *compose_tables,
|
||||
const guint16 *data,
|
||||
int max_seq_len,
|
||||
int n_seqs);
|
||||
GSList * gtk_compose_table_list_add_file (GSList *compose_tables,
|
||||
const char *compose_file);
|
||||
|
||||
gboolean gtk_compose_table_check (const GtkComposeTable *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
GString *output);
|
||||
|
||||
gboolean gtk_compose_table_compact_check (const GtkComposeTableCompact *table,
|
||||
const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char);
|
||||
|
||||
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ _gtk_css_border_value_parse (GtkCssParser *parser,
|
||||
}
|
||||
|
||||
result->is_computed = TRUE;
|
||||
for (; i < 4; i++)
|
||||
for (i = 0; i < 4; i++)
|
||||
if (result->values[i] && !gtk_css_value_is_computed (result->values[i]))
|
||||
{
|
||||
result->is_computed = FALSE;
|
||||
|
||||
+64
-20
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "gtkcssfiltervalueprivate.h"
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtkcssshadowvalueprivate.h"
|
||||
|
||||
typedef union _GtkCssFilter GtkCssFilter;
|
||||
|
||||
@@ -46,7 +47,7 @@ union _GtkCssFilter {
|
||||
struct {
|
||||
GtkCssFilterType type;
|
||||
GtkCssValue *value;
|
||||
} brightness, contrast, grayscale, hue_rotate, invert, opacity, saturate, sepia, blur;
|
||||
} blur, brightness, contrast, drop_shadow, grayscale, hue_rotate, invert, opacity, saturate, sepia;
|
||||
};
|
||||
|
||||
struct _GtkCssValue {
|
||||
@@ -90,8 +91,10 @@ gtk_css_filter_clear (GtkCssFilter *filter)
|
||||
case GTK_CSS_FILTER_BLUR:
|
||||
_gtk_css_value_unref (filter->blur.value);
|
||||
break;
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
_gtk_css_value_unref (filter->drop_shadow.value);
|
||||
break;
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -131,8 +134,10 @@ gtk_css_filter_init_identity (GtkCssFilter *filter,
|
||||
case GTK_CSS_FILTER_BLUR:
|
||||
filter->blur.value = _gtk_css_number_value_new (0, GTK_CSS_PX);
|
||||
break;
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
filter->drop_shadow.value = gtk_css_shadow_value_new_filter ();
|
||||
break;
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -347,8 +352,11 @@ gtk_css_filter_compute (GtkCssFilter *dest,
|
||||
dest->blur.value = _gtk_css_value_compute (src->blur.value, property_id, provider, style, parent_style);
|
||||
return dest->blur.value == src->blur.value;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
dest->drop_shadow.value = _gtk_css_value_compute (src->drop_shadow.value, property_id, provider, style, parent_style);
|
||||
return dest->drop_shadow.value == src->drop_shadow.value;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
@@ -428,8 +436,10 @@ gtk_css_filter_equal (const GtkCssFilter *filter1,
|
||||
case GTK_CSS_FILTER_BLUR:
|
||||
return _gtk_css_value_equal (filter1->blur.value, filter2->blur.value);
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
return _gtk_css_value_equal (filter1->drop_shadow.value, filter2->drop_shadow.value);
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
@@ -517,8 +527,11 @@ gtk_css_filter_transition (GtkCssFilter *result,
|
||||
result->blur.value = _gtk_css_value_transition (start->blur.value, end->blur.value, property_id, progress);
|
||||
break;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
result->drop_shadow.value = _gtk_css_value_transition (start->drop_shadow.value, end->drop_shadow.value, property_id, progress);
|
||||
break;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -663,8 +676,13 @@ gtk_css_filter_print (const GtkCssFilter *filter,
|
||||
g_string_append (string, ")");
|
||||
break;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
g_string_append (string, "drop-shadow(");
|
||||
_gtk_css_value_print (filter->drop_shadow.value, string);
|
||||
g_string_append (string, ")");
|
||||
break;
|
||||
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -709,12 +727,12 @@ static GtkCssValue *
|
||||
gtk_css_filter_value_alloc (guint n_filters)
|
||||
{
|
||||
GtkCssValue *result;
|
||||
|
||||
|
||||
g_return_val_if_fail (n_filters > 0, NULL);
|
||||
|
||||
|
||||
result = _gtk_css_value_alloc (>K_CSS_VALUE_FILTER, sizeof (GtkCssValue) + sizeof (GtkCssFilter) * (n_filters - 1));
|
||||
result->n_filters = n_filters;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -737,7 +755,7 @@ gtk_css_filter_parse_number (GtkCssParser *parser,
|
||||
{
|
||||
GtkCssValue **values = data;
|
||||
|
||||
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT);
|
||||
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT | GTK_CSS_POSITIVE_ONLY);
|
||||
if (values[n] == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -751,7 +769,7 @@ gtk_css_filter_parse_length (GtkCssParser *parser,
|
||||
{
|
||||
GtkCssValue **values = data;
|
||||
|
||||
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH);
|
||||
values[n] = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH | GTK_CSS_POSITIVE_ONLY);
|
||||
if (values[n] == NULL)
|
||||
return 0;
|
||||
|
||||
@@ -772,6 +790,20 @@ gtk_css_filter_parse_angle (GtkCssParser *parser,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_css_filter_parse_shadow (GtkCssParser *parser,
|
||||
guint n,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCssValue **values = data;
|
||||
|
||||
values[n] = gtk_css_shadow_value_parse_filter (parser);
|
||||
if (values[n] == NULL)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_filter_value_parse (GtkCssParser *parser)
|
||||
{
|
||||
@@ -861,6 +893,14 @@ gtk_css_filter_value_parse (GtkCssParser *parser)
|
||||
filter.type = GTK_CSS_FILTER_SEPIA;
|
||||
computed = computed && gtk_css_value_is_computed (filter.sepia.value);
|
||||
}
|
||||
else if (gtk_css_parser_has_function (parser, "drop-shadow"))
|
||||
{
|
||||
if (!gtk_css_parser_consume_function (parser, 1, 1, gtk_css_filter_parse_shadow, &filter.drop_shadow.value))
|
||||
goto fail;
|
||||
|
||||
filter.type = GTK_CSS_FILTER_DROP_SHADOW;
|
||||
computed = computed && gtk_css_value_is_computed (filter.drop_shadow.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
@@ -899,7 +939,6 @@ gtk_css_filter_value_push_snapshot (const GtkCssValue *filter,
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
int i, j;
|
||||
double radius;
|
||||
|
||||
if (gtk_css_filter_value_is_none (filter))
|
||||
return;
|
||||
@@ -909,16 +948,18 @@ gtk_css_filter_value_push_snapshot (const GtkCssValue *filter,
|
||||
{
|
||||
j = gtk_css_filter_value_compute_matrix (filter, i, &matrix, &offset);
|
||||
if (i < j)
|
||||
gtk_snapshot_push_color_matrix (snapshot,
|
||||
&matrix,
|
||||
&offset);
|
||||
gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset);
|
||||
|
||||
if (j < filter->n_filters)
|
||||
{
|
||||
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
|
||||
{
|
||||
radius = _gtk_css_number_value_get (filter->filters[j].blur.value, 100.0);
|
||||
gtk_snapshot_push_blur (snapshot, radius);
|
||||
double std_dev = _gtk_css_number_value_get (filter->filters[j].blur.value, 100.0);
|
||||
gtk_snapshot_push_blur (snapshot, 2 * std_dev);
|
||||
}
|
||||
else if (filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
|
||||
{
|
||||
gtk_css_shadow_value_push_snapshot (filter->filters[j].drop_shadow.value, snapshot);
|
||||
}
|
||||
else
|
||||
g_warning ("Don't know how to handle filter type %d", filter->filters[j].type);
|
||||
@@ -942,15 +983,18 @@ gtk_css_filter_value_pop_snapshot (const GtkCssValue *filter,
|
||||
{
|
||||
for (j = i; j < filter->n_filters; j++)
|
||||
{
|
||||
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
|
||||
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR ||
|
||||
filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < j)
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
if (j < filter->n_filters)
|
||||
if (filter->filters[j].type == GTK_CSS_FILTER_BLUR)
|
||||
gtk_snapshot_pop (snapshot);
|
||||
else if (filter->filters[j].type == GTK_CSS_FILTER_DROP_SHADOW)
|
||||
gtk_css_shadow_value_pop_snapshot (filter->filters[j].drop_shadow.value, snapshot);
|
||||
|
||||
i = j + 1;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "gtk/gtkcssimageurlprivate.h"
|
||||
#include "gtk/gtkcssimagescaledprivate.h"
|
||||
#include "gtk/gtkcssimagerecolorprivate.h"
|
||||
#include "gtk/gtkcssimagefilterprivate.h"
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (GtkCssImage, _gtk_css_image, G_TYPE_OBJECT)
|
||||
|
||||
@@ -524,6 +525,7 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
|
||||
{ "repeating-radial-gradient", _gtk_css_image_radial_get_type },
|
||||
{ "conic-gradient", gtk_css_image_conic_get_type },
|
||||
{ "cross-fade", gtk_css_image_cross_fade_get_type },
|
||||
{ "filter", gtk_css_image_filter_get_type },
|
||||
{ "image", _gtk_css_image_fallback_get_type }
|
||||
};
|
||||
guint i;
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright © 2021 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gtkcssimagefilterprivate.h"
|
||||
|
||||
#include "gtkcssfiltervalueprivate.h"
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GtkCssImageFilter, gtk_css_image_filter, GTK_TYPE_CSS_IMAGE)
|
||||
|
||||
static int
|
||||
gtk_css_image_filter_get_width (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return _gtk_css_image_get_width (self->image);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_css_image_filter_get_height (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return _gtk_css_image_get_height (self->image);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_filter_equal (GtkCssImage *image1,
|
||||
GtkCssImage *image2)
|
||||
{
|
||||
GtkCssImageFilter *filter1 = GTK_CSS_IMAGE_FILTER (image1);
|
||||
GtkCssImageFilter *filter2 = GTK_CSS_IMAGE_FILTER (image2);
|
||||
|
||||
return _gtk_css_image_equal (filter1->image, filter2->image) &&
|
||||
_gtk_css_value_equal (filter1->filter, filter2->filter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_filter_is_dynamic (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return gtk_css_image_is_dynamic (self->image);
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
gtk_css_image_filter_get_dynamic_image (GtkCssImage *image,
|
||||
gint64 monotonic_time)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return gtk_css_image_filter_new (gtk_css_image_get_dynamic_image (self->image, monotonic_time),
|
||||
self->filter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_filter_snapshot (GtkCssImage *image,
|
||||
GtkSnapshot *snapshot,
|
||||
double width,
|
||||
double height)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
gtk_css_filter_value_push_snapshot (self->filter, snapshot);
|
||||
gtk_css_image_snapshot (self->image, snapshot, width, height);
|
||||
gtk_css_filter_value_pop_snapshot (self->filter, snapshot);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_css_image_filter_parse_arg (GtkCssParser *parser,
|
||||
guint arg,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCssImageFilter *self = data;
|
||||
|
||||
switch (arg)
|
||||
{
|
||||
case 0:
|
||||
self->image = _gtk_css_image_new_parse (parser);
|
||||
if (self->image == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
case 1:
|
||||
self->filter = gtk_css_filter_value_parse (parser);
|
||||
if (self->filter == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_filter_parse (GtkCssImage *image,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
if (!gtk_css_parser_has_function (parser, "filter"))
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Expected 'filter('");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return gtk_css_parser_consume_function (parser, 2, 2, gtk_css_image_filter_parse_arg, image);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_filter_print (GtkCssImage *image,
|
||||
GString *string)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
g_string_append (string, "filter(");
|
||||
_gtk_css_image_print (self->image, string);
|
||||
g_string_append (string, ",");
|
||||
_gtk_css_value_print (self->filter, string);
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
static GtkCssImage *
|
||||
gtk_css_image_filter_compute (GtkCssImage *image,
|
||||
guint property_id,
|
||||
GtkStyleProvider *provider,
|
||||
GtkCssStyle *style,
|
||||
GtkCssStyle *parent_style)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return gtk_css_image_filter_new (_gtk_css_image_compute (self->image, property_id, provider, style, parent_style),
|
||||
_gtk_css_value_compute (self->filter, property_id, provider, style, parent_style));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_filter_dispose (GObject *object)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (object);
|
||||
|
||||
g_clear_object (&self->image);
|
||||
g_clear_pointer (&self->filter, _gtk_css_value_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_css_image_filter_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_image_filter_is_computed (GtkCssImage *image)
|
||||
{
|
||||
GtkCssImageFilter *self = GTK_CSS_IMAGE_FILTER (image);
|
||||
|
||||
return gtk_css_image_is_computed (self->image) &&
|
||||
gtk_css_value_is_computed (self->filter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_filter_class_init (GtkCssImageFilterClass *klass)
|
||||
{
|
||||
GtkCssImageClass *image_class = GTK_CSS_IMAGE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
image_class->get_width = gtk_css_image_filter_get_width;
|
||||
image_class->get_height = gtk_css_image_filter_get_height;
|
||||
image_class->compute = gtk_css_image_filter_compute;
|
||||
image_class->equal = gtk_css_image_filter_equal;
|
||||
image_class->snapshot = gtk_css_image_filter_snapshot;
|
||||
image_class->is_dynamic = gtk_css_image_filter_is_dynamic;
|
||||
image_class->get_dynamic_image = gtk_css_image_filter_get_dynamic_image;
|
||||
image_class->parse = gtk_css_image_filter_parse;
|
||||
image_class->print = gtk_css_image_filter_print;
|
||||
image_class->is_computed = gtk_css_image_filter_is_computed;
|
||||
|
||||
object_class->dispose = gtk_css_image_filter_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_image_filter_init (GtkCssImageFilter *self)
|
||||
{
|
||||
}
|
||||
|
||||
GtkCssImage *
|
||||
gtk_css_image_filter_new (GtkCssImage *image,
|
||||
GtkCssValue *filter)
|
||||
{
|
||||
GtkCssImageFilter *self;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CSS_IMAGE (image), NULL);
|
||||
|
||||
self = g_object_new (GTK_TYPE_CSS_IMAGE_FILTER, NULL);
|
||||
|
||||
self->image = g_object_ref (image);
|
||||
self->filter = gtk_css_value_ref (filter);
|
||||
|
||||
return GTK_CSS_IMAGE (self);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright © 2021 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CSS_IMAGE_FILTER_PRIVATE_H__
|
||||
#define __GTK_CSS_IMAGE_FILTER_PRIVATE_H__
|
||||
|
||||
#include "gtk/gtkcssimageprivate.h"
|
||||
#include "gtk/gtkcssvalueprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_CSS_IMAGE_FILTER (gtk_css_image_filter_get_type ())
|
||||
#define GTK_CSS_IMAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilter))
|
||||
#define GTK_CSS_IMAGE_FILTER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilterClass))
|
||||
#define GTK_IS_CSS_IMAGE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_CSS_IMAGE_FILTER))
|
||||
#define GTK_IS_CSS_IMAGE_FILTER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_CSS_IMAGE_FILTER))
|
||||
#define GTK_CSS_IMAGE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CSS_IMAGE_FILTER, GtkCssImageFilterClass))
|
||||
|
||||
typedef struct _GtkCssImageFilter GtkCssImageFilter;
|
||||
typedef struct _GtkCssImageFilterClass GtkCssImageFilterClass;
|
||||
|
||||
struct _GtkCssImageFilter
|
||||
{
|
||||
GtkCssImage parent;
|
||||
|
||||
GtkCssImage *image;
|
||||
GtkCssValue *filter;
|
||||
};
|
||||
|
||||
struct _GtkCssImageFilterClass
|
||||
{
|
||||
GtkCssImageClass parent_class;
|
||||
};
|
||||
|
||||
GType gtk_css_image_filter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkCssImage * gtk_css_image_filter_new (GtkCssImage *image,
|
||||
GtkCssValue *filter);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CSS_IMAGE_FILTER_PRIVATE_H__ */
|
||||
@@ -1073,11 +1073,8 @@ parse_n_plus_b (GtkCssParser *parser,
|
||||
*a = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
parse_a_n_plus_b (GtkCssParser *parser,
|
||||
int seen_sign,
|
||||
|
||||
+91
-31
@@ -44,12 +44,14 @@ typedef struct {
|
||||
|
||||
struct _GtkCssValue {
|
||||
GTK_CSS_VALUE_BASE
|
||||
guint is_filter : 1; /* values stored in radius are std_dev, for drop-shadow */
|
||||
guint n_shadows;
|
||||
ShadowValue shadows[1];
|
||||
};
|
||||
|
||||
static GtkCssValue * gtk_css_shadow_value_new (ShadowValue *shadows,
|
||||
guint n_shadows);
|
||||
guint n_shadows,
|
||||
gboolean is_filter);
|
||||
|
||||
static void
|
||||
shadow_value_for_transition (ShadowValue *result,
|
||||
@@ -133,7 +135,7 @@ gtk_css_value_shadow_compute (GtkCssValue *value,
|
||||
shadows[i].inset = shadow->inset;
|
||||
}
|
||||
|
||||
return gtk_css_shadow_value_new (shadows, value->n_shadows);
|
||||
return gtk_css_shadow_value_new (shadows, value->n_shadows, value->is_filter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -151,11 +153,11 @@ gtk_css_value_shadow_equal (const GtkCssValue *value1,
|
||||
const ShadowValue *shadow2 = &value2->shadows[i];
|
||||
|
||||
if (shadow1->inset != shadow2->inset ||
|
||||
_gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset) ||
|
||||
_gtk_css_value_equal (shadow1->voffset, shadow2->voffset) ||
|
||||
_gtk_css_value_equal (shadow1->radius, shadow2->radius) ||
|
||||
_gtk_css_value_equal (shadow1->spread, shadow2->spread) ||
|
||||
_gtk_css_value_equal (shadow1->color, shadow2->color))
|
||||
!_gtk_css_value_equal (shadow1->hoffset, shadow2->hoffset) ||
|
||||
!_gtk_css_value_equal (shadow1->voffset, shadow2->voffset) ||
|
||||
!_gtk_css_value_equal (shadow1->radius, shadow2->radius) ||
|
||||
!_gtk_css_value_equal (shadow1->spread, shadow2->spread) ||
|
||||
!_gtk_css_value_equal (shadow1->color, shadow2->color))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -172,9 +174,6 @@ gtk_css_value_shadow_transition (GtkCssValue *start,
|
||||
guint i, len;
|
||||
ShadowValue *shadows;
|
||||
|
||||
if (start->n_shadows != end->n_shadows)
|
||||
return NULL;
|
||||
|
||||
if (start->n_shadows > end->n_shadows)
|
||||
len = start->n_shadows;
|
||||
else
|
||||
@@ -230,7 +229,7 @@ gtk_css_value_shadow_transition (GtkCssValue *start,
|
||||
}
|
||||
}
|
||||
|
||||
return gtk_css_shadow_value_new (shadows, len);
|
||||
return gtk_css_shadow_value_new (shadows, len, start->is_filter);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -287,7 +286,7 @@ static const GtkCssValueClass GTK_CSS_VALUE_SHADOW = {
|
||||
gtk_css_value_shadow_print
|
||||
};
|
||||
|
||||
static GtkCssValue shadow_none_singleton = { >K_CSS_VALUE_SHADOW, 1, TRUE, 0 };
|
||||
static GtkCssValue shadow_none_singleton = { >K_CSS_VALUE_SHADOW, 1, TRUE, FALSE, 0 };
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_shadow_value_new_none (void)
|
||||
@@ -297,7 +296,8 @@ gtk_css_shadow_value_new_none (void)
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_shadow_value_new (ShadowValue *shadows,
|
||||
guint n_shadows)
|
||||
guint n_shadows,
|
||||
gboolean is_filter)
|
||||
{
|
||||
GtkCssValue *retval;
|
||||
guint i;
|
||||
@@ -307,6 +307,7 @@ gtk_css_shadow_value_new (ShadowValue *shadows,
|
||||
|
||||
retval = _gtk_css_value_alloc (>K_CSS_VALUE_SHADOW, sizeof (GtkCssValue) + sizeof (ShadowValue) * (n_shadows - 1));
|
||||
retval->n_shadows = n_shadows;
|
||||
retval->is_filter = is_filter;
|
||||
|
||||
memcpy (retval->shadows, shadows, sizeof (ShadowValue) * n_shadows);
|
||||
|
||||
@@ -329,6 +330,21 @@ gtk_css_shadow_value_new (ShadowValue *shadows,
|
||||
return retval;
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_shadow_value_new_filter (void)
|
||||
{
|
||||
ShadowValue value;
|
||||
|
||||
value.inset = FALSE;
|
||||
value.hoffset = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.voffset = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.radius = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.spread = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.color = _gtk_css_color_value_new_current_color ();
|
||||
|
||||
return gtk_css_shadow_value_new (&value, 1, TRUE);
|
||||
}
|
||||
|
||||
enum {
|
||||
HOFFSET,
|
||||
VOFFSET,
|
||||
@@ -419,9 +435,9 @@ parse_color (GtkCssParser *parser,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_gtk_css_shadow_value_parse_one (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode,
|
||||
ShadowValue *result)
|
||||
gtk_css_shadow_value_parse_one (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode,
|
||||
ShadowValue *result)
|
||||
{
|
||||
GtkCssValue *values[N_VALUES] = { NULL, };
|
||||
GtkCssValue *color = NULL;
|
||||
@@ -467,8 +483,8 @@ fail:
|
||||
|
||||
#define MAX_SHADOWS 64
|
||||
GtkCssValue *
|
||||
_gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode)
|
||||
gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode)
|
||||
{
|
||||
ShadowValue shadows[MAX_SHADOWS];
|
||||
int n_shadows = 0;
|
||||
@@ -478,7 +494,7 @@ _gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
return gtk_css_shadow_value_new_none ();
|
||||
|
||||
do {
|
||||
if (_gtk_css_shadow_value_parse_one (parser, box_shadow_mode, &shadows[n_shadows]))
|
||||
if (gtk_css_shadow_value_parse_one (parser, box_shadow_mode, &shadows[n_shadows]))
|
||||
n_shadows++;
|
||||
|
||||
if (n_shadows > MAX_SHADOWS)
|
||||
@@ -488,7 +504,7 @@ _gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
}
|
||||
} while (gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA));
|
||||
|
||||
return gtk_css_shadow_value_new (shadows, n_shadows);
|
||||
return gtk_css_shadow_value_new (shadows, n_shadows, FALSE);
|
||||
|
||||
fail:
|
||||
for (i = 0; i < n_shadows; i++)
|
||||
@@ -500,6 +516,17 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_shadow_value_parse_filter (GtkCssParser *parser)
|
||||
{
|
||||
ShadowValue shadow;
|
||||
|
||||
if (gtk_css_shadow_value_parse_one (parser, FALSE, &shadow))
|
||||
return gtk_css_shadow_value_new (&shadow, 1, TRUE);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_css_shadow_value_get_extents (const GtkCssValue *value,
|
||||
GtkBorder *border)
|
||||
@@ -515,6 +542,8 @@ gtk_css_shadow_value_get_extents (const GtkCssValue *value,
|
||||
|
||||
spread = _gtk_css_number_value_get (shadow->spread, 0);
|
||||
radius = _gtk_css_number_value_get (shadow->radius, 0);
|
||||
if (value->is_filter)
|
||||
radius = radius * 2;
|
||||
clip_radius = gsk_cairo_blur_compute_pixels (radius);
|
||||
hoffset = _gtk_css_number_value_get (shadow->hoffset, 0);
|
||||
voffset = _gtk_css_number_value_get (shadow->voffset, 0);
|
||||
@@ -532,6 +561,8 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
|
||||
const GskRoundedRect *border_box)
|
||||
{
|
||||
guint i;
|
||||
double dx, dy, spread, radius;
|
||||
const GdkRGBA *color;
|
||||
|
||||
g_return_if_fail (value->class == >K_CSS_VALUE_SHADOW);
|
||||
|
||||
@@ -542,17 +573,20 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue *value,
|
||||
if (shadow->inset)
|
||||
continue;
|
||||
|
||||
color = gtk_css_color_value_get_rgba (shadow->color);
|
||||
|
||||
/* We don't need to draw invisible shadows */
|
||||
if (gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
|
||||
if (gdk_rgba_is_clear (color))
|
||||
continue;
|
||||
|
||||
gtk_snapshot_append_outset_shadow (snapshot,
|
||||
border_box,
|
||||
gtk_css_color_value_get_rgba (shadow->color),
|
||||
_gtk_css_number_value_get (shadow->hoffset, 0),
|
||||
_gtk_css_number_value_get (shadow->voffset, 0),
|
||||
_gtk_css_number_value_get (shadow->spread, 0),
|
||||
_gtk_css_number_value_get (shadow->radius, 0));
|
||||
dx = _gtk_css_number_value_get (shadow->hoffset, 0);
|
||||
dy = _gtk_css_number_value_get (shadow->voffset, 0);
|
||||
spread = _gtk_css_number_value_get (shadow->spread, 0);
|
||||
radius = _gtk_css_number_value_get (shadow->radius, 0);
|
||||
if (value->is_filter)
|
||||
radius = 2 * radius;
|
||||
|
||||
gtk_snapshot_append_outset_shadow (snapshot, border_box, color, dx, dy, spread, radius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,15 +608,18 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue *value,
|
||||
if (!shadow->inset)
|
||||
continue;
|
||||
|
||||
color = gtk_css_color_value_get_rgba (shadow->color);
|
||||
|
||||
/* We don't need to draw invisible shadows */
|
||||
if (gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
|
||||
if (gdk_rgba_is_clear (color))
|
||||
continue;
|
||||
|
||||
dx = _gtk_css_number_value_get (shadow->hoffset, 0);
|
||||
dy = _gtk_css_number_value_get (shadow->voffset, 0);
|
||||
spread = _gtk_css_number_value_get (shadow->spread, 0);
|
||||
radius = _gtk_css_number_value_get (shadow->radius, 0);
|
||||
color = gtk_css_color_value_get_rgba (shadow->color);
|
||||
if (value->is_filter)
|
||||
radius = 2 * radius;
|
||||
|
||||
/* These are trivial to do with a color node */
|
||||
if (spread == 0 && radius == 0 &&
|
||||
@@ -678,7 +715,6 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
|
||||
gboolean need_shadow = FALSE;
|
||||
guint i;
|
||||
|
||||
/* TODO: We can save this as a flag once and then reuse it */
|
||||
for (i = 0; i < value->n_shadows; i++)
|
||||
{
|
||||
const ShadowValue *shadow = &value->shadows[i];
|
||||
@@ -702,6 +738,8 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
|
||||
shadows[i].dy = _gtk_css_number_value_get (shadow->voffset, 0);
|
||||
shadows[i].color = *gtk_css_color_value_get_rgba (shadow->color);
|
||||
shadows[i].radius = _gtk_css_number_value_get (shadow->radius, 0);
|
||||
if (value->is_filter)
|
||||
shadows[i].radius *= 2;
|
||||
}
|
||||
|
||||
gtk_snapshot_push_shadow (snapshot, shadows, value->n_shadows);
|
||||
@@ -709,3 +747,25 @@ gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
|
||||
|
||||
return need_shadow;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_css_shadow_value_pop_snapshot (const GtkCssValue *value,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
gboolean need_shadow = FALSE;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < value->n_shadows; i++)
|
||||
{
|
||||
const ShadowValue *shadow = &value->shadows[i];
|
||||
|
||||
if (!gdk_rgba_is_clear (gtk_css_color_value_get_rgba (shadow->color)))
|
||||
{
|
||||
need_shadow = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_shadow)
|
||||
gtk_snapshot_pop (snapshot);
|
||||
}
|
||||
|
||||
@@ -34,10 +34,12 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkCssValue * gtk_css_shadow_value_new_none (void);
|
||||
GtkCssValue * gtk_css_shadow_value_new_none (void);
|
||||
GtkCssValue * gtk_css_shadow_value_new_filter (void);
|
||||
|
||||
GtkCssValue * _gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
GtkCssValue * gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode);
|
||||
GtkCssValue * gtk_css_shadow_value_parse_filter (GtkCssParser *parser);
|
||||
|
||||
void gtk_css_shadow_value_get_extents (const GtkCssValue *shadow,
|
||||
GtkBorder *border);
|
||||
@@ -53,6 +55,8 @@ gboolean gtk_css_shadow_value_is_none (const GtkCssValue
|
||||
|
||||
gboolean gtk_css_shadow_value_push_snapshot (const GtkCssValue *value,
|
||||
GtkSnapshot *snapshot);
|
||||
void gtk_css_shadow_value_pop_snapshot (const GtkCssValue *value,
|
||||
GtkSnapshot *snapshot);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -512,14 +512,14 @@ static GtkCssValue *
|
||||
box_shadow_value_parse (GtkCssStyleProperty *property,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
return _gtk_css_shadow_value_parse (parser, TRUE);
|
||||
return gtk_css_shadow_value_parse (parser, TRUE);
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
shadow_value_parse (GtkCssStyleProperty *property,
|
||||
GtkCssParser *parser)
|
||||
{
|
||||
return _gtk_css_shadow_value_parse (parser, FALSE);
|
||||
return gtk_css_shadow_value_parse (parser, FALSE);
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
|
||||
+2
-2
@@ -260,8 +260,8 @@ _gtk_css_value_transition (GtkCssValue *start,
|
||||
guint property_id,
|
||||
double progress)
|
||||
{
|
||||
gtk_internal_return_val_if_fail (start != NULL, FALSE);
|
||||
gtk_internal_return_val_if_fail (end != NULL, FALSE);
|
||||
gtk_internal_return_val_if_fail (start != NULL, NULL);
|
||||
gtk_internal_return_val_if_fail (end != NULL, NULL);
|
||||
|
||||
if (start->class != end->class)
|
||||
return NULL;
|
||||
|
||||
+25
-25
@@ -48,20 +48,32 @@
|
||||
* SECTION:gtkdialog
|
||||
* @Short_description: Create popup windows
|
||||
* @Title: GtkDialog
|
||||
* @See_also: #GtkBox, #GtkWindow, #GtkButton
|
||||
* @See_also: #GtkWindow, #GtkMessageDialog
|
||||
*
|
||||
* Dialog boxes are a convenient way to prompt the user for a small amount
|
||||
* Dialogs are a convenient way to prompt the user for a small amount
|
||||
* of input, e.g. to display a message, ask a question, or anything else
|
||||
* that does not require extensive effort on the user’s part.
|
||||
*
|
||||
* GTK treats a dialog as a window split vertically. The top section is a
|
||||
* #GtkBox, and is where widgets such as a #GtkLabel or a #GtkEntry should
|
||||
* be packed. The bottom area is known as the
|
||||
* “action area”. This is generally used for
|
||||
* packing buttons into the dialog which may perform functions such as
|
||||
* cancel, ok, or apply.
|
||||
* The main area of a GtkDialog is called the "content area", and is yours
|
||||
* to populate with widgets such a #GtkLabel or #GtkEntry, to present
|
||||
* your information, questions, or tasks to the user. In addition, dialogs
|
||||
* allow you to add "action widgets". Most commonly, action widgets are
|
||||
* buttons. Depending on the platform, action widgets may be presented
|
||||
* in the header bar at the top of the window, or at the bottom of the window.
|
||||
* To add action widgets, use GtkDialog using gtk_dialog_new_with_buttons(),
|
||||
* gtk_dialog_add_button(), gtk_dialog_add_buttons(), or
|
||||
* gtk_dialog_add_action_widget().
|
||||
*
|
||||
* #GtkDialog boxes are created with a call to gtk_dialog_new() or
|
||||
* Clicking a button that was added as an action widget will emit the
|
||||
* #GtkDialog::response signal with a response ID that you specified.
|
||||
* GTK will never assign a meaning to positive response IDs; these are
|
||||
* entirely user-defined. But for convenience, you can use the response
|
||||
* IDs in the #GtkResponseType enumeration (these all have values less
|
||||
* than zero). If a dialog receives a delete event, the
|
||||
* #GtkDialog::response signal will be emitted with the
|
||||
* #GTK_RESPONSE_DELETE_EVENT response ID.
|
||||
*
|
||||
* Dialogs are created with a call to gtk_dialog_new() or
|
||||
* gtk_dialog_new_with_buttons(). gtk_dialog_new_with_buttons() is
|
||||
* recommended; it allows you to set the dialog title, some convenient
|
||||
* flags, and add simple buttons.
|
||||
@@ -72,20 +84,9 @@
|
||||
* gtk_dialog_new() into a #GtkWindow. When using gtk_dialog_new_with_buttons()
|
||||
* you can also pass the #GTK_DIALOG_MODAL flag to make a dialog modal.
|
||||
*
|
||||
* If you add buttons to #GtkDialog using gtk_dialog_new_with_buttons(),
|
||||
* gtk_dialog_add_button(), gtk_dialog_add_buttons(), or
|
||||
* gtk_dialog_add_action_widget(), clicking the button will emit a signal
|
||||
* called #GtkDialog::response with a response ID that you specified. GTK
|
||||
* will never assign a meaning to positive response IDs; these are entirely
|
||||
* user-defined. But for convenience, you can use the response IDs in the
|
||||
* #GtkResponseType enumeration (these all have values less than zero). If
|
||||
* a dialog receives a delete event, the #GtkDialog::response signal will
|
||||
* be emitted with a response ID of #GTK_RESPONSE_DELETE_EVENT.
|
||||
*
|
||||
* For the simple dialog in the following example, in reality you’d probably
|
||||
* use #GtkMessageDialog to save yourself some effort. But you’d need to
|
||||
* create the dialog contents manually if you had more than a simple message
|
||||
* in the dialog.
|
||||
* For the simple dialog in the following example, a #GtkMessageDialog would
|
||||
* save some effort. But you’d need to create the dialog contents manually if
|
||||
* you had more than a simple message in the dialog.
|
||||
*
|
||||
* An example for simple GtkDialog usage:
|
||||
* |[<!-- language="C" -->
|
||||
@@ -124,8 +125,7 @@
|
||||
* # GtkDialog as GtkBuildable
|
||||
*
|
||||
* The GtkDialog implementation of the #GtkBuildable interface exposes the
|
||||
* @content_area and @action_area as internal children with the names
|
||||
* “content_area” and “action_area”.
|
||||
* @content_area as an internal child with the name “content_area”.
|
||||
*
|
||||
* GtkDialog supports a custom <action-widgets> element, which can contain
|
||||
* multiple <action-widget> elements. The “response” attribute specifies a
|
||||
|
||||
+19
-2
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgesturesingleprivate.h"
|
||||
@@ -292,7 +292,7 @@ gtk_drag_source_update (GtkGesture *gesture,
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
if (gtk_drag_check_threshold (widget, source->start_x, source->start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, source->start_x, source->start_y, x, y))
|
||||
{
|
||||
gtk_drag_source_drag_begin (source);
|
||||
}
|
||||
@@ -796,3 +796,20 @@ gtk_drag_check_threshold (GtkWidget *widget,
|
||||
return (ABS (current_x - start_x) > drag_threshold ||
|
||||
ABS (current_y - start_y) > drag_threshold);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_drag_check_threshold_double (GtkWidget *widget,
|
||||
double start_x,
|
||||
double start_y,
|
||||
double current_x,
|
||||
double current_y)
|
||||
{
|
||||
int drag_threshold;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
drag_threshold = gtk_settings_get_dnd_drag_threshold (gtk_widget_get_settings (widget));
|
||||
|
||||
return (ABS (current_x - start_x) > drag_threshold ||
|
||||
ABS (current_y - start_y) > drag_threshold);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2020 Alexander Mikhaylenko
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_DRAG_SOURCE_PRIVATE_H__
|
||||
#define __GTK_DRAG_SOURCE_PRIVATE_H__
|
||||
|
||||
#include "gtkdragsource.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean gtk_drag_check_threshold_double (GtkWidget *widget,
|
||||
double start_x,
|
||||
double start_y,
|
||||
double current_x,
|
||||
double current_y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_DRAG_SOURCE_PRIVATE_H__ */
|
||||
+7
-6
@@ -65,7 +65,7 @@
|
||||
#include "gtkwindow.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
|
||||
@@ -1586,32 +1586,33 @@ icon_released_cb (GtkGestureClick *gesture,
|
||||
|
||||
static void
|
||||
icon_drag_update_cb (GtkGestureDrag *gesture,
|
||||
double x,
|
||||
double y,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
double start_x, start_y;
|
||||
GtkEntryIconPosition pos;
|
||||
EntryIconInfo *icon_info;
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
|
||||
icon_info = priv->icons[pos];
|
||||
|
||||
if (icon_info->content != NULL &&
|
||||
gtk_drag_check_threshold (icon_info->widget, start_x, start_y, x, y))
|
||||
gtk_drag_check_threshold_double (icon_info->widget, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
GdkDrag *drag;
|
||||
double start_x, start_y;
|
||||
|
||||
icon_info->in_drag = TRUE;
|
||||
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (entry)));
|
||||
device = gtk_gesture_get_device (GTK_GESTURE (gesture));
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
|
||||
drag = gdk_drag_begin (surface, device, icon_info->content, icon_info->actions, start_x, start_y);
|
||||
paintable = gtk_widget_paintable_new (icon_info->widget);
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
|
||||
|
||||
@@ -60,6 +60,11 @@
|
||||
* Showing, hiding and running the dialog is handled by the #GtkNativeDialog
|
||||
* functions.
|
||||
*
|
||||
* Note that unlike #GtkFileChooserDialog, #GtkFileChooserNative objects are
|
||||
* not toplevel widgets, and GTK does not keep them alive. It is your
|
||||
* responsibility to keep a reference until you are done with the
|
||||
* object.
|
||||
|
||||
* ## Typical usage ## {#gtkfilechoosernative-typical-usage}
|
||||
*
|
||||
* In the simplest of cases, you can the following code to use
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "gtkgesturelongpressprivate.h"
|
||||
#include "gtkgestureprivate.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
@@ -159,7 +159,7 @@ gtk_gesture_long_press_update (GtkGesture *gesture,
|
||||
priv = gtk_gesture_long_press_get_instance_private (GTK_GESTURE_LONG_PRESS (gesture));
|
||||
gtk_gesture_get_point (gesture, sequence, &x, &y);
|
||||
|
||||
if (gtk_drag_check_threshold (widget, priv->initial_x, priv->initial_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, priv->initial_x, priv->initial_y, x, y))
|
||||
{
|
||||
if (priv->timeout_id)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,65 @@
|
||||
* from the grid, use gtk_grid_remove(). The behaviour of GtkGrid when
|
||||
* several children occupy the same grid cell is undefined.
|
||||
*
|
||||
* # GtkGrid as GtkBuildable
|
||||
*
|
||||
* Every child in a GtkGrid has access to a custom #GtkBuildable element, called ´<layout>´.
|
||||
* It can by used to specify a position in the grid and optionally spans.
|
||||
* All properties that can be used in the ´<layout>´ element are implemented by #GtkGridLayoutChild.
|
||||
*
|
||||
* It is implemented by #GtkWidget using #GtkLayoutManager.
|
||||
*
|
||||
* To showcase it, here is a simple example:
|
||||
*
|
||||
* |[
|
||||
* <object class="GtkGrid" id="my_grid">
|
||||
* <child>
|
||||
* <object class="GtkButton" id="button1">
|
||||
* <property name="label">Button 1</property>
|
||||
* <layout>
|
||||
* <property name="column">0</property>
|
||||
* <property name="row">0</property>
|
||||
* </layout>
|
||||
* </object>
|
||||
* </child>
|
||||
* <child>
|
||||
* <object class="GtkButton" id="button2">
|
||||
* <property name="label">Button 2</property>
|
||||
* <layout>
|
||||
* <property name="column">1</property>
|
||||
* <property name="row">0</property>
|
||||
* </layout>
|
||||
* </object>
|
||||
* </child>
|
||||
* <child>
|
||||
* <object class="GtkButton" id="button3">
|
||||
* <property name="label">Button 3</property>
|
||||
* <layout>
|
||||
* <property name="column">2</property>
|
||||
* <property name="row">0</property>
|
||||
* <property name="row-span">2</property>
|
||||
* </layout>
|
||||
* </object>
|
||||
* </child>
|
||||
* <child>
|
||||
* <object class="GtkButton" id="button4">
|
||||
* <property name="label">Button 4</property>
|
||||
* <layout>
|
||||
* <property name="column">0</property>
|
||||
* <property name="row">1</property>
|
||||
* <property name="column-span">2</property>
|
||||
* </layout>
|
||||
* </object>
|
||||
* </child>
|
||||
* </object>
|
||||
* ]|
|
||||
*
|
||||
* It organizes the first two buttons side-by-side in one cell each.
|
||||
* The third button is in the last column but spans across two rows.
|
||||
* This is defined by the ´row-span´ property.
|
||||
* The last button is located in the second row and spans across two columns,
|
||||
* which is defined by the ´column-span´ property.
|
||||
*
|
||||
* # CSS nodes
|
||||
*
|
||||
* GtkGrid uses a single CSS node with name `grid`.
|
||||
|
||||
+5
-5
@@ -26,7 +26,7 @@
|
||||
#include "gtkcellrenderer.h"
|
||||
#include "gtkcellrendererpixbuf.h"
|
||||
#include "gtkcellrenderertext.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkentry.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@@ -5884,10 +5884,10 @@ gtk_icon_view_maybe_begin_drag (GtkIconView *icon_view,
|
||||
if (icon_view->priv->pressed_button < 0)
|
||||
goto out;
|
||||
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (icon_view),
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
x, y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (icon_view),
|
||||
icon_view->priv->press_start_x,
|
||||
icon_view->priv->press_start_y,
|
||||
x, y))
|
||||
goto out;
|
||||
|
||||
model = gtk_icon_view_get_model (icon_view);
|
||||
|
||||
@@ -133,8 +133,8 @@ struct _GtkIconViewPrivate
|
||||
/* Drag-and-drop. */
|
||||
GdkModifierType start_button_mask;
|
||||
int pressed_button;
|
||||
int press_start_x;
|
||||
int press_start_y;
|
||||
double press_start_x;
|
||||
double press_start_y;
|
||||
|
||||
GdkContentFormats *source_formats;
|
||||
GtkDropTargetAsync *dest;
|
||||
|
||||
+176
-486
@@ -32,7 +32,6 @@
|
||||
#include "gtkcomposetable.h"
|
||||
#include "gtkimmoduleprivate.h"
|
||||
|
||||
#include "gtkimcontextsimpleprivate.h"
|
||||
#include "gtkimcontextsimpleseqs.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
@@ -61,8 +60,9 @@
|
||||
|
||||
struct _GtkIMContextSimplePrivate
|
||||
{
|
||||
guint16 compose_buffer[GTK_MAX_COMPOSE_LEN + 1];
|
||||
gunichar tentative_match;
|
||||
guint16 *compose_buffer;
|
||||
int compose_buffer_len;
|
||||
GString *tentative_match;
|
||||
int tentative_match_len;
|
||||
|
||||
guint in_hex_sequence : 1;
|
||||
@@ -174,8 +174,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
g_free (path);
|
||||
return;
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
|
||||
home = g_get_home_dir ();
|
||||
if (home == NULL)
|
||||
@@ -190,8 +189,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
g_free (path);
|
||||
return;
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
|
||||
locale = g_getenv ("LC_CTYPE");
|
||||
if (locale == NULL)
|
||||
@@ -224,8 +222,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
|
||||
if (g_file_test (path, G_FILE_TEST_EXISTS))
|
||||
break;
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
}
|
||||
|
||||
g_free (x11_compose_file_dir);
|
||||
@@ -237,8 +234,7 @@ gtk_im_context_simple_init_compose_table (void)
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables, path);
|
||||
G_UNLOCK (global_tables);
|
||||
}
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
g_clear_pointer (&path, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -271,14 +267,27 @@ init_compose_table_async (GCancellable *cancellable,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_init (GtkIMContextSimple *im_context_simple)
|
||||
gtk_im_context_simple_init (GtkIMContextSimple *context_simple)
|
||||
{
|
||||
im_context_simple->priv = gtk_im_context_simple_get_instance_private (im_context_simple);
|
||||
GtkIMContextSimplePrivate *priv;
|
||||
|
||||
priv = context_simple->priv = gtk_im_context_simple_get_instance_private (context_simple);
|
||||
|
||||
priv->compose_buffer_len = gtk_compose_table_compact.max_seq_len + 1;
|
||||
priv->compose_buffer = g_new0 (guint16, priv->compose_buffer_len);
|
||||
priv->tentative_match = g_string_new ("");
|
||||
priv->tentative_match_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_finalize (GObject *obj)
|
||||
{
|
||||
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (obj);
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;;
|
||||
|
||||
g_free (priv->compose_buffer);
|
||||
g_string_free (priv->tentative_match, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gtk_im_context_simple_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
@@ -296,396 +305,29 @@ gtk_im_context_simple_new (void)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_im_context_simple_commit_char (GtkIMContext *context,
|
||||
gunichar ch)
|
||||
{
|
||||
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;
|
||||
char buf[10];
|
||||
int len;
|
||||
|
||||
g_return_if_fail (g_unichar_validate (ch));
|
||||
|
||||
len = g_unichar_to_utf8 (ch, buf);
|
||||
buf[len] = '\0';
|
||||
|
||||
if (priv->tentative_match || priv->in_hex_sequence)
|
||||
{
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
priv->tentative_match_len = 0;
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
g_signal_emit_by_name (context_simple, "preedit-end");
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (context, "commit", &buf);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq_index (const void *key, const void *value)
|
||||
{
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
if (keysyms[0] < seq[0])
|
||||
return -1;
|
||||
else if (keysyms[0] > seq[0])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_seq (const void *key, const void *value)
|
||||
{
|
||||
int i = 0;
|
||||
const guint16 *keysyms = key;
|
||||
const guint16 *seq = value;
|
||||
|
||||
while (keysyms[i])
|
||||
{
|
||||
if (keysyms[i] < seq[i])
|
||||
return -1;
|
||||
else if (keysyms[i] > seq[i])
|
||||
return 1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_table (GtkIMContextSimple *context_simple,
|
||||
const GtkComposeTable *table,
|
||||
int n_compose)
|
||||
gtk_im_context_simple_commit_string (GtkIMContextSimple *context_simple,
|
||||
const char *str)
|
||||
{
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;
|
||||
int row_stride = table->max_seq_len + 2;
|
||||
guint16 *seq;
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val. */
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq = bsearch (priv->compose_buffer,
|
||||
table->data, table->n_seqs,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
if (seq)
|
||||
{
|
||||
guint16 *prev_seq;
|
||||
|
||||
/* Back up to the first sequence that matches to make sure
|
||||
* we find the exact match if there is one.
|
||||
*/
|
||||
while (seq > table->data)
|
||||
{
|
||||
prev_seq = seq - row_stride;
|
||||
if (compare_seq (priv->compose_buffer, prev_seq) != 0)
|
||||
break;
|
||||
seq = prev_seq;
|
||||
}
|
||||
|
||||
if (n_compose == table->max_seq_len ||
|
||||
seq[n_compose] == 0) /* complete sequence */
|
||||
{
|
||||
guint16 *next_seq;
|
||||
gunichar value =
|
||||
0x10000 * seq[table->max_seq_len] + seq[table->max_seq_len + 1];
|
||||
|
||||
/* We found a tentative match. See if there are any longer
|
||||
* sequences containing this subsequence
|
||||
*/
|
||||
next_seq = seq + row_stride;
|
||||
if (next_seq < table->data + row_stride * table->n_seqs)
|
||||
{
|
||||
if (compare_seq (priv->compose_buffer, next_seq) == 0)
|
||||
{
|
||||
priv->tentative_match = value;
|
||||
priv->tentative_match_len = n_compose;
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), value);
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
g_signal_emit_by_name (context_simple, "preedit-end");
|
||||
g_signal_emit_by_name (context_simple, "commit", str);
|
||||
}
|
||||
|
||||
/* Checks if a keysym is a dead key. Dead key keysym values are defined in
|
||||
* ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated,
|
||||
* more dead keys are added and we need to update the upper limit.
|
||||
* Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with
|
||||
* a temporary issue in the X.Org header files.
|
||||
* In future versions it will be just the keysym (no +1).
|
||||
*/
|
||||
#define IS_DEAD_KEY(k) \
|
||||
((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
|
||||
|
||||
gboolean
|
||||
gtk_check_compact_table (const GtkComposeTableCompact *table,
|
||||
guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char)
|
||||
static void
|
||||
gtk_im_context_simple_commit_char (GtkIMContextSimple *context_simple,
|
||||
gunichar ch)
|
||||
{
|
||||
int row_stride;
|
||||
guint16 *seq_index;
|
||||
guint16 *seq;
|
||||
int i;
|
||||
gboolean match;
|
||||
gunichar value;
|
||||
char buf[8] = { 0, };
|
||||
|
||||
if (compose_finish)
|
||||
*compose_finish = FALSE;
|
||||
if (compose_match)
|
||||
*compose_match = FALSE;
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
g_unichar_to_utf8 (ch, buf);
|
||||
|
||||
/* Will never match, if the sequence in the compose buffer is longer
|
||||
* than the sequences in the table. Further, compare_seq (key, val)
|
||||
* will overrun val if key is longer than val.
|
||||
*/
|
||||
if (n_compose > table->max_seq_len)
|
||||
return FALSE;
|
||||
|
||||
seq_index = bsearch (compose_buffer,
|
||||
table->data,
|
||||
table->n_index_size,
|
||||
sizeof (guint16) * table->n_index_stride,
|
||||
compare_seq_index);
|
||||
|
||||
if (!seq_index)
|
||||
return FALSE;
|
||||
|
||||
if (seq_index && n_compose == 1)
|
||||
return TRUE;
|
||||
|
||||
seq = NULL;
|
||||
match = FALSE;
|
||||
value = 0;
|
||||
|
||||
for (i = n_compose - 1; i < table->max_seq_len; i++)
|
||||
{
|
||||
row_stride = i + 1;
|
||||
|
||||
if (seq_index[i + 1] - seq_index[i] > 0)
|
||||
{
|
||||
seq = bsearch (compose_buffer + 1,
|
||||
table->data + seq_index[i],
|
||||
(seq_index[i + 1] - seq_index[i]) / row_stride,
|
||||
sizeof (guint16) * row_stride,
|
||||
compare_seq);
|
||||
|
||||
if (seq)
|
||||
{
|
||||
if (i == n_compose - 1)
|
||||
{
|
||||
value = seq[row_stride - 1];
|
||||
match = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
if (compose_match)
|
||||
*compose_match = TRUE;
|
||||
if (compose_finish)
|
||||
*compose_finish = TRUE;
|
||||
if (output_char)
|
||||
*output_char = value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This function receives a sequence of Unicode characters and tries to
|
||||
* normalize it (NFC). We check for the case where the resulting string
|
||||
* has length 1 (single character).
|
||||
* NFC normalisation normally rearranges diacritic marks, unless these
|
||||
* belong to the same Canonical Combining Class.
|
||||
* If they belong to the same canonical combining class, we produce all
|
||||
* permutations of the diacritic marks, then attempt to normalize.
|
||||
*/
|
||||
static gboolean
|
||||
check_normalize_nfc (gunichar* combination_buffer, int n_compose)
|
||||
{
|
||||
gunichar combination_buffer_temp[GTK_MAX_COMPOSE_LEN];
|
||||
char *combination_utf8_temp = NULL;
|
||||
char *nfc_temp = NULL;
|
||||
int n_combinations;
|
||||
gunichar temp_swap;
|
||||
int i;
|
||||
|
||||
n_combinations = 1;
|
||||
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
n_combinations *= i;
|
||||
|
||||
/* Xorg reuses dead_tilde for the perispomeni diacritic mark.
|
||||
* We check if base character belongs to Greek Unicode block,
|
||||
* and if so, we replace tilde with perispomeni.
|
||||
*/
|
||||
if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF)
|
||||
{
|
||||
for (i = 1; i < n_compose; i++ )
|
||||
if (combination_buffer[i] == 0x303)
|
||||
combination_buffer[i] = 0x342;
|
||||
}
|
||||
|
||||
memcpy (combination_buffer_temp, combination_buffer, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
|
||||
|
||||
for (i = 0; i < n_combinations; i++ )
|
||||
{
|
||||
g_unicode_canonical_ordering (combination_buffer_temp, n_compose);
|
||||
combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, NULL, NULL, NULL);
|
||||
nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (g_utf8_strlen (nfc_temp, -1) == 1)
|
||||
{
|
||||
memcpy (combination_buffer, combination_buffer_temp, GTK_MAX_COMPOSE_LEN * sizeof (gunichar) );
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_free (combination_utf8_temp);
|
||||
g_free (nfc_temp);
|
||||
|
||||
if (n_compose > 2)
|
||||
{
|
||||
temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
|
||||
combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output_char)
|
||||
|
||||
{
|
||||
int i;
|
||||
gunichar combination_buffer[GTK_MAX_COMPOSE_LEN];
|
||||
char *combination_utf8, *nfc;
|
||||
|
||||
if (output_char)
|
||||
*output_char = 0;
|
||||
|
||||
if (n_compose >= GTK_MAX_COMPOSE_LEN)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++)
|
||||
;
|
||||
if (i == n_compose)
|
||||
return TRUE;
|
||||
|
||||
if (i > 0 && i == n_compose - 1)
|
||||
{
|
||||
combination_buffer[0] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
combination_buffer[n_compose] = 0;
|
||||
i--;
|
||||
while (i >= 0)
|
||||
{
|
||||
switch (compose_buffer[i])
|
||||
{
|
||||
#define CASE(keysym, unicode) \
|
||||
case GDK_KEY_dead_##keysym: combination_buffer[i+1] = unicode; break
|
||||
|
||||
CASE (grave, 0x0300);
|
||||
CASE (acute, 0x0301);
|
||||
CASE (circumflex, 0x0302);
|
||||
CASE (tilde, 0x0303); /* Also used with perispomeni, 0x342. */
|
||||
CASE (macron, 0x0304);
|
||||
CASE (breve, 0x0306);
|
||||
CASE (abovedot, 0x0307);
|
||||
CASE (diaeresis, 0x0308);
|
||||
CASE (hook, 0x0309);
|
||||
CASE (abovering, 0x030A);
|
||||
CASE (doubleacute, 0x030B);
|
||||
CASE (caron, 0x030C);
|
||||
CASE (abovecomma, 0x0313); /* Equivalent to psili */
|
||||
CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
|
||||
CASE (horn, 0x031B); /* Legacy use for psili, 0x313 (or 0x343). */
|
||||
CASE (belowdot, 0x0323);
|
||||
CASE (cedilla, 0x0327);
|
||||
CASE (ogonek, 0x0328); /* Legacy use for dasia, 0x314.*/
|
||||
CASE (iota, 0x0345);
|
||||
CASE (voiced_sound, 0x3099); /* Per Markus Kuhn keysyms.txt file. */
|
||||
CASE (semivoiced_sound, 0x309A); /* Per Markus Kuhn keysyms.txt file. */
|
||||
|
||||
/* The following cases are to be removed once xkeyboard-config,
|
||||
* xorg are fully updated.
|
||||
*/
|
||||
/* Workaround for typo in 1.4.x xserver-xorg */
|
||||
case 0xfe66: combination_buffer[i+1] = 0x314; break;
|
||||
/* CASE (dasia, 0x314); */
|
||||
/* CASE (perispomeni, 0x342); */
|
||||
/* CASE (psili, 0x343); */
|
||||
#undef CASE
|
||||
default:
|
||||
combination_buffer[i+1] = gdk_keyval_to_unicode (compose_buffer[i]);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
/* If the buffer normalizes to a single character, then modify the order
|
||||
* of combination_buffer accordingly, if necessary, and return TRUE.
|
||||
*/
|
||||
if (check_normalize_nfc (combination_buffer, n_compose))
|
||||
{
|
||||
combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL);
|
||||
nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC);
|
||||
|
||||
if (output_char)
|
||||
*output_char = g_utf8_get_char (nfc);
|
||||
|
||||
g_free (combination_utf8);
|
||||
g_free (nfc);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
gtk_im_context_simple_commit_string (context_simple, buf);
|
||||
}
|
||||
|
||||
/* In addition to the table-driven sequences, we allow Unicode hex
|
||||
@@ -716,7 +358,7 @@ check_hex (GtkIMContextSimple *context_simple,
|
||||
char *nptr = NULL;
|
||||
char buf[7];
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
@@ -756,7 +398,8 @@ check_hex (GtkIMContextSimple *context_simple,
|
||||
|
||||
if (g_unichar_validate (n))
|
||||
{
|
||||
priv->tentative_match = n;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
g_string_append_unichar (priv->tentative_match, n);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
|
||||
@@ -792,18 +435,25 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
|
||||
/* No compose sequences found, check first if we have a partial
|
||||
* match pending.
|
||||
*/
|
||||
if (priv->tentative_match)
|
||||
if (priv->tentative_match_len > 0)
|
||||
{
|
||||
int len = priv->tentative_match_len;
|
||||
int i;
|
||||
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
guint16 *compose_buffer;
|
||||
char *str;
|
||||
|
||||
compose_buffer = alloca (sizeof (guint16) * priv->compose_buffer_len);
|
||||
|
||||
memcpy (compose_buffer, priv->compose_buffer, sizeof (guint16) * priv->compose_buffer_len);
|
||||
|
||||
str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
|
||||
for (i = 0; i < n_compose - len - 1; i++)
|
||||
{
|
||||
{
|
||||
GdkTranslatedKey translated;
|
||||
translated.keyval = priv->compose_buffer[len + i];
|
||||
translated.keyval = compose_buffer[len + i];
|
||||
translated.consumed = 0;
|
||||
translated.layout = 0;
|
||||
translated.level = 0;
|
||||
@@ -811,7 +461,7 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
|
||||
gdk_event_get_surface (event),
|
||||
gdk_event_get_device (event),
|
||||
gdk_event_get_time (event),
|
||||
priv->compose_buffer[len + i],
|
||||
compose_buffer[len + i],
|
||||
gdk_event_get_modifier_state (event),
|
||||
FALSE,
|
||||
&translated,
|
||||
@@ -831,13 +481,15 @@ no_sequence_matches (GtkIMContextSimple *context_simple,
|
||||
if (n_compose > 1) /* Invalid sequence */
|
||||
{
|
||||
beep_surface (gdk_event_get_surface (event));
|
||||
g_signal_emit_by_name (context, "preedit-changed");
|
||||
g_signal_emit_by_name (context, "preedit-end");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ch = gdk_keyval_to_unicode (keyval);
|
||||
if (ch != 0 && !g_unichar_iscntrl (ch))
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, ch);
|
||||
gtk_im_context_simple_commit_char (context_simple, ch);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@@ -921,7 +573,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
gunichar output_char;
|
||||
guint keyval, state;
|
||||
|
||||
while (priv->compose_buffer[n_compose] != 0)
|
||||
while (priv->compose_buffer[n_compose] != 0 && n_compose < priv->compose_buffer_len)
|
||||
n_compose++;
|
||||
|
||||
keyval = gdk_key_event_get_keyval (event);
|
||||
@@ -933,11 +585,11 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
(keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R ||
|
||||
keyval == GDK_KEY_Shift_L || keyval == GDK_KEY_Shift_R))
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
priv->compose_buffer[0] = 0;
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -952,7 +604,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* invalid hex sequence */
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
@@ -1036,14 +688,27 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!priv->in_hex_sequence && n_compose > 0 && is_backspace)
|
||||
{
|
||||
n_compose--;
|
||||
priv->compose_buffer[n_compose] = 0;
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
|
||||
if (n_compose == 0)
|
||||
g_signal_emit_by_name (context_simple, "preedit-end");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check for hex sequence restart */
|
||||
if (priv->in_hex_sequence && have_hex_mods && is_hex_start)
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
priv->compose_buffer[0] = 0;
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1051,7 +716,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
if (n_compose > 0)
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
@@ -1063,7 +728,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
priv->compose_buffer[0] = 0;
|
||||
priv->in_hex_sequence = TRUE;
|
||||
priv->modifiers_dropped = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
|
||||
g_signal_emit_by_name (context_simple, "preedit-start");
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
@@ -1074,7 +739,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* Then, check for compose sequences */
|
||||
if (priv->in_hex_sequence)
|
||||
{
|
||||
if (hex_keyval)
|
||||
if (hex_keyval && n_compose < 6)
|
||||
priv->compose_buffer[n_compose++] = hex_keyval;
|
||||
else if (is_escape)
|
||||
{
|
||||
@@ -1083,13 +748,21 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
}
|
||||
else if (!is_hex_end)
|
||||
{
|
||||
/* non-hex character in hex sequence */
|
||||
/* non-hex character in hex sequence, or sequence too long */
|
||||
beep_surface (surface);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
priv->compose_buffer[n_compose++] = keyval;
|
||||
{
|
||||
if (n_compose + 1 == priv->compose_buffer_len)
|
||||
{
|
||||
priv->compose_buffer_len += 1;
|
||||
priv->compose_buffer = g_renew (guint16, priv->compose_buffer, priv->compose_buffer_len);
|
||||
}
|
||||
|
||||
priv->compose_buffer[n_compose++] = keyval;
|
||||
}
|
||||
|
||||
priv->compose_buffer[n_compose] = 0;
|
||||
|
||||
@@ -1101,18 +774,18 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
/* space or return ends the sequence, and we eat the key */
|
||||
if (n_compose > 0 && is_hex_end)
|
||||
{
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
if (priv->tentative_match->len > 0)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
priv->compose_buffer[0] = 0;
|
||||
char *str = g_strdup (priv->tentative_match->str);
|
||||
gtk_im_context_simple_commit_string (context_simple, str);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid hex sequence */
|
||||
beep_surface (surface);
|
||||
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
@@ -1131,65 +804,81 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
else
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
GString *output;
|
||||
|
||||
output = g_string_new ("");
|
||||
|
||||
G_LOCK (global_tables);
|
||||
|
||||
tmp_list = global_tables;
|
||||
while (tmp_list)
|
||||
{
|
||||
if (check_table (context_simple, tmp_list->data, n_compose))
|
||||
if (gtk_compose_table_check ((GtkComposeTable *)tmp_list->data,
|
||||
priv->compose_buffer, n_compose,
|
||||
&compose_finish, &compose_match,
|
||||
output))
|
||||
{
|
||||
if (compose_finish)
|
||||
{
|
||||
if (compose_match)
|
||||
gtk_im_context_simple_commit_string (context_simple, output->str);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
g_string_assign (priv->tentative_match, output->str);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
G_UNLOCK (global_tables);
|
||||
|
||||
g_string_free (output, TRUE);
|
||||
|
||||
if (success)
|
||||
return TRUE;
|
||||
|
||||
if (gtk_check_compact_table (>k_compose_table_compact,
|
||||
priv->compose_buffer,
|
||||
n_compose, &compose_finish,
|
||||
&compose_match, &output_char))
|
||||
if (gtk_compose_table_compact_check (>k_compose_table_compact,
|
||||
priv->compose_buffer, n_compose,
|
||||
&compose_finish, &compose_match,
|
||||
&output_char))
|
||||
{
|
||||
if (compose_finish)
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
|
||||
output_char);
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
gtk_im_context_simple_commit_char (context_simple, output_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compose_match)
|
||||
{
|
||||
priv->tentative_match = output_char;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
g_string_append_unichar (priv->tentative_match, output_char);
|
||||
priv->tentative_match_len = n_compose;
|
||||
}
|
||||
if (output_char)
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
if (gtk_check_algorithmically (priv->compose_buffer, n_compose, &output_char))
|
||||
{
|
||||
if (output_char)
|
||||
{
|
||||
gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple),
|
||||
output_char);
|
||||
priv->compose_buffer[0] = 0;
|
||||
}
|
||||
return TRUE;
|
||||
gtk_im_context_simple_commit_char (context_simple, output_char);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The current compose_buffer doesn't match anything */
|
||||
return no_sequence_matches (context_simple, n_compose, (GdkEvent *)event);
|
||||
}
|
||||
@@ -1202,66 +891,69 @@ gtk_im_context_simple_reset (GtkIMContext *context)
|
||||
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
if (priv->tentative_match || priv->in_hex_sequence)
|
||||
if (priv->tentative_match->len > 0 || priv->in_hex_sequence)
|
||||
{
|
||||
priv->in_hex_sequence = FALSE;
|
||||
priv->tentative_match = 0;
|
||||
g_string_set_size (priv->tentative_match, 0);
|
||||
priv->tentative_match_len = 0;
|
||||
g_signal_emit_by_name (context_simple, "preedit-changed");
|
||||
g_signal_emit_by_name (context_simple, "preedit-end");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static void
|
||||
gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
|
||||
char **str,
|
||||
PangoAttrList **attrs,
|
||||
int *cursor_pos)
|
||||
char **str,
|
||||
PangoAttrList **attrs,
|
||||
int *cursor_pos)
|
||||
{
|
||||
GtkIMContextSimple *context_simple = GTK_IM_CONTEXT_SIMPLE (context);
|
||||
GtkIMContextSimplePrivate *priv = context_simple->priv;
|
||||
char outbuf[37]; /* up to 6 hex digits */
|
||||
int len = 0;
|
||||
GString *s;
|
||||
int i;
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
if (priv->in_hex_sequence)
|
||||
{
|
||||
int hexchars = 0;
|
||||
|
||||
outbuf[0] = 'u';
|
||||
len = 1;
|
||||
g_string_append_c (s, 'u');
|
||||
|
||||
while (priv->compose_buffer[hexchars] != 0)
|
||||
{
|
||||
len += g_unichar_to_utf8 (gdk_keyval_to_unicode (priv->compose_buffer[hexchars]),
|
||||
outbuf + len);
|
||||
++hexchars;
|
||||
}
|
||||
|
||||
g_assert (len < 25);
|
||||
for (i = 0; priv->compose_buffer[i]; i++)
|
||||
g_string_append_unichar (s, gdk_keyval_to_unicode (priv->compose_buffer[i]));
|
||||
}
|
||||
else if (priv->tentative_match->len > 0 && priv->compose_buffer[0] != 0)
|
||||
{
|
||||
g_string_append (s, priv->tentative_match->str);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; priv->compose_buffer[i]; i++)
|
||||
{
|
||||
if (priv->compose_buffer[i] == GDK_KEY_Multi_key)
|
||||
g_string_append_unichar (s, 0x2384); /* U+2384 COMPOSITION SYMBOL */
|
||||
else
|
||||
g_string_append_unichar (s, gdk_keyval_to_unicode (priv->compose_buffer[i]));
|
||||
}
|
||||
}
|
||||
else if (priv->tentative_match)
|
||||
len = g_unichar_to_utf8 (priv->tentative_match, outbuf);
|
||||
|
||||
outbuf[len] = '\0';
|
||||
|
||||
if (str)
|
||||
*str = g_strdup (outbuf);
|
||||
if (cursor_pos)
|
||||
*cursor_pos = s->len;
|
||||
|
||||
if (attrs)
|
||||
{
|
||||
*attrs = pango_attr_list_new ();
|
||||
|
||||
if (len)
|
||||
{
|
||||
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
|
||||
attr->start_index = 0;
|
||||
attr->end_index = len;
|
||||
pango_attr_list_insert (*attrs, attr);
|
||||
}
|
||||
|
||||
if (s->len)
|
||||
{
|
||||
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
|
||||
attr->start_index = 0;
|
||||
attr->end_index = s->len;
|
||||
pango_attr_list_insert (*attrs, attr);
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor_pos)
|
||||
*cursor_pos = len;
|
||||
if (str)
|
||||
*str = g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1269,7 +961,6 @@ gtk_im_context_simple_get_preedit_string (GtkIMContext *context,
|
||||
* @context_simple: A #GtkIMContextSimple
|
||||
* @data: (array): the table
|
||||
* @max_seq_len: Maximum length of a sequence in the table
|
||||
* (cannot be greater than #GTK_MAX_COMPOSE_LEN)
|
||||
* @n_seqs: number of sequences in the table
|
||||
*
|
||||
* Adds an additional table to search to the input context.
|
||||
@@ -1313,8 +1004,7 @@ gtk_im_context_simple_add_compose_file (GtkIMContextSimple *context_simple,
|
||||
|
||||
G_LOCK (global_tables);
|
||||
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables,
|
||||
compose_file);
|
||||
global_tables = gtk_compose_table_list_add_file (global_tables, compose_file);
|
||||
|
||||
G_UNLOCK (global_tables);
|
||||
}
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GTK_MAX_COMPOSE_LEN:
|
||||
*
|
||||
* The maximum length of sequences in compose tables.
|
||||
/*
|
||||
* No longer used by GTK, just left here on the off chance that some
|
||||
* 3rd party code used this define.
|
||||
*/
|
||||
#define GTK_MAX_COMPOSE_LEN 7
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2000 Red Hat Software
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
|
||||
#define __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "gdk/gdkkeysyms.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
extern const GtkComposeTableCompact gtk_compose_table_compact;
|
||||
|
||||
gboolean gtk_check_algorithmically (const guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gunichar *output);
|
||||
gboolean gtk_check_compact_table (const GtkComposeTableCompact *table,
|
||||
guint16 *compose_buffer,
|
||||
int n_compose,
|
||||
gboolean *compose_finish,
|
||||
gboolean *compose_match,
|
||||
gunichar *output_char);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GTK_IM_CONTEXT_SIMPLE_PRIVATE_H__ */
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include "gtk/gtkdragsourceprivate.h"
|
||||
#include "gtk/gtkimcontextwayland.h"
|
||||
#include "gtk/gtkintl.h"
|
||||
#include "gtk/gtkimmoduleprivate.h"
|
||||
@@ -524,10 +525,10 @@ released_cb (GtkGestureClick *gesture,
|
||||
if (global->focused &&
|
||||
n_press == 1 &&
|
||||
(hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
|
||||
!gtk_drag_check_threshold (context->widget,
|
||||
context->press_x,
|
||||
context->press_y,
|
||||
x, y))
|
||||
!gtk_drag_check_threshold_double (context->widget,
|
||||
context->press_x,
|
||||
context->press_y,
|
||||
x, y))
|
||||
{
|
||||
zwp_text_input_v3_enable (global->text_input);
|
||||
g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
|
||||
@@ -4273,7 +4273,7 @@ gtk_label_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (info->in_drag)
|
||||
{
|
||||
if (gtk_drag_check_threshold (widget, info->drag_start_x, info->drag_start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (widget, info->drag_start_x, info->drag_start_y, x, y))
|
||||
{
|
||||
GdkDrag *drag;
|
||||
GdkSurface *surface;
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdropcontrollermotion.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgizmoprivate.h"
|
||||
@@ -1147,7 +1147,7 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
P_("The orientation of the orientable"),
|
||||
GTK_TYPE_ORIENTATION,
|
||||
GTK_ORIENTATION_VERTICAL,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
@@ -1709,7 +1709,7 @@ gtk_list_base_drag_update (GtkGestureDrag *gesture,
|
||||
|
||||
if (!priv->rubberband)
|
||||
{
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
return;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
+3
-3
@@ -724,13 +724,13 @@ gtk_list_box_init (GtkListBox *box)
|
||||
* gtk_list_box_get_selected_row:
|
||||
* @box: a #GtkListBox
|
||||
*
|
||||
* Gets the selected row.
|
||||
* Gets the selected row, or %NULL if no rows are selected.
|
||||
*
|
||||
* Note that the box may allow multiple selection, in which
|
||||
* case you should use gtk_list_box_selected_foreach() to
|
||||
* find all selected rows.
|
||||
*
|
||||
* Returns: (transfer none): the selected row
|
||||
* Returns: (transfer none) (nullable): the selected row or %NULL
|
||||
*/
|
||||
GtkListBoxRow *
|
||||
gtk_list_box_get_selected_row (GtkListBox *box)
|
||||
@@ -746,7 +746,7 @@ gtk_list_box_get_selected_row (GtkListBox *box)
|
||||
* @index_: the index of the row
|
||||
*
|
||||
* Gets the n-th child in the list (not counting headers).
|
||||
* If @_index is negative or larger than the number of items in the
|
||||
* If @index_ is negative or larger than the number of items in the
|
||||
* list, %NULL is returned.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): the child #GtkWidget or %NULL
|
||||
|
||||
+11
-1
@@ -332,7 +332,7 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
|
||||
if (!priv->list_item || priv->list_item->activatable)
|
||||
{
|
||||
if (n_press == 2 || priv->single_click_activate)
|
||||
if (n_press == 2 && !priv->single_click_activate)
|
||||
{
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.activate-item",
|
||||
@@ -356,6 +356,16 @@ gtk_list_item_widget_click_gesture_released (GtkGestureClick *gesture,
|
||||
{
|
||||
GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
|
||||
|
||||
if (priv->single_click_activate)
|
||||
{
|
||||
gtk_widget_activate_action (GTK_WIDGET (self),
|
||||
"list.activate-item",
|
||||
"u",
|
||||
priv->position);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priv->list_item || priv->list_item->selectable)
|
||||
{
|
||||
GdkModifierType state;
|
||||
|
||||
@@ -454,8 +454,6 @@ gtk_message_dialog_init (GtkMessageDialog *dialog)
|
||||
GtkSettings *settings;
|
||||
gboolean use_caret;
|
||||
|
||||
priv->has_primary_markup = FALSE;
|
||||
priv->has_secondary_text = FALSE;
|
||||
priv->has_primary_markup = FALSE;
|
||||
priv->has_secondary_text = FALSE;
|
||||
priv->message_type = GTK_MESSAGE_OTHER;
|
||||
|
||||
@@ -52,6 +52,11 @@
|
||||
* various common properties on the dialog, as well as show and hide
|
||||
* it and get a #GtkNativeDialog::response signal when the user finished
|
||||
* with the dialog.
|
||||
*
|
||||
* Note that unlike #GtkDialog, #GtkNativeDialog objects are not
|
||||
* toplevel widgets, and GTK does not keep them alive. It is your
|
||||
* responsibility to keep a reference until you are done with the
|
||||
* object.
|
||||
*/
|
||||
|
||||
typedef struct _GtkNativeDialogPrivate GtkNativeDialogPrivate;
|
||||
|
||||
+10
-7
@@ -50,7 +50,7 @@
|
||||
#include "gtkstack.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkwidgetpaintable.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
@@ -248,14 +248,14 @@ struct _GtkNotebook
|
||||
GList *first_tab; /* The first tab visible (for scrolling notebooks) */
|
||||
GList *focus_tab;
|
||||
|
||||
int drag_begin_x;
|
||||
int drag_begin_y;
|
||||
double drag_begin_x;
|
||||
double drag_begin_y;
|
||||
int drag_offset_x;
|
||||
int drag_offset_y;
|
||||
int drag_surface_x;
|
||||
int drag_surface_y;
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
double mouse_x;
|
||||
double mouse_y;
|
||||
int pressed_button;
|
||||
|
||||
GQuark group;
|
||||
@@ -2934,8 +2934,11 @@ gtk_notebook_motion (GtkEventController *controller,
|
||||
|
||||
if (page->reorderable &&
|
||||
(notebook->operation == DRAG_OPERATION_REORDER ||
|
||||
gtk_drag_check_threshold (widget, notebook->drag_begin_x, notebook->drag_begin_y,
|
||||
notebook->mouse_x, notebook->mouse_y)))
|
||||
gtk_drag_check_threshold_double (widget,
|
||||
notebook->drag_begin_x,
|
||||
notebook->drag_begin_y,
|
||||
notebook->mouse_x,
|
||||
notebook->mouse_y)))
|
||||
{
|
||||
GtkNotebookPointerPosition pointer_position = get_pointer_position (notebook);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
|
||||
/*< private >
|
||||
@@ -3451,7 +3451,7 @@ on_row_dragged (GtkGestureDrag *gesture,
|
||||
return;
|
||||
}
|
||||
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (row), 0, 0, x, y))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (row), 0, 0, x, y))
|
||||
{
|
||||
double start_x, start_y;
|
||||
double drag_x, drag_y;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkeventcontrollerscroll.h"
|
||||
#include "gtkeventcontrollerprivate.h"
|
||||
@@ -953,8 +953,8 @@ scrolled_window_drag_update_cb (GtkScrolledWindow *scrolled_window,
|
||||
GtkAdjustment *vadjustment;
|
||||
double dx, dy;
|
||||
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (scrolled_window),
|
||||
0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (GTK_WIDGET (scrolled_window),
|
||||
0, 0, offset_x, offset_y))
|
||||
return;
|
||||
|
||||
gtk_scrolled_window_invalidate_overshoot (scrolled_window);
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ gtk_show_uri_full (GtkWindow *parent,
|
||||
* @result: #GAsyncResult that was passed to @callback
|
||||
* @error: return location for an error
|
||||
*
|
||||
* Finished the gtk_show_uri() call and returns the result
|
||||
* Finishes the gtk_show_uri() call and returns the result
|
||||
* of the operation.
|
||||
*
|
||||
* Returns: %TRUE if the URI was shown successfully.
|
||||
|
||||
+2
-4
@@ -29,7 +29,7 @@
|
||||
#include "gtkbutton.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdroptarget.h"
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkemojichooser.h"
|
||||
@@ -2941,9 +2941,7 @@ gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
if (priv->in_drag)
|
||||
{
|
||||
if (gtk_text_get_display_mode (self) == DISPLAY_NORMAL &&
|
||||
gtk_drag_check_threshold (widget,
|
||||
priv->drag_start_x, priv->drag_start_y,
|
||||
x, y))
|
||||
gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
int *ranges;
|
||||
int n_ranges;
|
||||
|
||||
+2
-2
@@ -257,8 +257,8 @@ static void gtk_text_btree_rebalance (GtkTextBTree
|
||||
static GtkTextLine * get_last_line (GtkTextBTree *tree);
|
||||
static void post_insert_fixup (GtkTextBTree *tree,
|
||||
GtkTextLine *insert_line,
|
||||
int char_count_delta,
|
||||
int line_count_delta);
|
||||
int line_count_delta,
|
||||
int char_count_delta);
|
||||
static void gtk_text_btree_node_adjust_toggle_count (GtkTextBTreeNode *node,
|
||||
GtkTextTagInfo *info,
|
||||
int adjust);
|
||||
|
||||
+3
-2
@@ -32,6 +32,7 @@
|
||||
#include "gtkadjustmentprivate.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdropcontrollermotion.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
@@ -7232,7 +7233,7 @@ gtk_text_view_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
/* If no data is attached, the initial press happened within the current
|
||||
* text selection, check for drag and drop to be initiated.
|
||||
*/
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
|
||||
{
|
||||
if (!is_touchscreen)
|
||||
{
|
||||
@@ -7366,7 +7367,7 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
|
||||
gdk_device_get_source (device) == GDK_SOURCE_TOUCHSCREEN;
|
||||
|
||||
if ((is_touchscreen || clicked_in_selection) &&
|
||||
!gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
|
||||
!gtk_drag_check_threshold_double (GTK_WIDGET (text_view), 0, 0, offset_x, offset_y))
|
||||
{
|
||||
GtkTextIter iter;
|
||||
|
||||
|
||||
@@ -3285,9 +3285,6 @@ gtk_tree_model_filter_iter_children (GtkTreeModel *model,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
iter->stamp = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@
|
||||
#include "gtkcellrenderer.h"
|
||||
#include "gtkcssnumbervalueprivate.h"
|
||||
#include "gtkcsscolorvalueprivate.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkdragicon.h"
|
||||
#include "gtkdroptargetasync.h"
|
||||
#include "gtkentryprivate.h"
|
||||
@@ -7052,7 +7052,7 @@ gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view)
|
||||
gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (priv->drag_gesture),
|
||||
&offset_x, &offset_y);
|
||||
|
||||
if (!gtk_drag_check_threshold (widget, 0, 0, offset_x, offset_y))
|
||||
if (!gtk_drag_check_threshold_double (widget, 0, 0, offset_x, offset_y))
|
||||
goto out;
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "gtkcellareabox.h"
|
||||
#include "gtkcellareacontext.h"
|
||||
#include "gtkcelllayout.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkframe.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtkintl.h"
|
||||
@@ -1072,7 +1072,7 @@ column_button_drag_update (GtkGestureDrag *gesture,
|
||||
{
|
||||
GtkTreeViewColumnPrivate *priv = column->priv;
|
||||
|
||||
if (gtk_drag_check_threshold (priv->button, 0, 0, offset_x, offset_y))
|
||||
if (gtk_drag_check_threshold_double (priv->button, 0, 0, offset_x, offset_y))
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
_gtk_tree_view_column_start_drag (GTK_TREE_VIEW (priv->tree_view), column,
|
||||
|
||||
+1
-34
@@ -257,7 +257,7 @@
|
||||
* custom `<layout>` element, used to define layout properties:
|
||||
*
|
||||
* |[<!-- language="xml" -->
|
||||
* <object class="MyGrid" id="grid1">
|
||||
* <object class="GtkGrid" id="my_grid">
|
||||
* <child>
|
||||
* <object class="GtkLabel" id="label1">
|
||||
* <property name="label">Description</property>
|
||||
@@ -11304,39 +11304,6 @@ gtk_widget_remove_controller (GtkWidget *widget,
|
||||
gtk_list_list_model_item_removed (priv->controller_observer, before);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_widget_consumes_motion (GtkWidget *widget,
|
||||
GtkWidget *parent,
|
||||
GdkEventSequence *sequence)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
while (widget != NULL && widget != parent)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = priv->event_controllers; l; l = l->next)
|
||||
{
|
||||
GtkEventController *controller = l->data;
|
||||
|
||||
if (controller == NULL ||
|
||||
!GTK_IS_GESTURE (controller))
|
||||
continue;
|
||||
|
||||
if ((!GTK_IS_GESTURE_SINGLE (controller) ||
|
||||
GTK_IS_GESTURE_DRAG (controller) ||
|
||||
GTK_IS_GESTURE_SWIPE (controller)) &&
|
||||
gtk_gesture_handles_sequence (GTK_GESTURE (controller), sequence))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
widget = priv->parent;
|
||||
priv = gtk_widget_get_instance_private (widget);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_widget_reset_controllers (GtkWidget *widget)
|
||||
{
|
||||
|
||||
@@ -278,10 +278,6 @@ void _gtk_widget_update_parent_muxer (GtkWidget *widget
|
||||
GtkActionMuxer * _gtk_widget_get_action_muxer (GtkWidget *widget,
|
||||
gboolean create);
|
||||
|
||||
gboolean gtk_widget_consumes_motion (GtkWidget *widget,
|
||||
GtkWidget *parent,
|
||||
GdkEventSequence *sequence);
|
||||
|
||||
gboolean gtk_widget_has_tick_callback (GtkWidget *widget);
|
||||
|
||||
gboolean gtk_widget_has_size_request (GtkWidget *widget);
|
||||
|
||||
+6
-57
@@ -24,6 +24,7 @@
|
||||
#include "gtkbinlayout.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkbuildable.h"
|
||||
#include "gtkdragsourceprivate.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgestureprivate.h"
|
||||
@@ -60,7 +61,6 @@ struct _GtkWindowHandle {
|
||||
|
||||
GtkGesture *click_gesture;
|
||||
GtkGesture *drag_gesture;
|
||||
GtkGesture *bubble_drag_gesture;
|
||||
|
||||
GtkWidget *child;
|
||||
GtkWidget *fallback_menu;
|
||||
@@ -389,47 +389,14 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
|
||||
double offset_y,
|
||||
GtkWindowHandle *self)
|
||||
{
|
||||
int double_click_distance;
|
||||
GtkSettings *settings;
|
||||
|
||||
settings = gtk_widget_get_settings (GTK_WIDGET (self));
|
||||
g_object_get (settings,
|
||||
"gtk-double-click-distance", &double_click_distance,
|
||||
NULL);
|
||||
|
||||
if (ABS (offset_x) > double_click_distance ||
|
||||
ABS (offset_y) > double_click_distance)
|
||||
if (gtk_drag_check_threshold_double (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
{
|
||||
GdkEventSequence *sequence;
|
||||
double start_x, start_y;
|
||||
double native_x, native_y;
|
||||
double window_x, window_y;
|
||||
GtkNative *native;
|
||||
GdkSurface *surface;
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
|
||||
if (gtk_event_controller_get_propagation_phase (GTK_EVENT_CONTROLLER (gesture)) == GTK_PHASE_CAPTURE)
|
||||
{
|
||||
GtkWidget *event_widget = gtk_gesture_get_last_target (GTK_GESTURE (gesture), sequence);
|
||||
|
||||
/* Check whether the target widget should be left alone at handling
|
||||
* the sequence, this is better done late to give room for gestures
|
||||
* there to go denied.
|
||||
*
|
||||
* Besides claiming gestures, we must bail out too if there's gestures
|
||||
* in the "none" state at this point, as those are still handling events
|
||||
* and can potentially go claimed, and we don't want to stop the target
|
||||
* widget from doing anything.
|
||||
*/
|
||||
if (event_widget != GTK_WIDGET (self) &&
|
||||
gtk_widget_consumes_motion (event_widget, GTK_WIDGET (self), sequence))
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
@@ -458,19 +425,6 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
|
||||
}
|
||||
}
|
||||
|
||||
static GtkGesture *
|
||||
create_drag_gesture (GtkWindowHandle *self)
|
||||
{
|
||||
GtkGesture *gesture;
|
||||
|
||||
gesture = gtk_gesture_drag_new ();
|
||||
g_signal_connect (gesture, "drag-update",
|
||||
G_CALLBACK (drag_gesture_update_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
return gesture;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_window_handle_unrealize (GtkWidget *widget)
|
||||
{
|
||||
@@ -562,19 +516,14 @@ gtk_window_handle_init (GtkWindowHandle *self)
|
||||
{
|
||||
self->click_gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->click_gesture), 0);
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->click_gesture),
|
||||
GTK_PHASE_BUBBLE);
|
||||
g_signal_connect (self->click_gesture, "pressed",
|
||||
G_CALLBACK (click_gesture_pressed_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->click_gesture));
|
||||
|
||||
self->drag_gesture = create_drag_gesture (self);
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->drag_gesture),
|
||||
GTK_PHASE_CAPTURE);
|
||||
|
||||
self->bubble_drag_gesture = create_drag_gesture (self);
|
||||
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->bubble_drag_gesture),
|
||||
GTK_PHASE_BUBBLE);
|
||||
self->drag_gesture = gtk_gesture_drag_new ();
|
||||
g_signal_connect (self->drag_gesture, "drag-update",
|
||||
G_CALLBACK (drag_gesture_update_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (self->drag_gesture));
|
||||
}
|
||||
|
||||
static GtkBuildableIface *parent_buildable_iface;
|
||||
|
||||
+7
-6
@@ -66,6 +66,7 @@ gtk_private_sources = files([
|
||||
'gtkcssimageconic.c',
|
||||
'gtkcssimagecrossfade.c',
|
||||
'gtkcssimagefallback.c',
|
||||
'gtkcssimagefilter.c',
|
||||
'gtkcssimageicontheme.c',
|
||||
'gtkcssimageinvalid.c',
|
||||
'gtkcssimagelinear.c',
|
||||
@@ -1142,12 +1143,6 @@ if build_gir
|
||||
# the installed one
|
||||
gdk_gir_inc = [ 'cairo-1.0', 'Gio-2.0', ]
|
||||
|
||||
if graphene_dep.type_name() == 'internal'
|
||||
gdk_gir_inc += subproject('graphene').get_variable('graphene_gir').get(0)
|
||||
else
|
||||
gdk_gir_inc += 'Graphene-1.0'
|
||||
endif
|
||||
|
||||
if pixbuf_dep.type_name() == 'internal'
|
||||
gdk_gir_inc += subproject('gdk-pixbuf').get_variable('gdkpixbuf_gir').get(0)
|
||||
else
|
||||
@@ -1211,6 +1206,12 @@ if build_gir
|
||||
|
||||
gsk_gir_inc = [ gdk_gir[0] ]
|
||||
|
||||
if graphene_dep.type_name() == 'internal'
|
||||
gsk_gir_inc += subproject('graphene').get_variable('graphene_gir').get(0)
|
||||
else
|
||||
gsk_gir_inc += 'Graphene-1.0'
|
||||
endif
|
||||
|
||||
gsk_gir = gnome.generate_gir(libgtk,
|
||||
sources: gsk_public_headers + gsk_public_sources + [ gskenum_h ],
|
||||
namespace: 'Gsk',
|
||||
|
||||
@@ -933,6 +933,14 @@ list > row button.image-button:not(.flat) {
|
||||
&:hover { @include button(hover); }
|
||||
&:active,
|
||||
&:checked { @include button(active); }
|
||||
|
||||
@each $b_type, $b_color in (suggested-action, $selected_bg_color),
|
||||
(destructive-action, $destructive_color) {
|
||||
&.#{$b_type} { // allow colored buttons in lists #3643
|
||||
@include button(normal, $b_color, white);
|
||||
@include focus-ring($fc: $alt_focus_border_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********
|
||||
|
||||
@@ -85,6 +85,13 @@ gtk_library_version = '1.@0@.@1@'.format(gtk_binary_age - gtk_interface_age, gtk
|
||||
|
||||
gtk_api_version = '4.0'
|
||||
|
||||
module_suffix = []
|
||||
# GModule requires file extension to be .so, not .dylib on Mac.
|
||||
# https://gitlab.gnome.org/GNOME/glib/issues/520
|
||||
if ['darwin', 'ios'].contains(host_machine.system())
|
||||
module_suffix = 'so'
|
||||
endif
|
||||
|
||||
x11_enabled = get_option('x11-backend')
|
||||
wayland_enabled = get_option('wayland-backend')
|
||||
broadway_enabled = get_option('broadway-backend')
|
||||
|
||||
@@ -35,6 +35,7 @@ if ffmpeg_found
|
||||
sources: 'gtkffmediafile.c',
|
||||
c_args: extra_c_args,
|
||||
dependencies: [ libgtk_dep, ffmpeg_deps ],
|
||||
name_suffix: module_suffix,
|
||||
install_dir: media_install_dir,
|
||||
install: true,
|
||||
)
|
||||
@@ -56,6 +57,7 @@ if gstplayer_dep.found() and gstgl_dep.found()
|
||||
],
|
||||
c_args: extra_c_args,
|
||||
dependencies: [ libm, libgtk_dep, gstplayer_dep, gstgl_dep ],
|
||||
name_suffix: module_suffix,
|
||||
install_dir: media_install_dir,
|
||||
install: true,
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@ if cups_dep.found()
|
||||
],
|
||||
c_args: printbackends_args,
|
||||
dependencies: [libgtk_dep, cups_dep, colord_dep],
|
||||
name_suffix: module_suffix,
|
||||
install_dir: printbackends_install_dir,
|
||||
install: true,
|
||||
)
|
||||
@@ -32,6 +33,7 @@ else
|
||||
sources: 'gtkprintbackendlpr.c',
|
||||
c_args: printbackends_args,
|
||||
dependencies: libgtk_dep,
|
||||
name_suffix: module_suffix,
|
||||
install_dir: printbackends_install_dir,
|
||||
install: true,
|
||||
)
|
||||
@@ -49,6 +51,7 @@ if rest_dep.found() and json_glib_dep.found()
|
||||
],
|
||||
c_args: printbackends_args,
|
||||
dependencies: [ libgtk_dep, rest_dep, json_glib_dep ],
|
||||
name_suffix: module_suffix,
|
||||
install_dir: printbackends_install_dir,
|
||||
install: true)
|
||||
endif
|
||||
@@ -59,6 +62,7 @@ shared_module('printbackend-file',
|
||||
sources: 'gtkprintbackendfile.c',
|
||||
c_args: printbackends_args,
|
||||
dependencies: libgtk_dep,
|
||||
name_suffix: module_suffix,
|
||||
install_dir: printbackends_install_dir,
|
||||
install: true,
|
||||
)
|
||||
|
||||
+468
-458
File diff suppressed because it is too large
Load Diff
@@ -97,7 +97,7 @@ msgstr "Backspace"
|
||||
#: gdk/keyname-table.h:6844
|
||||
msgctxt "keyboard label"
|
||||
msgid "Tab"
|
||||
msgstr "Tabulátor"
|
||||
msgstr "Tab"
|
||||
|
||||
#: gdk/keyname-table.h:6845
|
||||
msgctxt "keyboard label"
|
||||
@@ -122,7 +122,7 @@ msgstr "Sys_Req"
|
||||
#: gdk/keyname-table.h:6849
|
||||
msgctxt "keyboard label"
|
||||
msgid "Escape"
|
||||
msgstr "Escape"
|
||||
msgstr "Esc"
|
||||
|
||||
#: gdk/keyname-table.h:6850
|
||||
msgctxt "keyboard label"
|
||||
|
||||
+186
-322
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
[Test]
|
||||
Exec=/bin/sh -c "env G_ENABLE_DIAGNOSTIC=0 GTK_A11Y=test @libexecdir@/installed-tests/gtk-4.0/css/data --tap -k"
|
||||
Type=session
|
||||
Output=TAP
|
||||
@@ -6,6 +6,7 @@ csstest_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
|
||||
csstest_env.set('GIO_USE_VFS', 'local')
|
||||
csstest_env.set('GSETTINGS_BACKEND', 'memory')
|
||||
csstest_env.set('G_ENABLE_DIAGNOSTIC', '0')
|
||||
csstest_env.set('GDK_DEBUG', 'default-settings')
|
||||
|
||||
subdir('parser')
|
||||
subdir('nodes')
|
||||
@@ -29,10 +30,10 @@ test('api', test_api,
|
||||
suite: 'css',
|
||||
)
|
||||
|
||||
test_data = executable('data', ['data.c', '../../gtk/css/gtkcssdataurl.c'],
|
||||
test_data = executable('data', 'data.c',
|
||||
c_args: common_cflags,
|
||||
include_directories: [confinc, ],
|
||||
dependencies: gtk_deps,
|
||||
dependencies: libgtk_static_dep,
|
||||
install: get_option('install-tests'),
|
||||
install_dir: testexecdir,
|
||||
)
|
||||
@@ -44,6 +45,20 @@ test('data', test_data,
|
||||
suite: 'css',
|
||||
)
|
||||
|
||||
transition = executable('transition', 'transition.c',
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_static_dep,
|
||||
install: get_option('install-tests'),
|
||||
install_dir: testexecdir,
|
||||
)
|
||||
|
||||
test('transition', transition,
|
||||
args: [ '--tap', '-k' ],
|
||||
protocol: 'tap',
|
||||
env: csstest_env,
|
||||
suite: 'css'
|
||||
)
|
||||
|
||||
if get_option('install-tests')
|
||||
conf = configuration_data()
|
||||
conf.set('libexecdir', gtk_libexecdir)
|
||||
@@ -52,6 +67,14 @@ if get_option('install-tests')
|
||||
configuration: conf,
|
||||
install_dir: testdatadir,
|
||||
)
|
||||
|
||||
conf = configuration_data()
|
||||
conf.set('libexecdir', gtk_libexecdir)
|
||||
configure_file(input: 'data.test.in',
|
||||
output: 'data.test',
|
||||
configuration: conf,
|
||||
install_dir: testdatadir,
|
||||
)
|
||||
endif
|
||||
|
||||
if false and get_option ('profiler')
|
||||
|
||||
@@ -74,3 +74,11 @@ r {
|
||||
s {
|
||||
background-image: -gtk-scaled(-gtk-icontheme("object-select-symbolic"),linear-gradient(yellow, blue));
|
||||
}
|
||||
|
||||
t {
|
||||
background-image: cross-fade(10% image(red), 20% image(yellow), linear-gradient(blue, black));
|
||||
}
|
||||
|
||||
u {
|
||||
background-image: filter(url("test.png"), grayscale(100%) invert(50%));
|
||||
}
|
||||
|
||||
@@ -73,3 +73,11 @@ r {
|
||||
s {
|
||||
background-image: -gtk-scaled(-gtk-icontheme("object-select-symbolic"),1,linear-gradient(rgb(255,255,0), rgb(0,0,255)),2);
|
||||
}
|
||||
|
||||
t {
|
||||
background-image: cross-fade(10% image(rgb(255,0,0)), 20% image(rgb(255,255,0)), linear-gradient(rgb(0,0,255), rgb(0,0,0)));
|
||||
}
|
||||
|
||||
u {
|
||||
background-image: filter(none /* FIXME */,grayscale(100%) invert(50%));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: blur(-1px);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid1.css:2:16-20: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: brightness(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid2.css:2:22-27: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: contrast(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid3.css:2:20-25: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: grayscale(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid4.css:2:21-26: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: invert(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid5.css:2:18-23: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: opacity(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid6.css:2:19-24: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: saturate(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid7.css:2:20-25: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: sepia(-100%);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid8.css:2:17-22: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
|
||||
@@ -0,0 +1,3 @@
|
||||
a {
|
||||
filter: drop-shadow(none);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
filter-invalid9.css:2:23-27: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||
@@ -0,0 +1,23 @@
|
||||
a {
|
||||
filter: initial;
|
||||
}
|
||||
|
||||
b {
|
||||
filter: inherit;
|
||||
}
|
||||
|
||||
c {
|
||||
filter: unset;
|
||||
}
|
||||
|
||||
d {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
e {
|
||||
filter: blur(2px) brightness(20%) contrast(120%) grayscale(100%) hue-rotate(45deg) invert(50%) opacity(25%) saturate(90%) sepia(100%);
|
||||
}
|
||||
|
||||
f {
|
||||
filter: drop-shadow(rgb(255,0,0) 1px 2px);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user