Compare commits
41 Commits
parse-dash
...
tooltip_wi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab2bf2596 | ||
|
|
11b4e4a467 | ||
|
|
1cae0cd54c | ||
|
|
1f3db35271 | ||
|
|
18cce46ed2 | ||
|
|
e78148bae5 | ||
|
|
41237509ad | ||
|
|
576e8a2090 | ||
|
|
d0f77c1db4 | ||
|
|
e28ff79bec | ||
|
|
dccf6b55bd | ||
|
|
d5ea376e7b | ||
|
|
40707a6af0 | ||
|
|
9b71c9dfc6 | ||
|
|
64308317f8 | ||
|
|
f920723eae | ||
|
|
c581f4c96f | ||
|
|
4998c90b10 | ||
|
|
412b23a146 | ||
|
|
c179013790 | ||
|
|
c6eb7fd483 | ||
|
|
7c58370673 | ||
|
|
84737a5159 | ||
|
|
48804c81f3 | ||
|
|
c79ec355af | ||
|
|
ce5d74d7df | ||
|
|
5bcc943ec3 | ||
|
|
f5d68bb586 | ||
|
|
6d1537647c | ||
|
|
ae2c10996a | ||
|
|
81e9de3778 | ||
|
|
42a704fefb | ||
|
|
e57eaf16b4 | ||
|
|
9aabb0e98d | ||
|
|
9590a5f45e | ||
|
|
32a3690a3c | ||
|
|
43af0ee514 | ||
|
|
3912d6aba9 | ||
|
|
871685e271 | ||
|
|
5e9daa9728 | ||
|
|
412bc1713a |
9
NEWS
9
NEWS
@@ -1,4 +1,7 @@
|
||||
Overview of Changes in 4.11.4, xx-xx-xxxx
|
||||
Overview of Changes in 4.11.5, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
Overview of Changes in 4.11.4, 03-07-2023
|
||||
=========================================
|
||||
|
||||
* GtkFileChooser:
|
||||
@@ -26,6 +29,9 @@ Overview of Changes in 4.11.4, xx-xx-xxxx
|
||||
* GtkDropDown:
|
||||
- Update on expression changes
|
||||
|
||||
* GtkMapListModel:
|
||||
- Implement GtkSectionModel
|
||||
|
||||
* Accessibility:
|
||||
- Improvements all over the place: GtkButton, GtkPasswordEntry,
|
||||
GtkFontChooserDialog, GtkColorChooserDialog, GtkShortcutsWindow,
|
||||
@@ -72,6 +78,7 @@ Overview of Changes in 4.11.4, xx-xx-xxxx
|
||||
* Build:
|
||||
- Require GLib 2.76
|
||||
- Make asan builds work again
|
||||
- Fix the build if ld is not ld.bdf
|
||||
|
||||
* Translation updates:
|
||||
Brazilian Portuguese
|
||||
|
||||
@@ -153,6 +153,35 @@ get_busy (GSimpleAction *action,
|
||||
gtk_widget_set_sensitive (window, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
search_button_tooltip_show (GtkWidget *self,
|
||||
GtkTooltip *tooltip)
|
||||
{
|
||||
static int style = 0;
|
||||
|
||||
if (style == 0)
|
||||
{
|
||||
gtk_tooltip_set_css_class (tooltip, "red-tooltip");
|
||||
style++;
|
||||
}
|
||||
else if (style == 1)
|
||||
{
|
||||
gtk_tooltip_set_css_class (tooltip, "yellow-tooltip");
|
||||
style++;
|
||||
}
|
||||
else
|
||||
{
|
||||
style = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
search_button_tooltip_hide (GtkWidget *self,
|
||||
GtkTooltip *tooltip)
|
||||
{
|
||||
gtk_tooltip_set_css_class (tooltip, NULL);
|
||||
}
|
||||
|
||||
static int current_page = 0;
|
||||
static gboolean
|
||||
on_page (int i)
|
||||
@@ -2221,6 +2250,8 @@ activate (GApplication *app)
|
||||
gtk_builder_cscope_add_callback (scope, level_scale_value_changed);
|
||||
gtk_builder_cscope_add_callback (scope, transition_speed_changed);
|
||||
gtk_builder_cscope_add_callback (scope, reset_icon_size);
|
||||
gtk_builder_cscope_add_callback (scope, search_button_tooltip_show);
|
||||
gtk_builder_cscope_add_callback (scope, search_button_tooltip_hide);
|
||||
gtk_builder_set_scope (builder, scope);
|
||||
g_object_unref (scope);
|
||||
if (!gtk_builder_add_from_resource (builder, "/org/gtk/WidgetFactory4/widget-factory.ui", &error))
|
||||
|
||||
@@ -6,3 +6,12 @@
|
||||
.toolbar {
|
||||
-gtk-icon-style: symbolic;
|
||||
}
|
||||
|
||||
.red-tooltip {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.yellow-tooltip {
|
||||
background-color: yellow;
|
||||
color: black;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,9 @@
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="textbuffer1">
|
||||
<property name="tag-table">tags</property>
|
||||
<property name="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
<property name="text">Search button above will display its tooltip in an alternating red, yellow and default style.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Nullam fringilla, est ut feugiat ultrices, elit lacus ultricies nibh, id commodo tortor nisi id elit.
|
||||
Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
|
||||
Morbi vel elit erat. Maecenas dignissim, dui et pharetra rutrum, tellus lectus rutrum mi, a convallis libero nisi quis tellus.
|
||||
@@ -1921,6 +1923,8 @@ microphone-sensitivity-medium-symbolic</property>
|
||||
<property name="icon-name">edit-find</property>
|
||||
<property name="action-name">win.search</property>
|
||||
<property name="tooltip-text" translatable="1">Search for it</property>
|
||||
<signal name="tooltip-show" handler="search_button_tooltip_show"/>
|
||||
<signal name="tooltip-hide" handler="search_button_tooltip_hide"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -30,12 +30,12 @@ Views display data from a **_model_**. Models implement the [`iface@Gio.ListMode
|
||||
interface and can be provided in a variety of ways:
|
||||
|
||||
* List model implementations for many specific types of data already exist, for
|
||||
example `GtkDirectoryList` or `GtkStringList`.
|
||||
example [`class@Gtk.DirectoryList`] or [`class@Gtk.StringList`].
|
||||
|
||||
* There are generic list model implementations like`GListStore` that allow building
|
||||
* There are generic list model implementations like [`class@Gio.ListStore`] that allow building
|
||||
lists of arbitrary objects.
|
||||
|
||||
* Wrapping list models like `GtkFilterListModel` or `GtkSortListModel`
|
||||
* Wrapping list models like [`class@Gtk.FilterListModel`] or [`class@Gtk.SortListModel`]
|
||||
modify, adapt or combine other models.
|
||||
|
||||
* Last but not least, developers are encouraged to create their own `GListModel`
|
||||
@@ -133,8 +133,8 @@ tradeoffs of those and experiment with them.
|
||||
|
||||
GTK offers a wide variety of wrapping models which change or supplement an
|
||||
existing model (or models) in some way. But when it comes to storing your
|
||||
actual data, there are only a few ready-made choices available: [`class@Gio.ListStore`]
|
||||
and [`class@Gtk.StringList`].
|
||||
actual data, there are only a few ready-made choices available:
|
||||
[`class@Gio.ListStore`], [`class@Gtk.StringList`], and [`class@Gtk.DirectoryList`].
|
||||
|
||||
`GListStore` is backed by a balanced tree and has performance characteristics
|
||||
that are expected for that data structure. It works reasonably well for dataset
|
||||
@@ -147,6 +147,10 @@ that are expected for that data structure. `GtkStringList` is a good fit for any
|
||||
place where you would otherwise use `char*[]` and works best if the dataset
|
||||
is not very dynamic.
|
||||
|
||||
`GtkDirectoryList` is a list model that wraps [`method@Gio.File.enumerate_children_async`].
|
||||
It presents a `GListModel` and fills it asynchronously with the [`iface@Gio.File`]s
|
||||
returned from that function.
|
||||
|
||||
If these models don't fit your use case or scalability requirements, you
|
||||
should make a custom `GListModel` implementation. It is a small interface and
|
||||
not very hard to implement.
|
||||
@@ -199,7 +203,7 @@ the `.data-table` style class.
|
||||
## Sections
|
||||
|
||||
List models can optionally group their items into **_sections_**, by implementing
|
||||
the `GtkSectionModel` interface. Both `GtkListView` and `GtkGridView` can
|
||||
the `GtkSectionModel` interface. `GtkListView` can
|
||||
display headers for sections, by installing a separate **_header factory_**.
|
||||
|
||||
Many GTK list models support section inherently, or they pass through the
|
||||
|
||||
@@ -1552,7 +1552,7 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
|
||||
priv->has_sync = gdk_gl_context_check_version (context, "3.2", "3.0") ||
|
||||
epoxy_has_gl_extension ("GL_ARB_sync") ||
|
||||
epoxy_has_gl_extension ("GK_APPLE_sync");
|
||||
epoxy_has_gl_extension ("GL_APPLE_sync");
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
* multiple frames, and will be used for a long time.
|
||||
*
|
||||
* There are various ways to create `GdkTexture` objects from a
|
||||
* [class@GdkPixbuf.Pixbuf], or a Cairo surface, or other pixel data.
|
||||
* [class@GdkPixbuf.Pixbuf], or from bytes stored in memory, a file, or a
|
||||
* [struct@Gio.Resource].
|
||||
*
|
||||
* The ownership of the pixel data is transferred to the `GdkTexture`
|
||||
* instance; you can only make a copy of it, via [method@Gdk.Texture.download].
|
||||
|
||||
@@ -3064,9 +3064,9 @@ tablet_tool_handle_button (void *data,
|
||||
tablet->pointer_info.press_serial = serial;
|
||||
|
||||
if (button == BTN_STYLUS)
|
||||
n_button = GDK_BUTTON_SECONDARY;
|
||||
else if (button == BTN_STYLUS2)
|
||||
n_button = GDK_BUTTON_MIDDLE;
|
||||
else if (button == BTN_STYLUS2)
|
||||
n_button = GDK_BUTTON_SECONDARY;
|
||||
else if (button == BTN_STYLUS3)
|
||||
n_button = 8; /* Back */
|
||||
else
|
||||
|
||||
@@ -139,7 +139,6 @@ static GSourceFuncs event_funcs = {
|
||||
|
||||
static GdkSurface *mouse_window = NULL;
|
||||
static GdkSurface *mouse_window_ignored_leave = NULL;
|
||||
static int current_x, current_y;
|
||||
static int current_root_x, current_root_y;
|
||||
|
||||
static UINT got_gdk_events_message;
|
||||
@@ -1522,14 +1521,15 @@ generate_button_event (GdkEventType type,
|
||||
GdkEvent *event;
|
||||
GdkDeviceManagerWin32 *device_manager;
|
||||
GdkWin32Surface *impl = GDK_WIN32_SURFACE (window);
|
||||
double x, y;
|
||||
|
||||
if (_gdk_input_ignore_core > 0)
|
||||
return;
|
||||
|
||||
device_manager = GDK_DEVICE_MANAGER_WIN32 (_gdk_device_manager);
|
||||
|
||||
current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
x = (double) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
y = (double) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
|
||||
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
|
||||
_gdk_device_manager->system_pointer);
|
||||
@@ -1541,10 +1541,10 @@ generate_button_event (GdkEventType type,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
build_pointer_event_state (msg),
|
||||
button,
|
||||
current_x,
|
||||
current_y,
|
||||
x,
|
||||
y,
|
||||
NULL);
|
||||
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
}
|
||||
|
||||
@@ -2350,19 +2350,19 @@ gdk_event_translate (MSG *msg,
|
||||
* sends WM_MOUSEMOVE messages after a new window is shown under
|
||||
* the mouse, even if the mouse hasn't moved. This disturbs gtk.
|
||||
*/
|
||||
if (msg->pt.x / impl->surface_scale == current_root_x &&
|
||||
msg->pt.y / impl->surface_scale == current_root_y)
|
||||
if (msg->pt.x == current_root_x &&
|
||||
msg->pt.y == current_root_y)
|
||||
break;
|
||||
|
||||
current_root_x = msg->pt.x / impl->surface_scale;
|
||||
current_root_y = msg->pt.y / impl->surface_scale;
|
||||
current_root_x = msg->pt.x;
|
||||
current_root_y = msg->pt.y;
|
||||
|
||||
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
|
||||
gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
|
||||
gdk_win32_surface_do_move_resize_drag (window, msg->pt.x, msg->pt.y);
|
||||
else if (_gdk_input_ignore_core == 0)
|
||||
{
|
||||
current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
double x = (double) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
double y = (double) GET_Y_LPARAM (msg->lParam) / impl->surface_scale;
|
||||
|
||||
_gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
|
||||
_gdk_device_manager->system_pointer);
|
||||
@@ -2372,8 +2372,8 @@ gdk_event_translate (MSG *msg,
|
||||
NULL,
|
||||
_gdk_win32_get_next_tick (msg->time),
|
||||
build_pointer_event_state (msg),
|
||||
current_x,
|
||||
current_y,
|
||||
x,
|
||||
y,
|
||||
NULL);
|
||||
|
||||
_gdk_win32_append_event (event);
|
||||
|
||||
@@ -271,9 +271,10 @@ winpointer_make_event (GdkDeviceWinpointer *device,
|
||||
y /= impl->surface_scale;
|
||||
|
||||
state = 0;
|
||||
if (info->dwKeyStates & POINTER_MOD_CTRL)
|
||||
/* Note that info->dwKeyStates is not reliable, use GetKeyState() */
|
||||
if (GetKeyState (VK_CONTROL) < 0)
|
||||
state |= GDK_CONTROL_MASK;
|
||||
if (info->dwKeyStates & POINTER_MOD_SHIFT)
|
||||
if (GetKeyState (VK_SHIFT) < 0)
|
||||
state |= GDK_SHIFT_MASK;
|
||||
if (GetKeyState (VK_MENU) < 0)
|
||||
state |= GDK_ALT_MASK;
|
||||
|
||||
@@ -3535,6 +3535,8 @@ setup_drag_move_resize_context (GdkSurface *surface,
|
||||
context->button = button;
|
||||
context->start_root_x = root_x;
|
||||
context->start_root_y = root_y;
|
||||
context->current_root_x = root_x;
|
||||
context->current_root_y = root_y;
|
||||
context->timestamp = timestamp;
|
||||
context->start_rect = rect;
|
||||
|
||||
@@ -3650,6 +3652,16 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
|
||||
if (!_gdk_win32_get_window_rect (window, &rect))
|
||||
return;
|
||||
|
||||
x /= impl->surface_scale;
|
||||
y /= impl->surface_scale;
|
||||
|
||||
if (context->current_root_x == x &&
|
||||
context->current_root_y == y)
|
||||
return;
|
||||
|
||||
context->current_root_x = x;
|
||||
context->current_root_y = y;
|
||||
|
||||
new_rect = context->start_rect;
|
||||
diffx = (x - context->start_root_x) * impl->surface_scale;
|
||||
diffy = (y - context->start_root_y) * impl->surface_scale;
|
||||
|
||||
@@ -137,6 +137,12 @@ struct _GdkW32DragMoveResizeContext
|
||||
int start_root_x;
|
||||
int start_root_y;
|
||||
|
||||
/* Last processed cursor position. Values are divided by the window
|
||||
* scale.
|
||||
*/
|
||||
int current_root_x;
|
||||
int current_root_y;
|
||||
|
||||
/* Initial window rectangle (position and size).
|
||||
* The window is resized/moved relative to this (see start_root_*).
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,12 @@ void main() {
|
||||
uniform int u_mode;
|
||||
uniform sampler2D u_mask;
|
||||
|
||||
float
|
||||
luminance (vec3 color)
|
||||
{
|
||||
return dot (vec3 (0.2126, 0.7152, 0.0722), color);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 source = GskTexture(u_source, vUv);
|
||||
vec4 mask = GskTexture(u_mask, vUv);
|
||||
@@ -23,9 +29,9 @@ void main() {
|
||||
else if (u_mode == 1)
|
||||
mask_value = 1.0 - mask.a;
|
||||
else if (u_mode == 2)
|
||||
mask_value = (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a;
|
||||
mask_value = luminance (mask.rgb);
|
||||
else if (u_mode == 3)
|
||||
mask_value = 1.0 - (0.2126 * mask.r + 0.7152 * mask.g + 0.0722 * mask.b) * mask.a;
|
||||
mask_value = mask.a - luminance (mask.rgb);
|
||||
else
|
||||
mask_value = 0.0;
|
||||
|
||||
|
||||
@@ -2421,6 +2421,7 @@ gsk_inset_shadow_node_new (const GskRoundedRect *outline,
|
||||
|
||||
g_return_val_if_fail (outline != NULL, NULL);
|
||||
g_return_val_if_fail (color != NULL, NULL);
|
||||
g_return_val_if_fail (blur_radius >= 0, NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_INSET_SHADOW_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
@@ -2696,7 +2697,7 @@ gsk_outset_shadow_node_diff (GskRenderNode *node1,
|
||||
|
||||
static void
|
||||
gsk_outset_shadow_node_class_init (gpointer g_class,
|
||||
gpointer class_data)
|
||||
gpointer class_data)
|
||||
{
|
||||
GskRenderNodeClass *node_class = g_class;
|
||||
|
||||
@@ -2734,6 +2735,7 @@ gsk_outset_shadow_node_new (const GskRoundedRect *outline,
|
||||
|
||||
g_return_val_if_fail (outline != NULL, NULL);
|
||||
g_return_val_if_fail (color != NULL, NULL);
|
||||
g_return_val_if_fail (blur_radius >= 0, NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_OUTSET_SHADOW_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
@@ -3700,8 +3702,7 @@ gsk_color_matrix_node_finalize (GskRenderNode *node)
|
||||
static void
|
||||
apply_color_matrix_to_pattern (cairo_pattern_t *pattern,
|
||||
const graphene_matrix_t *color_matrix,
|
||||
const graphene_vec4_t *color_offset,
|
||||
gboolean multiply_alpha)
|
||||
const graphene_vec4_t *color_offset)
|
||||
{
|
||||
cairo_surface_t *surface, *image_surface;
|
||||
guchar *data;
|
||||
@@ -3739,13 +3740,6 @@ apply_color_matrix_to_pattern (cairo_pattern_t *pattern,
|
||||
graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel);
|
||||
}
|
||||
|
||||
if (multiply_alpha)
|
||||
graphene_vec4_init (&pixel,
|
||||
graphene_vec4_get_x (&pixel),
|
||||
graphene_vec4_get_y (&pixel),
|
||||
graphene_vec4_get_z (&pixel),
|
||||
alpha * graphene_vec4_get_w (&pixel));
|
||||
|
||||
graphene_vec4_add (&pixel, color_offset, &pixel);
|
||||
|
||||
alpha = graphene_vec4_get_w (&pixel);
|
||||
@@ -3768,6 +3762,8 @@ apply_color_matrix_to_pattern (cairo_pattern_t *pattern,
|
||||
|
||||
cairo_surface_mark_dirty (image_surface);
|
||||
cairo_surface_unmap_image (surface, image_surface);
|
||||
/* https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/487 */
|
||||
cairo_surface_mark_dirty (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3789,7 +3785,7 @@ gsk_color_matrix_node_draw (GskRenderNode *node,
|
||||
|
||||
pattern = cairo_pop_group (cr);
|
||||
|
||||
apply_color_matrix_to_pattern (pattern, &self->color_matrix, &self->color_offset, FALSE);
|
||||
apply_color_matrix_to_pattern (pattern, &self->color_matrix, &self->color_offset);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
@@ -5650,6 +5646,50 @@ gsk_mask_node_finalize (GskRenderNode *node)
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_luminance_to_pattern (cairo_pattern_t *pattern,
|
||||
gboolean invert_luminance)
|
||||
{
|
||||
cairo_surface_t *surface, *image_surface;
|
||||
guchar *data;
|
||||
gsize x, y, width, height, stride;
|
||||
int red, green, blue, alpha, luminance;
|
||||
guint32* pixel_data;
|
||||
|
||||
cairo_pattern_get_surface (pattern, &surface);
|
||||
image_surface = cairo_surface_map_to_image (surface, NULL);
|
||||
|
||||
data = cairo_image_surface_get_data (image_surface);
|
||||
width = cairo_image_surface_get_width (image_surface);
|
||||
height = cairo_image_surface_get_height (image_surface);
|
||||
stride = cairo_image_surface_get_stride (image_surface);
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
pixel_data = (guint32 *) data;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
alpha = (pixel_data[x] >> 24) & 0xFF;
|
||||
red = (pixel_data[x] >> 16) & 0xFF;
|
||||
green = (pixel_data[x] >> 8) & 0xFF;
|
||||
blue = (pixel_data[x] >> 0) & 0xFF;
|
||||
|
||||
luminance = 2126 * red + 7152 * green + 722 * blue;
|
||||
if (invert_luminance)
|
||||
luminance = 10000 * alpha - luminance;
|
||||
luminance = (luminance + 5000) / 10000;
|
||||
|
||||
pixel_data[x] = luminance * 0x1010101;
|
||||
}
|
||||
data += stride;
|
||||
}
|
||||
|
||||
cairo_surface_mark_dirty (image_surface);
|
||||
cairo_surface_unmap_image (surface, image_surface);
|
||||
/* https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/487 */
|
||||
cairo_surface_mark_dirty (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_mask_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
@@ -5672,28 +5712,18 @@ gsk_mask_node_draw (GskRenderNode *node,
|
||||
case GSK_MASK_MODE_ALPHA:
|
||||
break;
|
||||
case GSK_MASK_MODE_INVERTED_ALPHA:
|
||||
graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, -1 });
|
||||
graphene_vec4_init (&color_offset, 0, 0, 0, 1);
|
||||
apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, FALSE);
|
||||
graphene_matrix_init_from_float (&color_matrix, (float[]){ 0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
-1, -1, -1, -1 });
|
||||
graphene_vec4_init (&color_offset, 1, 1, 1, 1);
|
||||
apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset);
|
||||
break;
|
||||
case GSK_MASK_MODE_LUMINANCE:
|
||||
graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, 0.2126,
|
||||
0, 1, 0, 0.7152,
|
||||
0, 0, 1, 0.0722,
|
||||
0, 0, 0, 0 });
|
||||
graphene_vec4_init (&color_offset, 0, 0, 0, 0);
|
||||
apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE);
|
||||
apply_luminance_to_pattern (mask_pattern, FALSE);
|
||||
break;
|
||||
case GSK_MASK_MODE_INVERTED_LUMINANCE:
|
||||
graphene_matrix_init_from_float (&color_matrix, (float[]){ 1, 0, 0, -0.2126,
|
||||
0, 1, 0, -0.7152,
|
||||
0, 0, 1, -0.0722,
|
||||
0, 0, 0, 0 });
|
||||
graphene_vec4_init (&color_offset, 0, 0, 0, 1);
|
||||
apply_color_matrix_to_pattern (mask_pattern, &color_matrix, &color_offset, TRUE);
|
||||
apply_luminance_to_pattern (mask_pattern, TRUE);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@@ -5715,6 +5745,12 @@ gsk_mask_node_diff (GskRenderNode *node1,
|
||||
GskMaskNode *self1 = (GskMaskNode *) node1;
|
||||
GskMaskNode *self2 = (GskMaskNode *) node2;
|
||||
|
||||
if (self1->mask_mode != self2->mask_mode)
|
||||
{
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_render_node_diff (self1->source, self2->source, region);
|
||||
gsk_render_node_diff (self1->mask, self2->mask, region);
|
||||
}
|
||||
|
||||
@@ -453,6 +453,21 @@ parse_double (GtkCssParser *parser,
|
||||
return gtk_css_parser_consume_number (parser, out_double);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_positive_double (GtkCssParser *parser,
|
||||
Context *context,
|
||||
gpointer out_double)
|
||||
{
|
||||
if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNED_NUMBER)
|
||||
|| gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNED_INTEGER))
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Expected a positive number");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return gtk_css_parser_consume_number (parser, out_double);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_point (GtkCssParser *parser,
|
||||
Context *context,
|
||||
@@ -1242,10 +1257,10 @@ parse_radial_gradient_node_internal (GtkCssParser *parser,
|
||||
const Declaration declarations[] = {
|
||||
{ "bounds", parse_rect, NULL, &bounds },
|
||||
{ "center", parse_point, NULL, ¢er },
|
||||
{ "hradius", parse_double, NULL, &hradius },
|
||||
{ "vradius", parse_double, NULL, &vradius },
|
||||
{ "start", parse_double, NULL, &start },
|
||||
{ "end", parse_double, NULL, &end },
|
||||
{ "hradius", parse_positive_double, NULL, &hradius },
|
||||
{ "vradius", parse_positive_double, NULL, &vradius },
|
||||
{ "start", parse_positive_double, NULL, &start },
|
||||
{ "end", parse_positive_double, NULL, &end },
|
||||
{ "stops", parse_stops, clear_stops, &stops },
|
||||
};
|
||||
GskRenderNode *result;
|
||||
@@ -1335,7 +1350,7 @@ parse_inset_shadow_node (GtkCssParser *parser,
|
||||
{ "dx", parse_double, NULL, &dx },
|
||||
{ "dy", parse_double, NULL, &dy },
|
||||
{ "spread", parse_double, NULL, &spread },
|
||||
{ "blur", parse_double, NULL, &blur }
|
||||
{ "blur", parse_positive_double, NULL, &blur }
|
||||
};
|
||||
|
||||
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
|
||||
@@ -1737,7 +1752,7 @@ parse_outset_shadow_node (GtkCssParser *parser,
|
||||
{ "dx", parse_double, NULL, &dx },
|
||||
{ "dy", parse_double, NULL, &dy },
|
||||
{ "spread", parse_double, NULL, &spread },
|
||||
{ "blur", parse_double, NULL, &blur }
|
||||
{ "blur", parse_positive_double, NULL, &blur }
|
||||
};
|
||||
|
||||
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
|
||||
@@ -2017,7 +2032,7 @@ parse_blur_node (GtkCssParser *parser,
|
||||
GskRenderNode *child = NULL;
|
||||
double blur_radius = 1.0;
|
||||
const Declaration declarations[] = {
|
||||
{ "blur", parse_double, NULL, &blur_radius },
|
||||
{ "blur", parse_positive_double, NULL, &blur_radius },
|
||||
{ "child", parse_node, clear_node, &child },
|
||||
};
|
||||
GskRenderNode *result;
|
||||
|
||||
@@ -8,138 +8,123 @@ name = os.path.splitext(os.path.basename(sys.argv[1]))[0]
|
||||
var_name = "gsk_vulkan_" + name.replace('-', '_')
|
||||
struct_name = "GskVulkan" + name.title().replace('-', '') + "Instance"
|
||||
|
||||
lines = open (sys.argv[1]).readlines()
|
||||
matches = []
|
||||
with open(sys.argv[1]) as f:
|
||||
lines = f.readlines()
|
||||
matches = []
|
||||
|
||||
for line in lines:
|
||||
match = re.search("^layout\(location = ([0-9]+)\) in ([a-z0-9]+) ([a-zA-Z0-9]+);$", line)
|
||||
if not match:
|
||||
if re.search("layout.*\sin\s.*", line):
|
||||
raise Exception("Failed to parse file")
|
||||
continue;
|
||||
if not match.group(3).startswith('in'):
|
||||
raise Exception("Variable doesn't start with 'in'")
|
||||
matches.append({ 'name': ''.join('_' + char.lower() if char.isupper() else char for char in match.group(3))[3:],
|
||||
'location': int(match.group(1)),
|
||||
'type': match.group(2) })
|
||||
for line in lines:
|
||||
match = re.search(r"^layout\(location = ([0-9]+)\) in ([a-z0-9]+) ([a-zA-Z0-9]+);$", line)
|
||||
if not match:
|
||||
if re.search(r"layout.*\sin\s.*", line):
|
||||
raise Exception("Failed to parse file")
|
||||
continue
|
||||
if not match.group(3).startswith('in'):
|
||||
raise Exception("Variable doesn't start with 'in'")
|
||||
matches.append({'name': ''.join('_' + char.lower() if char.isupper() else char for char in match.group(3))[3:],
|
||||
'location': int(match.group(1)),
|
||||
'type': match.group(2)})
|
||||
|
||||
print(
|
||||
f'''#pragma once
|
||||
print(f'''/* This file is auto-generated; any change will not be preserved */
|
||||
#pragma once
|
||||
|
||||
typedef struct _{struct_name} {struct_name};
|
||||
|
||||
struct _{struct_name} {{''')
|
||||
|
||||
expected = 0;
|
||||
expected = 0
|
||||
for match in matches:
|
||||
if expected != int(match['location']):
|
||||
raise Exception(f"Should be layout location {expected} but is {match['location']}")
|
||||
raise Exception(f"Should be layout location {expected} but is {match['location']}") # noqa
|
||||
|
||||
match match['type']:
|
||||
case "float":
|
||||
print(f" float {match['name']};")
|
||||
expected += 1
|
||||
case "int":
|
||||
print(f" gint32 {match['name']};")
|
||||
expected += 1
|
||||
case "uint":
|
||||
print(f" guint32 {match['name']};")
|
||||
expected += 1
|
||||
case "uvec2":
|
||||
print(f" guint32 {match['name']}[2];")
|
||||
expected += 1
|
||||
case "vec2":
|
||||
print(f" float {match['name']}[2];")
|
||||
expected += 1
|
||||
case "vec4":
|
||||
print(f" float {match['name']}[4];")
|
||||
expected += 1
|
||||
case "mat3x4":
|
||||
print(f" float {match['name']}[12];")
|
||||
expected += 3
|
||||
case "mat4":
|
||||
print(f" float {match['name']}[16];")
|
||||
expected += 4
|
||||
case _:
|
||||
raise Exception(f"Don't know what a {match['type']} is")
|
||||
if match['type'] == 'float':
|
||||
print(f" float {match['name']};")
|
||||
expected += 1
|
||||
elif match['type'] == 'int':
|
||||
print(f" gint32 {match['name']};")
|
||||
expected += 1
|
||||
elif match['type'] == 'uint':
|
||||
print(f" guint32 {match['name']};")
|
||||
expected += 1
|
||||
elif match['type'] == 'uvec2':
|
||||
print(f" guint32 {match['name']}[2];")
|
||||
expected += 1
|
||||
elif match['type'] == 'vec2':
|
||||
print(f" float {match['name']}[2];")
|
||||
expected += 1
|
||||
elif match['type'] == 'vec4':
|
||||
print(f" float {match['name']}[4];")
|
||||
expected += 1
|
||||
elif match['type'] == 'mat3x4':
|
||||
print(f" float {match['name']}[12];")
|
||||
expected += 3
|
||||
elif match['type'] == 'mat4':
|
||||
print(f" float {match['name']}[16];")
|
||||
expected += 4
|
||||
else:
|
||||
raise Exception(f"Don't know what a {match['type']} is")
|
||||
|
||||
print(
|
||||
'''};
|
||||
print('''};
|
||||
''')
|
||||
|
||||
print(
|
||||
f'''static const VkPipelineVertexInputStateCreateInfo {var_name}_info = {{
|
||||
print(f'''static const VkPipelineVertexInputStateCreateInfo {var_name}_info = {{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[1]) {{
|
||||
{{
|
||||
.binding = 0,
|
||||
.stride = sizeof ({struct_name}),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
|
||||
.binding = 0,
|
||||
.stride = sizeof ({struct_name}),
|
||||
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
|
||||
}}
|
||||
}},
|
||||
.vertexAttributeDescriptionCount = {expected},
|
||||
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[{expected}]) {{''')
|
||||
|
||||
for match in matches:
|
||||
match match['type']:
|
||||
case "float":
|
||||
print(
|
||||
f''' {{
|
||||
if match['type'] == 'float':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "int":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'int':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32_SINT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "uint":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'uint':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32_UINT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "uvec2":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'uvec2':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_UINT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "vec2":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'vec2':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "vec4":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'vec4':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}),
|
||||
}},''')
|
||||
|
||||
case "mat3x4":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'mat3x4':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
@@ -157,10 +142,8 @@ f''' {{
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 8,
|
||||
}},''')
|
||||
|
||||
case "mat4":
|
||||
print(
|
||||
f''' {{
|
||||
elif match['type'] == 'mat4':
|
||||
print(f''' {{
|
||||
.location = {match['location']},
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
@@ -184,9 +167,8 @@ f''' {{
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET({struct_name}, {match['name']}) + sizeof (float) * 12,
|
||||
}},''')
|
||||
|
||||
case _:
|
||||
raise Exception(f"Don't know what a {match['type']} is")
|
||||
else:
|
||||
raise Exception(f"Don't know what a {match['type']} is")
|
||||
|
||||
print(" },")
|
||||
print("};")
|
||||
|
||||
@@ -87,8 +87,10 @@ foreach shader: gsk_private_vulkan_shaders
|
||||
'-o', '@OUTPUT@'
|
||||
])
|
||||
gsk_private_vulkan_compiled_shaders_deps += [compiled_shader, compiled_clip_shader, compiled_clip_rounded_shader]
|
||||
gsk_private_vulkan_compiled_shaders += [spv_shader, clip_spv_shader, clip_rounded_spv_shader]
|
||||
else
|
||||
gsk_private_vulkan_compiled_shaders += files(spv_shader, clip_spv_shader, clip_rounded_spv_shader)
|
||||
endif
|
||||
gsk_private_vulkan_compiled_shaders += files(spv_shader, clip_spv_shader, clip_rounded_spv_shader)
|
||||
endforeach
|
||||
|
||||
foreach shader: gsk_private_vulkan_vertex_shaders
|
||||
|
||||
@@ -733,7 +733,7 @@ gtk_alert_dialog_choose (GtkAlertDialog *self,
|
||||
* and returns the index of the button that was clicked.
|
||||
*
|
||||
* Returns: the index of the button that was clicked, or -1 if
|
||||
* the dialog was cancelled and `[property@Gtk.AlertDialog:cancel-button]
|
||||
* the dialog was cancelled and [property@Gtk.AlertDialog:cancel-button]
|
||||
* is not set
|
||||
*
|
||||
* Since: 4.10
|
||||
|
||||
@@ -1333,6 +1333,8 @@ gtk_at_context_get_text_accumulate (GtkATContext *self,
|
||||
GtkATContext *rel_context = gtk_accessible_get_at_context (rel);
|
||||
|
||||
gtk_at_context_get_text_accumulate (rel_context, nodes, s, property, relation, FALSE, TRUE);
|
||||
|
||||
g_object_unref (rel_context);
|
||||
}
|
||||
|
||||
if (s->len > 0)
|
||||
|
||||
@@ -762,6 +762,7 @@ gtk_image_set_from_icon_name (GtkImage *image,
|
||||
_gtk_icon_helper_set_icon_name (image->icon_helper, icon_name);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_ICON_NAME]);
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_STORAGE_TYPE]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (image));
|
||||
}
|
||||
@@ -795,6 +796,7 @@ gtk_image_set_from_gicon (GtkImage *image,
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_GICON]);
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_STORAGE_TYPE]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (image));
|
||||
}
|
||||
@@ -857,6 +859,7 @@ gtk_image_set_from_paintable (GtkImage *image,
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_PAINTABLE]);
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_STORAGE_TYPE]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (image));
|
||||
}
|
||||
@@ -1079,6 +1082,8 @@ gtk_image_set_from_definition (GtkImage *image,
|
||||
gtk_image_notify_for_storage_type (image, gtk_image_definition_get_storage_type (def));
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_STORAGE_TYPE]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (image));
|
||||
}
|
||||
|
||||
|
||||
@@ -2249,7 +2249,7 @@ gtk_list_base_set_anchor (GtkListBase *self,
|
||||
* in front of it.
|
||||
*
|
||||
* Addditionally, there will be @above_below widgets allocated both
|
||||
* before and after the sencter widgets, so the total number of
|
||||
* before and after the center widgets, so the total number of
|
||||
* widgets kept alive is 2 * above_below + center + 1.
|
||||
**/
|
||||
void
|
||||
|
||||
@@ -1356,6 +1356,7 @@ gtk_list_item_manager_ensure_items (GtkListItemManager *self,
|
||||
position + i,
|
||||
item,
|
||||
gtk_selection_model_is_selected (self->model, position + i));
|
||||
g_object_unref (item);
|
||||
gtk_widget_insert_after (tile->widget, self->widget, insert_after);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "gtkmaplistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtksectionmodel.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,8 @@
|
||||
*
|
||||
* `GtkMapListModel` will attempt to discard the mapped objects as soon as
|
||||
* they are no longer needed and recreate them if necessary.
|
||||
*
|
||||
* `GtkMapListModel` passes through sections from the underlying model.
|
||||
*/
|
||||
|
||||
enum {
|
||||
@@ -207,8 +210,43 @@ gtk_map_list_model_model_init (GListModelInterface *iface)
|
||||
iface->get_item = gtk_map_list_model_get_item;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_map_list_model_get_section (GtkSectionModel *model,
|
||||
guint position,
|
||||
guint *out_start,
|
||||
guint *out_end)
|
||||
{
|
||||
GtkMapListModel *self = GTK_MAP_LIST_MODEL (model);
|
||||
|
||||
if (GTK_IS_SECTION_MODEL (self->model))
|
||||
{
|
||||
gtk_section_model_get_section (GTK_SECTION_MODEL (self->model), position, out_start, out_end);
|
||||
return;
|
||||
}
|
||||
|
||||
*out_start = 0;
|
||||
*out_end = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_map_list_model_sections_changed_cb (GtkSectionModel *model,
|
||||
unsigned int position,
|
||||
unsigned int n_items,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_section_model_sections_changed (GTK_SECTION_MODEL (user_data), position, n_items);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_map_list_model_section_model_init (GtkSectionModelInterface *iface)
|
||||
{
|
||||
iface->get_section = gtk_map_list_model_get_section;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkMapListModel, gtk_map_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_map_list_model_model_init))
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_map_list_model_model_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SECTION_MODEL, gtk_map_list_model_section_model_init))
|
||||
|
||||
static void
|
||||
gtk_map_list_model_items_changed_cb (GListModel *model,
|
||||
@@ -337,6 +375,7 @@ gtk_map_list_model_clear_model (GtkMapListModel *self)
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_map_list_model_sections_changed_cb, self);
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_map_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
}
|
||||
@@ -608,6 +647,9 @@ gtk_map_list_model_set_model (GtkMapListModel *self,
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_map_list_model_items_changed_cb), self);
|
||||
added = g_list_model_get_n_items (model);
|
||||
|
||||
if (GTK_IS_SECTION_MODEL (model))
|
||||
g_signal_connect (model, "sections-changed", G_CALLBACK (gtk_map_list_model_sections_changed_cb), self);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -755,6 +755,8 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
|
||||
|
||||
gtk_tooltip_position (tooltip, display, tooltip_widget, device);
|
||||
|
||||
g_signal_emit_by_name (tooltip_widget, "tooltip-show", tooltip);
|
||||
|
||||
gtk_widget_set_visible (GTK_WIDGET (tooltip->window), TRUE);
|
||||
|
||||
/* Now a tooltip is visible again on the display, make sure browse
|
||||
@@ -771,6 +773,8 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
|
||||
static void
|
||||
gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
|
||||
{
|
||||
GtkWidget *tooltip_widget;
|
||||
|
||||
guint timeout = BROWSE_DISABLE_TIMEOUT;
|
||||
|
||||
if (!tooltip)
|
||||
@@ -785,6 +789,7 @@ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
|
||||
if (!GTK_TOOLTIP_VISIBLE (tooltip))
|
||||
return;
|
||||
|
||||
tooltip_widget = tooltip->tooltip_widget;
|
||||
tooltip->tooltip_widget = NULL;
|
||||
|
||||
/* The tooltip is gone, after (by default, should be configurable) 500ms
|
||||
@@ -801,7 +806,10 @@ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
|
||||
}
|
||||
|
||||
if (tooltip->window)
|
||||
gtk_widget_set_visible (tooltip->window, FALSE);
|
||||
{
|
||||
gtk_widget_set_visible (tooltip->window, FALSE);
|
||||
g_signal_emit_by_name (tooltip_widget, "tooltip-hide", tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1065,3 +1073,26 @@ gtk_tooltip_unset_surface (GtkNative *native)
|
||||
gtk_tooltip_set_surface (tooltip, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_tooltip_set_css_class:
|
||||
* @tooltip: a #GtkTooltip
|
||||
* @css_class: (allow-none): a css class name, or %NULL
|
||||
*
|
||||
* This function allows to add a single css class
|
||||
* to @tooltip window, that means it will remove any
|
||||
* css class previously added by this function before
|
||||
* adding @css_class as the currently active one.
|
||||
*
|
||||
* if %NULL is passed then any active css class (which
|
||||
* was added by this function) will be cleared.
|
||||
*
|
||||
* Since: 4.12
|
||||
*/
|
||||
void
|
||||
gtk_tooltip_set_css_class (GtkTooltip *tooltip,
|
||||
const char *css_class)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
|
||||
|
||||
gtk_tooltip_window_set_css_class (GTK_TOOLTIP_WINDOW (tooltip->window), css_class);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ void gtk_tooltip_set_custom (GtkTooltip *tooltip,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_tooltip_set_tip_area (GtkTooltip *tooltip,
|
||||
const GdkRectangle *rect);
|
||||
GDK_AVAILABLE_IN_4_12
|
||||
void gtk_tooltip_set_css_class (GtkTooltip *tooltip,
|
||||
const char *css_class);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkTooltip, g_object_unref)
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ struct _GtkTooltipWindow
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
GtkWidget *custom_widget;
|
||||
char *css_class;
|
||||
};
|
||||
|
||||
struct _GtkTooltipWindowClass
|
||||
@@ -392,6 +393,7 @@ static void
|
||||
gtk_tooltip_window_init (GtkTooltipWindow *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
self->css_class = NULL;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -520,3 +522,30 @@ gtk_tooltip_window_position (GtkTooltipWindow *window,
|
||||
|
||||
gtk_tooltip_window_relayout (window);
|
||||
}
|
||||
|
||||
/* See gtk_tooltip_set_css_class() description */
|
||||
void
|
||||
gtk_tooltip_window_set_css_class (GtkTooltipWindow *window,
|
||||
const char *css_class)
|
||||
{
|
||||
GtkWidget *wid = GTK_WIDGET (window);
|
||||
|
||||
if (g_strcmp0 (window->css_class, css_class) == 0)
|
||||
return;
|
||||
|
||||
if (css_class)
|
||||
{
|
||||
if (window->css_class)
|
||||
{
|
||||
gtk_widget_remove_css_class (wid, window->css_class);
|
||||
g_free (window->css_class);
|
||||
}
|
||||
window->css_class = g_strdup (css_class);
|
||||
gtk_widget_add_css_class (wid, css_class);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_remove_css_class (wid, window->css_class);
|
||||
g_clear_pointer (&window->css_class, g_free);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ void gtk_tooltip_window_position (GtkTooltipWindo
|
||||
GdkAnchorHints anchor_hints,
|
||||
int dx,
|
||||
int dy);
|
||||
void gtk_tooltip_window_set_css_class (GtkTooltipWindow *window,
|
||||
const char *css_class);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -502,6 +502,8 @@ enum {
|
||||
MOVE_FOCUS,
|
||||
KEYNAV_FAILED,
|
||||
QUERY_TOOLTIP,
|
||||
TOOLTIP_SHOW,
|
||||
TOOLTIP_HIDE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@@ -1926,6 +1928,38 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
|
||||
gtk_widget_class_set_css_name (klass, I_("widget"));
|
||||
klass->priv->accessible_role = GTK_ACCESSIBLE_ROLE_WIDGET;
|
||||
|
||||
/**
|
||||
* GtkWidget::tooltip-show:
|
||||
* @widget: the object which received the signal.
|
||||
*
|
||||
* Emitted when a tooltip is about to be shown on @widget.
|
||||
*/
|
||||
widget_signals[TOOLTIP_SHOW] =
|
||||
g_signal_new (I_("tooltip-show"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_TOOLTIP);
|
||||
|
||||
/**
|
||||
* GtkWidget::tooltip-hide:
|
||||
* @widget: the object which received the signal.
|
||||
*
|
||||
* Emitted when a tooltip on @widget has just been hidden.
|
||||
*/
|
||||
widget_signals[TOOLTIP_HIDE] =
|
||||
g_signal_new (I_("tooltip-hide"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_TOOLTIP);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
extern IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
static inline HMODULE
|
||||
this_module ()
|
||||
this_module (void)
|
||||
{
|
||||
return (HMODULE) &__ImageBase;
|
||||
}
|
||||
|
||||
@@ -243,6 +243,8 @@ update_name (GtkInspectorA11y *sl)
|
||||
|
||||
name = gtk_at_context_get_name (context);
|
||||
gtk_label_set_label (GTK_LABEL (sl->name), name);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -257,6 +259,8 @@ update_description (GtkInspectorA11y *sl)
|
||||
|
||||
description = gtk_at_context_get_description (context);
|
||||
gtk_label_set_label (GTK_LABEL (sl->description), description);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -110,12 +110,11 @@ static struct {
|
||||
};
|
||||
|
||||
static FixSeverity
|
||||
check_accessibility_errors (GtkWidget *widget,
|
||||
GArray *context_elements,
|
||||
char **hint)
|
||||
check_accessibility_errors (GtkATContext *context,
|
||||
GtkAccessibleRole role,
|
||||
GArray *context_elements,
|
||||
char **hint)
|
||||
{
|
||||
GtkAccessibleRole role;
|
||||
GtkATContext *context;
|
||||
gboolean label_set;
|
||||
const char *role_name;
|
||||
GEnumClass *states;
|
||||
@@ -124,11 +123,8 @@ check_accessibility_errors (GtkWidget *widget,
|
||||
gboolean has_context;
|
||||
|
||||
*hint = NULL;
|
||||
|
||||
role = gtk_accessible_get_accessible_role (GTK_ACCESSIBLE (widget));
|
||||
role_name = gtk_accessible_role_to_name (role, NULL);
|
||||
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
|
||||
if (!gtk_at_context_is_realized (context))
|
||||
gtk_at_context_realize (context);
|
||||
|
||||
@@ -314,6 +310,23 @@ check_accessibility_errors (GtkWidget *widget,
|
||||
return SEVERITY_GOOD;
|
||||
}
|
||||
|
||||
static FixSeverity
|
||||
check_widget_accessibility_errors (GtkWidget *widget,
|
||||
GArray *context_elements,
|
||||
char **hint)
|
||||
{
|
||||
GtkAccessibleRole role;
|
||||
GtkATContext *context;
|
||||
FixSeverity ret;
|
||||
|
||||
role = gtk_accessible_get_accessible_role (GTK_ACCESSIBLE (widget));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
|
||||
ret = check_accessibility_errors (context, role, context_elements, hint);
|
||||
g_object_unref (context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
recurse_child_widgets (GtkA11yOverlay *self,
|
||||
GtkWidget *widget,
|
||||
@@ -327,7 +340,7 @@ recurse_child_widgets (GtkA11yOverlay *self,
|
||||
if (!gtk_widget_get_mapped (widget))
|
||||
return;
|
||||
|
||||
severity = check_accessibility_errors (widget, self->context, &hint);
|
||||
severity = check_widget_accessibility_errors (widget, self->context, &hint);
|
||||
|
||||
if (severity != SEVERITY_GOOD)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('gtk', 'c',
|
||||
version: '4.11.4',
|
||||
version: '4.11.5',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
'warning_level=1',
|
||||
|
||||
@@ -6,6 +6,7 @@ static void
|
||||
test_name_content (void)
|
||||
{
|
||||
GtkWidget *window, *label1, *label2, *box, *button;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
|
||||
label1 = gtk_label_new ("a");
|
||||
@@ -21,24 +22,32 @@ test_name_content (void)
|
||||
gtk_window_set_child (GTK_WINDOW (window), button);
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (label1)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (label1));
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "a");
|
||||
g_free (name);
|
||||
g_object_unref (context);
|
||||
|
||||
/* this is because generic doesn't allow naming */
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (box)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (box));
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "");
|
||||
g_free (name);
|
||||
g_object_unref (context);
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (button)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (button));
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "a b");
|
||||
g_free (name);
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_widget_set_visible (label2, FALSE);
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (button)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (button));
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "a");
|
||||
g_free (name);
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
@@ -47,6 +56,7 @@ static void
|
||||
test_name_tooltip (void)
|
||||
{
|
||||
GtkWidget *window, *image;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
|
||||
image = gtk_image_new ();
|
||||
@@ -57,10 +67,14 @@ test_name_tooltip (void)
|
||||
|
||||
gtk_widget_set_tooltip_text (image, "tooltip");
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (image)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (image));
|
||||
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "tooltip");
|
||||
g_free (name);
|
||||
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
@@ -68,6 +82,7 @@ static void
|
||||
test_name_menubutton (void)
|
||||
{
|
||||
GtkWidget *window, *widget;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
|
||||
widget = gtk_menu_button_new ();
|
||||
@@ -79,10 +94,14 @@ test_name_menubutton (void)
|
||||
|
||||
gtk_widget_set_tooltip_text (widget, "tooltip");
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
|
||||
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "tooltip");
|
||||
g_free (name);
|
||||
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
@@ -90,6 +109,7 @@ static void
|
||||
test_name_label (void)
|
||||
{
|
||||
GtkWidget *window, *image;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
char *desc;
|
||||
|
||||
@@ -108,8 +128,10 @@ test_name_label (void)
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "label",
|
||||
-1);
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (image)));
|
||||
desc = gtk_at_context_get_description (gtk_accessible_get_at_context (GTK_ACCESSIBLE (image)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (image));
|
||||
|
||||
name = gtk_at_context_get_name (context);
|
||||
desc = gtk_at_context_get_description (context);
|
||||
|
||||
g_assert_cmpstr (name, ==, "label");
|
||||
g_assert_cmpstr (desc, ==, "tooltip");
|
||||
@@ -117,6 +139,8 @@ test_name_label (void)
|
||||
g_free (name);
|
||||
g_free (desc);
|
||||
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
@@ -124,6 +148,7 @@ static void
|
||||
test_name_prohibited (void)
|
||||
{
|
||||
GtkWidget *window, *widget;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
char *desc;
|
||||
|
||||
@@ -136,8 +161,10 @@ test_name_prohibited (void)
|
||||
gtk_window_set_child (GTK_WINDOW (window), widget);
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)));
|
||||
desc = gtk_at_context_get_description (gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget)));
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
|
||||
|
||||
name = gtk_at_context_get_name (context);
|
||||
desc = gtk_at_context_get_description (context);
|
||||
|
||||
g_assert_cmpstr (name, ==, "");
|
||||
g_assert_cmpstr (desc, ==, "");
|
||||
@@ -145,6 +172,8 @@ test_name_prohibited (void)
|
||||
g_free (name);
|
||||
g_free (desc);
|
||||
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
@@ -152,6 +181,7 @@ static void
|
||||
test_name_range (void)
|
||||
{
|
||||
GtkWidget *window, *scale;
|
||||
GtkATContext *context;
|
||||
char *name;
|
||||
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 100, 10);
|
||||
@@ -160,16 +190,20 @@ test_name_range (void)
|
||||
gtk_window_set_child (GTK_WINDOW (window), scale);
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (scale));
|
||||
|
||||
g_assert_true (gtk_accessible_get_accessible_role (GTK_ACCESSIBLE (scale)) == GTK_ACCESSIBLE_ROLE_SLIDER);
|
||||
g_assert_true (gtk_at_context_get_accessible_role (gtk_accessible_get_at_context (GTK_ACCESSIBLE (scale))) == GTK_ACCESSIBLE_ROLE_SLIDER);
|
||||
g_assert_true (gtk_at_context_get_accessible_role (context) == GTK_ACCESSIBLE_ROLE_SLIDER);
|
||||
|
||||
gtk_range_set_value (GTK_RANGE (scale), 50);
|
||||
|
||||
name = gtk_at_context_get_name (gtk_accessible_get_at_context (GTK_ACCESSIBLE (scale)));
|
||||
name = gtk_at_context_get_name (context);
|
||||
g_assert_cmpstr (name, ==, "50");
|
||||
|
||||
g_free (name);
|
||||
|
||||
g_object_unref (context);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
|
||||
14
testsuite/gsk/compare/mask-clipped-inverted-alpha.node
Normal file
14
testsuite/gsk/compare/mask-clipped-inverted-alpha.node
Normal file
@@ -0,0 +1,14 @@
|
||||
clip {
|
||||
clip: 0 0 40 40;
|
||||
child: mask {
|
||||
mode: inverted-alpha;
|
||||
source: color {
|
||||
bounds: 0 0 100 100;
|
||||
color: rebeccapurple;
|
||||
}
|
||||
mask: color {
|
||||
bounds: 40 40 60 60;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
testsuite/gsk/compare/mask-clipped-inverted-alpha.png
Normal file
BIN
testsuite/gsk/compare/mask-clipped-inverted-alpha.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 129 B |
43
testsuite/gsk/compare/mask-modes-with-alpha.node
Normal file
43
testsuite/gsk/compare/mask-modes-with-alpha.node
Normal file
@@ -0,0 +1,43 @@
|
||||
mask {
|
||||
source: color {
|
||||
bounds: 0 0 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
mask: color {
|
||||
bounds: 0 0 50 50;
|
||||
color: rgba(204,204,204,0.666667);
|
||||
}
|
||||
}
|
||||
mask {
|
||||
mode: luminance;
|
||||
source: color {
|
||||
bounds: 50 0 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
mask: color {
|
||||
bounds: 50 0 50 50;
|
||||
color: rgba(204,204,204,0.666667);
|
||||
}
|
||||
}
|
||||
mask {
|
||||
mode: inverted-alpha;
|
||||
source: color {
|
||||
bounds: 0 50 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
mask: color {
|
||||
bounds: 0 50 50 50;
|
||||
color: rgba(204,204,204,0.666667);
|
||||
}
|
||||
}
|
||||
mask {
|
||||
mode: inverted-luminance;
|
||||
source: color {
|
||||
bounds: 50 50 50 50;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
mask: color {
|
||||
bounds: 50 50 50 50;
|
||||
color: rgba(204,204,204,0.666667);
|
||||
}
|
||||
}
|
||||
BIN
testsuite/gsk/compare/mask-modes-with-alpha.png
Normal file
BIN
testsuite/gsk/compare/mask-modes-with-alpha.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 337 B |
Binary file not shown.
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 223 B |
@@ -65,7 +65,9 @@ compare_render_tests = [
|
||||
'invalid-transform',
|
||||
'issue-3615',
|
||||
'mask',
|
||||
'mask-clipped-inverted-alpha',
|
||||
'mask-modes',
|
||||
'mask-modes-with-alpha',
|
||||
'nested-rounded-clips',
|
||||
'opacity_clip',
|
||||
'opacity-overdraw',
|
||||
|
||||
@@ -52,6 +52,41 @@ model_to_string (GListModel *model)
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
section_model_to_string (GListModel *model)
|
||||
{
|
||||
GString *string = g_string_new (NULL);
|
||||
guint i, s, e;
|
||||
|
||||
if (!GTK_IS_SECTION_MODEL (model))
|
||||
return model_to_string (model);
|
||||
|
||||
i = 0;
|
||||
while (i < g_list_model_get_n_items (model))
|
||||
{
|
||||
gtk_section_model_get_section (GTK_SECTION_MODEL (model), i, &s, &e);
|
||||
g_assert (s == i);
|
||||
|
||||
if (i > 0)
|
||||
g_string_append (string, " ");
|
||||
|
||||
g_string_append (string, "[");
|
||||
|
||||
for (; i < e; i++)
|
||||
{
|
||||
if (i > s)
|
||||
g_string_append (string, " ");
|
||||
|
||||
g_string_append_printf (string, "%u", get (model, i));
|
||||
}
|
||||
|
||||
g_string_append (string, "]");
|
||||
i = e;
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
static GListStore *
|
||||
new_store (guint start,
|
||||
guint end,
|
||||
@@ -106,6 +141,14 @@ add (GListStore *store,
|
||||
g_free (s); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_section_model(model, expected) G_STMT_START{ \
|
||||
char *s = section_model_to_string (G_LIST_MODEL (model)); \
|
||||
if (!g_str_equal (s, expected)) \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#model " == " #expected, s, "==", expected); \
|
||||
g_free (s); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_changes(model, expected) G_STMT_START{ \
|
||||
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
|
||||
if (!g_str_equal (changes->str, expected)) \
|
||||
@@ -164,6 +207,21 @@ items_changed (GListModel *model,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sections_changed (GListModel *model,
|
||||
guint position,
|
||||
guint n_items,
|
||||
GString *changes)
|
||||
{
|
||||
g_assert_true (n_items != 0);
|
||||
|
||||
if (changes->len)
|
||||
g_string_append (changes, ", ");
|
||||
|
||||
g_string_append_printf (changes, "s%u:%u", position, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_n_items (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
@@ -199,17 +257,18 @@ map_multiply (gpointer item,
|
||||
}
|
||||
|
||||
static GtkMapListModel *
|
||||
new_model (GListStore *store)
|
||||
new_model (GListModel *store)
|
||||
{
|
||||
GtkMapListModel *result;
|
||||
GString *changes;
|
||||
|
||||
if (store)
|
||||
g_object_ref (store);
|
||||
result = gtk_map_list_model_new (G_LIST_MODEL (store), map_multiply, GUINT_TO_POINTER (2), NULL);
|
||||
result = gtk_map_list_model_new (store, map_multiply, GUINT_TO_POINTER (2), NULL);
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
|
||||
g_signal_connect (result, "sections-changed", G_CALLBACK (sections_changed), changes);
|
||||
g_signal_connect (result, "notify::n-items", G_CALLBACK (notify_n_items), changes);
|
||||
|
||||
return result;
|
||||
@@ -234,7 +293,7 @@ test_create (void)
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
map = new_model (store);
|
||||
map = new_model (G_LIST_MODEL (store));
|
||||
assert_model (map, "2 4 6 8 10");
|
||||
assert_changes (map, "");
|
||||
|
||||
@@ -275,7 +334,7 @@ test_set_map_func (void)
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
map = new_model (store);
|
||||
map = new_model (G_LIST_MODEL (store));
|
||||
assert_model (map, "2 4 6 8 10");
|
||||
assert_changes (map, "");
|
||||
|
||||
@@ -302,7 +361,7 @@ test_add_items (void)
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
map = new_model (store);
|
||||
map = new_model (G_LIST_MODEL (store));
|
||||
assert_model (map, "2 4 6 8 10");
|
||||
assert_changes (map, "");
|
||||
|
||||
@@ -318,7 +377,7 @@ test_remove_items (void)
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
map = new_model (store);
|
||||
map = new_model (G_LIST_MODEL (store));
|
||||
assert_model (map, "2 4 6 8 10");
|
||||
assert_changes (map, "");
|
||||
|
||||
@@ -334,7 +393,7 @@ test_splice (void)
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
map = new_model (store);
|
||||
map = new_model (G_LIST_MODEL (store));
|
||||
assert_model (map, "2 4 6 8 10");
|
||||
assert_changes (map, "");
|
||||
|
||||
@@ -343,6 +402,61 @@ test_splice (void)
|
||||
assert_changes (map, "2-2+2");
|
||||
}
|
||||
|
||||
static int
|
||||
by_n (gconstpointer p1,
|
||||
gconstpointer p2,
|
||||
gpointer data)
|
||||
{
|
||||
guint n1 = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (p1), number_quark));
|
||||
guint n2 = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (p2), number_quark));
|
||||
unsigned int n = GPOINTER_TO_UINT (data);
|
||||
|
||||
n1 = n1 / n;
|
||||
n2 = n2 / n;
|
||||
|
||||
if (n1 < n2)
|
||||
return -1;
|
||||
else if (n1 > n2)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare (gconstpointer first,
|
||||
gconstpointer second,
|
||||
gpointer unused)
|
||||
{
|
||||
return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (first), number_quark))
|
||||
- GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (second), number_quark));
|
||||
}
|
||||
|
||||
static void
|
||||
test_sections (void)
|
||||
{
|
||||
GtkMapListModel *map;
|
||||
GListStore *store;
|
||||
GtkSortListModel *sorted;
|
||||
GtkSorter *sorter;
|
||||
|
||||
store = new_store (1, 10, 1);
|
||||
sorted = gtk_sort_list_model_new (G_LIST_MODEL (store),
|
||||
GTK_SORTER (gtk_custom_sorter_new (compare, NULL, NULL)));
|
||||
map = new_model (G_LIST_MODEL (sorted));
|
||||
assert_model (map, "2 4 6 8 10 12 14 16 18 20");
|
||||
assert_section_model (map, "[2 4 6 8 10 12 14 16 18 20]");
|
||||
assert_changes (map, "");
|
||||
|
||||
sorter = GTK_SORTER (gtk_custom_sorter_new (by_n, GUINT_TO_POINTER (3), NULL));
|
||||
gtk_sort_list_model_set_section_sorter (sorted, sorter);
|
||||
g_object_unref (sorter);
|
||||
|
||||
assert_section_model (map, "[2 4] [6 8 10] [12 14 16] [18 20]");
|
||||
assert_changes (map, "s0:10");
|
||||
|
||||
g_object_unref (map);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -359,6 +473,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/maplistmodel/add_items", test_add_items);
|
||||
g_test_add_func ("/maplistmodel/remove_items", test_remove_items);
|
||||
g_test_add_func ("/maplistmodel/splice", test_splice);
|
||||
g_test_add_func ("/maplistmodel/sections", test_sections);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright © 2021 Chun-wei Fan.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Chun-wei Fan <fanc999@yahoo.com.tw>
|
||||
|
||||
"""
|
||||
This script generates a Windows manifest file and optionally a resource file to
|
||||
@@ -8,82 +14,99 @@ determine whether a specified program requires UAC elevation
|
||||
import os
|
||||
import argparse
|
||||
|
||||
DOMAIN_NAME='gnome'
|
||||
DOMAIN_NAME = "gnome"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__)
|
||||
parser.add_argument('-p', '--package', required=True,
|
||||
help='package name of the executable')
|
||||
parser.add_argument('-n', '--name', required=True,
|
||||
help='name of executable')
|
||||
parser.add_argument('--pkg-version', required=True, dest='version',
|
||||
help='version of package')
|
||||
parser.add_argument('--require-admin', action='store_true', dest='admin',
|
||||
default=False,
|
||||
help='require admin access to application')
|
||||
parser.add_argument('--input-resource-file', dest='resource',
|
||||
default=None,
|
||||
help='existing .rc file to embed UAC manifest (do not generate a new .rc file), must have included windows.h in it')
|
||||
parser.add_argument('--output-dir', dest='outdir',
|
||||
default=None,
|
||||
help='directory to output resulting files')
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"-p", "--package", required=True, help="package name of the executable"
|
||||
)
|
||||
parser.add_argument("-n", "--name", required=True, help="name of executable")
|
||||
parser.add_argument(
|
||||
"--pkg-version", required=True, dest="version", help="version of package"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--require-admin",
|
||||
action="store_true",
|
||||
dest="admin",
|
||||
default=False,
|
||||
help="require admin access to application",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--input-resource-file",
|
||||
dest="resource",
|
||||
default=None,
|
||||
help="existing .rc file to embed UAC manifest (do not generate a new .rc file), must have included windows.h in it",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
dest="outdir",
|
||||
default=None,
|
||||
help="directory to output resulting files",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.resource is not None:
|
||||
if not os.path.isfile(args.resource):
|
||||
raise FileNotFoundError("Specified resource file '%s' does not exist" % args.resource)
|
||||
raise FileNotFoundError(
|
||||
"Specified resource file '%s' does not exist" % args.resource
|
||||
)
|
||||
|
||||
generate_manifest(args.package, args.name, args.version, args.admin, args.outdir)
|
||||
write_rc_file(args.name, args.resource, args.outdir)
|
||||
|
||||
|
||||
def generate_manifest(package, name, version, admin, outdir):
|
||||
if version.count('.') == 0:
|
||||
manifest_package_version = version + '.0.0.0'
|
||||
elif version.count('.') == 1:
|
||||
manifest_package_version = version + '.0.0'
|
||||
elif version.count('.') == 2:
|
||||
manifest_package_version = version + '.0'
|
||||
elif version.count('.') == 3:
|
||||
if version.count(".") == 0:
|
||||
manifest_package_version = version + ".0.0.0"
|
||||
elif version.count(".") == 1:
|
||||
manifest_package_version = version + ".0.0"
|
||||
elif version.count(".") == 2:
|
||||
manifest_package_version = version + ".0"
|
||||
elif version.count(".") == 3:
|
||||
manifest_package_version = version
|
||||
else:
|
||||
parts = version.split('.')
|
||||
manifest_package_version = ''
|
||||
parts = version.split(".")
|
||||
manifest_package_version = ""
|
||||
for x in (0, 1, 2, 3):
|
||||
if x == 0:
|
||||
manifest_package_version += parts[x]
|
||||
else:
|
||||
manifest_package_version += '.' + parts[x]
|
||||
manifest_package_version += "." + parts[x]
|
||||
|
||||
if outdir is not None:
|
||||
output_file_base_name = os.path.join(outdir, name)
|
||||
else:
|
||||
output_file_base_name = name
|
||||
|
||||
outfile = open(output_file_base_name + '.exe.manifest', 'w+')
|
||||
outfile.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n')
|
||||
outfile.write('<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n')
|
||||
outfile.write(' <assemblyIdentity version="%s"\n' % manifest_package_version)
|
||||
outfile.write(' processorArchitecture="*"\n')
|
||||
outfile.write(' name="%s.%s.%s.exe"\n' % (DOMAIN_NAME, package, name))
|
||||
outfile.write(' type="win32" />\n')
|
||||
outfile.write(' <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\n')
|
||||
outfile.write(' <security>\n')
|
||||
outfile.write(' <requestedPrivileges>\n')
|
||||
outfile.write(' <requestedExecutionLevel\n')
|
||||
outfile = open(output_file_base_name + ".exe.manifest", "w+")
|
||||
outfile.write("<?xml version='1.0' encoding='UTF-8' standalone='yes'?>\n")
|
||||
outfile.write(
|
||||
"<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>\n"
|
||||
)
|
||||
outfile.write(" <assemblyIdentity version='%s'\n" % manifest_package_version)
|
||||
outfile.write(" processorArchitecture='*'\n")
|
||||
outfile.write(" name='%s.%s.%s.exe'\n" % (DOMAIN_NAME, package, name))
|
||||
outfile.write(" type='win32' />\n")
|
||||
outfile.write(" <trustInfo xmlns='urn:schemas-microsoft-com:asm.v3'>\n")
|
||||
outfile.write(" <security>\n")
|
||||
outfile.write(" <requestedPrivileges>\n")
|
||||
outfile.write(" <requestedExecutionLevel\n")
|
||||
|
||||
if admin:
|
||||
outfile.write(' level="requireAdministrator"\n')
|
||||
outfile.write(" level='requireAdministrator'\n")
|
||||
else:
|
||||
outfile.write(' level="asInvoker"\n')
|
||||
outfile.write(" level='asInvoker'\n")
|
||||
|
||||
outfile.write(' uiAccess="false" />\n')
|
||||
outfile.write(' </requestedPrivileges>\n')
|
||||
outfile.write(' </security>\n')
|
||||
outfile.write(' </trustInfo>\n')
|
||||
outfile.write('</assembly>\n')
|
||||
outfile.write(" uiAccess='false' />\n")
|
||||
outfile.write(" </requestedPrivileges>\n")
|
||||
outfile.write(" </security>\n")
|
||||
outfile.write(" </trustInfo>\n")
|
||||
outfile.write("</assembly>\n")
|
||||
outfile.close()
|
||||
|
||||
|
||||
def write_rc_file(name, resource, outdir):
|
||||
if outdir is not None:
|
||||
output_file_base_name = os.path.join(outdir, name)
|
||||
@@ -91,21 +114,24 @@ def write_rc_file(name, resource, outdir):
|
||||
output_file_base_name = name
|
||||
|
||||
if resource is None:
|
||||
outfile = open(output_file_base_name + '.rc', 'w+')
|
||||
outfile.write('#define WIN32_LEAN_AND_MEAN\n')
|
||||
outfile.write('#include <windows.h>\n')
|
||||
outfile = open(output_file_base_name + ".rc", "w+")
|
||||
outfile.write("#define WIN32_LEAN_AND_MEAN\n")
|
||||
outfile.write("#include <windows.h>\n")
|
||||
else:
|
||||
if resource != output_file_base_name + '.rc':
|
||||
outfile = open(output_file_base_name + '.rc', 'w+')
|
||||
if resource != output_file_base_name + ".rc":
|
||||
outfile = open(output_file_base_name + ".rc", "w+")
|
||||
else:
|
||||
outfile = open(output_file_base_name + '.final.rc', 'w+')
|
||||
srcfile = open(resource, 'r')
|
||||
outfile = open(output_file_base_name + ".final.rc", "w+")
|
||||
srcfile = open(resource, "r")
|
||||
outfile.write(srcfile.read())
|
||||
srcfile.close()
|
||||
|
||||
outfile.write('\n')
|
||||
outfile.write('CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "%s.exe.manifest"' % name)
|
||||
outfile.write("\n")
|
||||
outfile.write(
|
||||
'CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "%s.exe.manifest"' % name
|
||||
)
|
||||
outfile.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user