Compare commits

...

41 Commits

Author SHA1 Message Date
Nelson Benítez León
bab2bf2596 widget-factory: add example on styling tooltip window
by using new api:
  gtk_tooltip_set_css_class()
  GtkWidget signals 'tooltip-show' and 'tooltip-hide'

Part of #5925
2023-07-09 17:07:09 -04:00
Nelson Benítez León
11b4e4a467 GtkWidget: add new signals 'tooltip-show' and 'tooltip-hide'
which are emitted when a tooltip window is about to be shown
on a widget, and when a tooltip window stopped being shown
on a widget.

These signals provide two convenient moments for where to style
our tooltip window in case we want to do so by adding a css
class to it.

The existant signal 'query-tooltip' could not be used for that
as it's triggered on motion events and we cannot distinguish
from that when the tooltip window gets shown or hidden.

Part of issue #5925
2023-07-09 17:07:09 -04:00
Nelson Benítez León
1cae0cd54c GtkToolTip: new API to add css classes to GtkTooltipWindow
we add a simple API to allow styling GtkTooltip's window
by setting a css class on it:

void gtk_tooltip_set_css_class (GtkTooltip *tooltip,
                                const char *css_class);

By passing NULL it will remove any previously set css class
by this function.

Issue #5925
2023-07-09 17:07:09 -04:00
Matthias Clasen
1f3db35271 Merge branch 'dboles/image-notify-storage-type' into 'main'
Image—Notify when :storage-type changes from EMPTY

See merge request GNOME/gtk!6170
2023-07-07 01:15:56 +00:00
Emmanuele Bassi
18cce46ed2 Merge branch 'wip/corey/listitemleak' into 'main'
gtklistitemmanager: Stop leaking item

Closes #5940

See merge request GNOME/gtk!6171
2023-07-06 23:57:16 +00:00
Corey Berla
e78148bae5 gtklistitemmanager: Stop leaking item
Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5940
2023-07-06 16:24:29 -07:00
Daniel Boles
41237509ad Image—Notify when :storage-type changes from EMPTY
PROP_STORAGE_TYPE was only notified if it was changing *to* EMPTY, in
gtk_image_clear_internal(). We did not notify when it changes *from*
EMPTY to something non-empty. We should as not doing so is confusing,
e.g. if a user wants to bind :storage-type to :visible if non-empty,
which I just did! So, in functions that apply an ImageType, now notify.

Also do so in gtk_image_set_from_definition, declared in imageprivate.h,
even though none of the function there are currently used anywhere.
(Should they be removed?)
2023-07-06 23:08:20 +01:00
Yosef Or Boczko
576e8a2090 Update Hebrew translation 2023-07-06 09:38:02 +00:00
Matthias Clasen
d0f77c1db4 Merge branch 'wip/carlosg/switch-stylus-buttons' into 'main'
gdk/wayland: Switch behavior of BTN_STYLUS/STYLUS2 as middle/right click

Closes #5935

See merge request GNOME/gtk!6168
2023-07-05 23:38:38 +00:00
Carlos Garnacho
e28ff79bec gdk/wayland: Switch behavior of BTN_STYLUS/STYLUS2 as middle/right click
This mapping of stylus evdev input event codes into GDK button numbers
makes gdk/wayland inconsistent with gdk/x11, so depending on the backend
the same button middle-click pastes or right-click pops up menus.

Make the wayland backend consistent with X11, so that a GNOME wayland
session gets these buttons consistently mapped across all kinds of
clients.

Closes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5935
2023-07-05 16:54:54 +02:00
Daniel Boles
dccf6b55bd GdkTexture: Don't mention private new_from_surface
The stuff about Cairo Surfaces is in gdktextureprivate.h, & so end users
will not be able to use them; we shouldn't confuse by implying they can.
2023-07-05 12:07:33 +01:00
Daniel Boles
d5ea376e7b docs/list-widget: links, DirList, correct Sections
* Add links to various symbols.
* Mention DirectoryList in the "ready-made choices available" section.
* Don't say that GridView can display headers: it makes no attempt to.
2023-07-05 12:02:08 +01:00
Matthias Clasen
40707a6af0 Merge branch 'ebassi/issue-5934' into 'main'
Lower the Python requirement

Closes #5934

See merge request GNOME/gtk!6167
2023-07-05 10:57:45 +00:00
Emmanuele Bassi
9b71c9dfc6 Do not use bleeding edge Python
The match operator was added in Python 3.10, which is a bit too new for
some downstreams.

While at it, let's fix the flake8 errors and warnings.

Fixes: #5934
2023-07-05 10:19:18 +01:00
Emmanuele Bassi
64308317f8 Add flake8 configuration file
Ignore long lines; most of our Python scripts generate code or other
types of files, which makes long lines a necessity.

We should validate all our Python script in our CI as well.
2023-07-05 10:12:20 +01:00
Daniel Boles
f920723eae AlertDialog: Remove spurious/unmatched backtick 2023-07-04 22:42:50 +01:00
Daniel Boles
c581f4c96f ListBase: Fix a typo 2023-07-04 19:44:56 +01:00
Matthias Clasen
4998c90b10 Merge branch 'update-uac-script-format' into 'main'
tools/generate-uac-manifest.py: Fix formatting (unify with copy in GLib)

See merge request GNOME/gtk!6164
2023-07-03 23:37:36 +00:00
Benjamin Otte
412b23a146 Merge branch 'wip/otte/for-main' into 'main'
gsk: Catch values < 0 before bad things happen

See merge request GNOME/gtk!6165
2023-07-03 20:40:30 +00:00
Benjamin Otte
c179013790 testsuite: Add a test for mask out of bounds effects
Inverted alpha masks have an effect on the source, even if the mask
doesn't cover the source at all - or worse, is completely clipped out.

The GL renderer handles this fine, but Cairo and Vulkan had
optimizations that got this wrong.
2023-07-03 22:02:44 +02:00
Benjamin Otte
c6eb7fd483 gsk: Fix luminance in Cairo and GL renderer
In particular, fix the combination of luminance and alpha. We want to do
  mask = luminance * alpha
and for inverted
  mask = (1.0 - luminance) * alpha
so add a test that makes sure we do that and then fix the code and
existing tests to conform to it.
2023-07-03 22:02:44 +02:00
Benjamin Otte
7c58370673 rendernode: Work around a Cairo bug
When color-matrix modifying a clear surface, the surface would remain
clear according to Cairo.

That's very unfortunate when we prepare a mask for inverted-alpha
masking.
2023-07-03 22:02:44 +02:00
Benjamin Otte
84737a5159 build: Include the right things
If we build our own targets, we need to include those.

This is only relevant when adding new shaders because meson will
complain that the (unused) sources don't exist as it tries to include
those.
And that will make the build.ninja file not be generated which would
have build those shaders and would have allowed to copy them into the
sources.

Note that this makes builds with glslc not care about all the shader
files being included with the sources, but we have CI to check that.
2023-07-03 22:02:44 +02:00
Benjamin Otte
48804c81f3 rendernode: Mask nodes with different modes are different
So treat them as such.

Fixes the node editor not updating when I edit the mask mode.
2023-07-03 22:02:44 +02:00
Benjamin Otte
c79ec355af gsk: Catch values < 0 before bad things happen
In particular, catch radius values being < 0 by return_if_fail()ing in
the rendernode creation code, and by erroring out in the rendernode
parser.

I try too much dumb stuff in the node editor.
2023-07-03 22:02:44 +02:00
Benjamin Otte
ce5d74d7df glcontext: Fix typo in Apple extension name 2023-07-03 22:02:44 +02:00
Matthias Clasen
5bcc943ec3 Post-release version bump 2023-07-03 14:56:49 -04:00
Matthias Clasen
f5d68bb586 4.11.4 2023-07-03 14:12:53 -04:00
Chun-wei Fan
6d1537647c tools/generate-uac-manifest.py: Fix formatting
As this script is now also used in GLib, unify the formatting between
GLib and GTK. Make the formatting of the script conformant to the
Black[1] tool, as GLib requires, and add a copyright header to this
script.

[1]: https://black.readthedocs.io/en/stable/, see also
$(glibsrcroot)/.gitlab-ci/run-bash.sh
2023-07-03 12:50:55 +08:00
Matthias Clasen
ae2c10996a Merge branch 'fix_atcontext_refleaks' into 'main'
a11y: Fix some GtkATContext reference leaks

See merge request GNOME/gtk!6160
2023-07-01 18:06:19 +00:00
Barnabás Pőcze
81e9de3778 a11y: Fix some GtkATContext reference leaks
`gtk_accessible_get_at_context()` is transfer-full, so the returned
reference needs to be dropped. This was missing in a couple places.
2023-07-01 16:40:11 +02:00
Chun-wei Fan
42a704fefb Merge branch 'gdk-win32-input-fixes' into 'main'
GdkWin32 input fixes

Closes #5877

See merge request GNOME/gtk!6131
2023-06-30 04:33:08 +00:00
Matthias Clasen
e57eaf16b4 Merge branch 'wip/chergert/map-as-sectionmodel' into 'main'
maplistmodel: implement GtkSectionModel

See merge request GNOME/gtk!6154
2023-06-30 01:50:07 +00:00
Matthias Clasen
9aabb0e98d Add section model tests for GtkMapListModel 2023-06-29 21:30:11 -04:00
Matthias Clasen
9590a5f45e maplistmodel: Handle the ::sections-changed signal
Wrapper section models need to listen to and pass
on the ::sections-changed signal from the underlying
model.
2023-06-29 21:29:11 -04:00
Christian Hergert
32a3690a3c maplistmodel: implement GtkSectionModel
This just wraps the underlying GListModel if it is a GtkSectionModel.
2023-06-27 18:08:20 -07:00
Luca Bacci
43af0ee514 Define this_module with (void) argument
Fixes a compiler warning about K&R (old-style) function definition
2023-06-21 16:18:40 +02:00
Luca Bacci
3912d6aba9 GdkWin32: Fix keyboard state for WinPointer input
The dwKeyStates field of the POINTER_INFO structure
is always set to 0, no matter what. Use GetKeyState
instead.

Forward-port of !4327 to GTK4
2023-06-21 16:18:01 +02:00
Luca Bacci
871685e271 GdkWin32: Use double coordinates for mouse events
Mouse coordinates reported by the system are still integers,
but go sub-pixel when dividing by the window scale factor.
2023-06-21 16:07:55 +02:00
Luca Bacci
5e9daa9728 GdkWin32: Unscaled coordinates in current_root_x, current_root_y
Also modify gdk_win32_surface_do_move_resize_drag() to take
unscaled root coordinates.

Fixes #5877
2023-06-21 16:01:42 +02:00
Luca Bacci
412bc1713a GdkWin32: Keep track of the last cursor position in move / resize contexts
...and avoid doing any work if the position hasn't changed.
2023-06-21 15:31:48 +02:00
43 changed files with 1544 additions and 960 deletions

2
.flake8 Normal file
View File

@@ -0,0 +1,2 @@
[flake8]
ignore = E501

9
NEWS
View File

@@ -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

View File

@@ -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))

View File

@@ -6,3 +6,12 @@
.toolbar {
-gtk-icon-style: symbolic;
}
.red-tooltip {
background-color: red;
}
.yellow-tooltip {
background-color: yellow;
color: black;
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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
{

View File

@@ -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].

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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_*).
*/

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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, &center },
{ "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;

View File

@@ -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("};")

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
{

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -36,7 +36,7 @@
extern IMAGE_DOS_HEADER __ImageBase;
static inline HMODULE
this_module ()
this_module (void)
{
return (HMODULE) &__ImageBase;
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -1,5 +1,5 @@
project('gtk', 'c',
version: '4.11.4',
version: '4.11.5',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',

1498
po/he.po

File diff suppressed because it is too large Load Diff

View File

@@ -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));
}

View 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;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

View 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);
}
}

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

View File

@@ -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',

View File

@@ -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 ();
}

View File

@@ -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()