aioxlib 0.0.6__tar.gz → 0.0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aioxlib
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: Human friendly interface to XLib subsystems using asyncio python
5
5
  Author-email: Jose Tiago Macara Coutinho <coutinhotiago@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -4,7 +4,7 @@
4
4
  # Copyright (c) 2026 Tiago Coutinho
5
5
  # Distributed under the GPLv3 license. See LICENSE for more info.
6
6
 
7
- __version__ = "0.0.6"
7
+ __version__ = "0.0.7"
8
8
 
9
9
  import asyncio
10
10
  import enum
@@ -3771,6 +3771,992 @@ class Present(Extension):
3771
3771
  return await self.display.write_read(payload, unpack_present_query_capabilities)
3772
3772
 
3773
3773
 
3774
+ # ---------------------------------------------------------------------------
3775
+ # RENDER extension (X Rendering Extension)
3776
+ # ---------------------------------------------------------------------------
3777
+
3778
+
3779
+ class RenderCommand(enum.IntEnum):
3780
+ QueryVersion = 0
3781
+ QueryPictFormats = 1
3782
+ QueryPictIndexValues = 2
3783
+ QueryDithers = 3
3784
+ CreatePicture = 4
3785
+ ChangePicture = 5
3786
+ SetPictureClipRectangles = 6
3787
+ FreePicture = 7
3788
+ Composite = 8
3789
+ Scale = 9
3790
+ Trapezoids = 10
3791
+ Triangles = 11
3792
+ TriStrip = 12
3793
+ TriFan = 13
3794
+ ColorTrapezoids = 14
3795
+ ColorTriangles = 15
3796
+ CreateGlyphSet = 17
3797
+ ReferenceGlyphSet = 18
3798
+ FreeGlyphSet = 19
3799
+ AddGlyphs = 20
3800
+ AddGlyphsFromPicture = 21
3801
+ FreeGlyphs = 22
3802
+ CompositeGlyphs8 = 23
3803
+ CompositeGlyphs16 = 24
3804
+ CompositeGlyphs32 = 25
3805
+ FillRectangles = 26
3806
+ CreateCursor = 27
3807
+ SetPictureTransform = 28
3808
+ QueryFilters = 29
3809
+ SetPictureFilter = 30
3810
+ CreateAnimCursor = 31
3811
+ AddTraps = 32
3812
+ CreateSolidFill = 33
3813
+ CreateLinearGradient = 34
3814
+ CreateRadialGradient = 35
3815
+ CreateConicalGradient = 36
3816
+
3817
+
3818
+ class PictType(enum.IntEnum):
3819
+ Indexed = 0
3820
+ Direct = 1
3821
+
3822
+
3823
+ class PictOp(enum.IntEnum):
3824
+ """Porter-Duff / blend operators for Composite and FillRectangles."""
3825
+
3826
+ Clear = 0
3827
+ Src = 1
3828
+ Dst = 2
3829
+ Over = 3
3830
+ OverReverse = 4
3831
+ In = 5
3832
+ InReverse = 6
3833
+ Out = 7
3834
+ OutReverse = 8
3835
+ Atop = 9
3836
+ AtopReverse = 10
3837
+ Xor = 11
3838
+ Add = 12
3839
+ Saturate = 13
3840
+ # Disjoint (0.2+)
3841
+ DisjointClear = 0x10
3842
+ DisjointSrc = 0x11
3843
+ DisjointDst = 0x12
3844
+ DisjointOver = 0x13
3845
+ DisjointOverReverse = 0x14
3846
+ DisjointIn = 0x15
3847
+ DisjointInReverse = 0x16
3848
+ DisjointOut = 0x17
3849
+ DisjointOutReverse = 0x18
3850
+ DisjointAtop = 0x19
3851
+ DisjointAtopReverse = 0x1A
3852
+ DisjointXor = 0x1B
3853
+ # Conjoint (0.2+)
3854
+ ConjointClear = 0x20
3855
+ ConjointSrc = 0x21
3856
+ ConjointDst = 0x22
3857
+ ConjointOver = 0x23
3858
+ ConjointOverReverse = 0x24
3859
+ ConjointIn = 0x25
3860
+ ConjointInReverse = 0x26
3861
+ ConjointOut = 0x27
3862
+ ConjointOutReverse = 0x28
3863
+ ConjointAtop = 0x29
3864
+ ConjointAtopReverse = 0x2A
3865
+ ConjointXor = 0x2B
3866
+ # Blend (0.11+)
3867
+ Multiply = 0x30
3868
+ Screen = 0x31
3869
+ Overlay = 0x32
3870
+ Darken = 0x33
3871
+ Lighten = 0x34
3872
+ ColorDodge = 0x35
3873
+ ColorBurn = 0x36
3874
+ HardLight = 0x37
3875
+ SoftLight = 0x38
3876
+ Difference = 0x39
3877
+ Exclusion = 0x3A
3878
+ HSLHue = 0x3B
3879
+ HSLSaturation = 0x3C
3880
+ HSLColor = 0x3D
3881
+ HSLLuminosity = 0x3E
3882
+
3883
+
3884
+ class PictureAttributes(enum.IntFlag):
3885
+ Repeat = 1 << 0
3886
+ AlphaMap = 1 << 1
3887
+ AlphaXOrigin = 1 << 2
3888
+ AlphaYOrigin = 1 << 3
3889
+ ClipXOrigin = 1 << 4
3890
+ ClipYOrigin = 1 << 5
3891
+ ClipMask = 1 << 6
3892
+ GraphicsExposures = 1 << 7
3893
+ SubwindowMode = 1 << 8
3894
+ PolyEdge = 1 << 9
3895
+ PolyMode = 1 << 10
3896
+ Dither = 1 << 11
3897
+ ComponentAlpha = 1 << 12
3898
+
3899
+
3900
+ PICTURE_ATTR_ORDER = (
3901
+ ("repeat", PictureAttributes.Repeat),
3902
+ ("alpha_map", PictureAttributes.AlphaMap),
3903
+ ("alpha_x_origin", PictureAttributes.AlphaXOrigin),
3904
+ ("alpha_y_origin", PictureAttributes.AlphaYOrigin),
3905
+ ("clip_x_origin", PictureAttributes.ClipXOrigin),
3906
+ ("clip_y_origin", PictureAttributes.ClipYOrigin),
3907
+ ("clip_mask", PictureAttributes.ClipMask),
3908
+ ("graphics_exposures", PictureAttributes.GraphicsExposures),
3909
+ ("subwindow_mode", PictureAttributes.SubwindowMode),
3910
+ ("poly_edge", PictureAttributes.PolyEdge),
3911
+ ("poly_mode", PictureAttributes.PolyMode),
3912
+ ("dither", PictureAttributes.Dither),
3913
+ ("component_alpha", PictureAttributes.ComponentAlpha),
3914
+ )
3915
+
3916
+
3917
+ class PolyEdge(enum.IntEnum):
3918
+ Sharp = 0
3919
+ Smooth = 1
3920
+
3921
+
3922
+ class PolyMode(enum.IntEnum):
3923
+ Precise = 0
3924
+ Imprecise = 1
3925
+
3926
+
3927
+ class SubPixel(enum.IntEnum):
3928
+ Unknown = 0
3929
+ HorizontalRGB = 1
3930
+ HorizontalBGR = 2
3931
+ VerticalRGB = 3
3932
+ VerticalBGR = 4
3933
+ None_ = 5
3934
+
3935
+
3936
+ class Repeat(enum.IntEnum):
3937
+ None_ = 0
3938
+ Normal = 1
3939
+ Pad = 2
3940
+ Reflect = 3
3941
+
3942
+
3943
+ def fixed(value) -> int:
3944
+ """Convert a float (or int) to X Fixed (16.16 signed)."""
3945
+ if isinstance(value, int) and not isinstance(value, bool):
3946
+ # already fixed or integer pixels → treat bare ints as fixed when |v| is large?
3947
+ # Convention: ints are whole numbers in fixed form (value << 16) unless already Fixed.
3948
+ return int(value) << 16
3949
+ return int(round(float(value) * 65536.0))
3950
+
3951
+
3952
+ def fixed_to_float(v: int) -> float:
3953
+ return int(v) / 65536.0
3954
+
3955
+
3956
+ def pack_render_color(r, g, b, a=1.0):
3957
+ """Pack an xRenderColor from 0..1 floats or 0..0xffff ints."""
3958
+
3959
+ def _chan(c):
3960
+ if isinstance(c, float):
3961
+ return max(0, min(0xFFFF, int(round(c * 0xFFFF))))
3962
+ return max(0, min(0xFFFF, int(c)))
3963
+
3964
+ return struct.pack("HHHH", _chan(r), _chan(g), _chan(b), _chan(a))
3965
+
3966
+
3967
+ def _picture_values(**attrs):
3968
+ mask = PictureAttributes(0)
3969
+ values = []
3970
+ for name, bit in PICTURE_ATTR_ORDER:
3971
+ if (val := attrs.get(name)) is None:
3972
+ continue
3973
+ mask |= bit
3974
+ values.append(val)
3975
+ return mask, values
3976
+
3977
+
3978
+ def pack_render_query_version(opcode, major=0, minor=11):
3979
+ return struct.pack(
3980
+ "BBHII",
3981
+ opcode,
3982
+ RenderCommand.QueryVersion,
3983
+ 3,
3984
+ major,
3985
+ minor,
3986
+ )
3987
+
3988
+
3989
+ def unpack_render_query_version(data, offset=0):
3990
+ result, offset = unpack_reply_head(data, offset)
3991
+ major, minor = struct.unpack_from("II", data, offset)
3992
+ offset += 8 + 16
3993
+ result["major_version"] = major
3994
+ result["minor_version"] = minor
3995
+ return result, offset
3996
+
3997
+
3998
+ def pack_render_query_pict_formats(opcode):
3999
+ return struct.pack("BBH", opcode, RenderCommand.QueryPictFormats, 1)
4000
+
4001
+
4002
+ def unpack_render_query_pict_formats(data, offset=0):
4003
+ result, offset = unpack_reply_head(data, offset)
4004
+ (
4005
+ num_formats,
4006
+ num_screens,
4007
+ num_depths,
4008
+ num_visuals,
4009
+ num_subpixel,
4010
+ ) = struct.unpack_from("5I", data, offset)
4011
+ offset += 20 + 4 # 5I + pad
4012
+
4013
+ formats = []
4014
+ for _ in range(num_formats):
4015
+ (
4016
+ fid,
4017
+ ftype,
4018
+ depth,
4019
+ red,
4020
+ red_mask,
4021
+ green,
4022
+ green_mask,
4023
+ blue,
4024
+ blue_mask,
4025
+ alpha,
4026
+ alpha_mask,
4027
+ colormap,
4028
+ ) = struct.unpack_from("IBB2x8HI", data, offset)
4029
+ offset += 28
4030
+ formats.append(
4031
+ {
4032
+ "id": fid,
4033
+ "type": PictType(ftype),
4034
+ "depth": depth,
4035
+ "direct": {
4036
+ "red": red,
4037
+ "red_mask": red_mask,
4038
+ "green": green,
4039
+ "green_mask": green_mask,
4040
+ "blue": blue,
4041
+ "blue_mask": blue_mask,
4042
+ "alpha": alpha,
4043
+ "alpha_mask": alpha_mask,
4044
+ },
4045
+ "colormap": colormap,
4046
+ }
4047
+ )
4048
+
4049
+ # screens: each has nDepth + fallback, then depths follow contiguously
4050
+ screens = []
4051
+ depth_headers = []
4052
+ for _ in range(num_screens):
4053
+ n_depth, fallback = struct.unpack_from("II", data, offset)
4054
+ offset += 8
4055
+ screens.append({"fallback": fallback, "n_depth": n_depth, "depths": []})
4056
+ depth_headers.append(n_depth)
4057
+
4058
+ depths = []
4059
+ for _ in range(num_depths):
4060
+ depth, n_visuals = struct.unpack_from("BxH4x", data, offset)
4061
+ offset += 8
4062
+ depths.append({"depth": depth, "n_visuals": n_visuals, "visuals": []})
4063
+
4064
+ visuals = []
4065
+ for _ in range(num_visuals):
4066
+ visual, fmt = struct.unpack_from("II", data, offset)
4067
+ offset += 8
4068
+ visuals.append({"visual": visual, "format": fmt})
4069
+
4070
+ # attach visuals → depths → screens
4071
+ vi = 0
4072
+ for d in depths:
4073
+ d["visuals"] = visuals[vi : vi + d["n_visuals"]]
4074
+ vi += d["n_visuals"]
4075
+ di = 0
4076
+ for s, n in zip(screens, depth_headers):
4077
+ s["depths"] = depths[di : di + n]
4078
+ di += n
4079
+
4080
+ subpixels = []
4081
+ if num_subpixel:
4082
+ for _ in range(num_subpixel):
4083
+ (sp,) = struct.unpack_from("I", data, offset)
4084
+ offset += 4
4085
+ try:
4086
+ subpixels.append(SubPixel(sp))
4087
+ except ValueError:
4088
+ subpixels.append(sp)
4089
+ # pad to 32-bit boundary already
4090
+
4091
+ result["formats"] = formats
4092
+ result["screens"] = screens
4093
+ result["subpixels"] = subpixels
4094
+ return result, offset
4095
+
4096
+
4097
+ def pack_render_create_picture(opcode, pid, drawable, format, **attrs):
4098
+ mask, values = _picture_values(**attrs)
4099
+ length = 5 + len(values)
4100
+ header = struct.pack(
4101
+ "BBHIIII",
4102
+ opcode,
4103
+ RenderCommand.CreatePicture,
4104
+ length,
4105
+ pid,
4106
+ drawable,
4107
+ format,
4108
+ mask,
4109
+ )
4110
+ body = b"".join(struct.pack("I", v) for v in values)
4111
+ return header + body
4112
+
4113
+
4114
+ def pack_render_change_picture(opcode, picture, **attrs):
4115
+ mask, values = _picture_values(**attrs)
4116
+ length = 3 + len(values)
4117
+ header = struct.pack(
4118
+ "BBHII",
4119
+ opcode,
4120
+ RenderCommand.ChangePicture,
4121
+ length,
4122
+ picture,
4123
+ mask,
4124
+ )
4125
+ body = b"".join(struct.pack("I", v) for v in values)
4126
+ return header + body
4127
+
4128
+
4129
+ def pack_render_set_picture_clip_rectangles(opcode, picture, x_origin, y_origin, rects):
4130
+ """rects: sequence of (x, y, width, height)."""
4131
+ n = len(rects)
4132
+ length = 3 + n # each rect is 8 bytes = 2 CARD32 units
4133
+ header = struct.pack(
4134
+ "BBHIhh",
4135
+ opcode,
4136
+ RenderCommand.SetPictureClipRectangles,
4137
+ length,
4138
+ picture,
4139
+ x_origin,
4140
+ y_origin,
4141
+ )
4142
+ body = b"".join(struct.pack("hhHH", *r) for r in rects)
4143
+ return header + body
4144
+
4145
+
4146
+ def pack_render_free_picture(opcode, picture):
4147
+ return struct.pack(
4148
+ "BBHI", opcode, RenderCommand.FreePicture, 2, int(picture)
4149
+ )
4150
+
4151
+
4152
+ def pack_render_composite(
4153
+ opcode,
4154
+ op,
4155
+ src,
4156
+ mask,
4157
+ dst,
4158
+ src_x,
4159
+ src_y,
4160
+ mask_x,
4161
+ mask_y,
4162
+ dst_x,
4163
+ dst_y,
4164
+ width,
4165
+ height,
4166
+ ):
4167
+ return struct.pack(
4168
+ "BBHBBHIII6hHH",
4169
+ opcode,
4170
+ RenderCommand.Composite,
4171
+ 9,
4172
+ int(op),
4173
+ 0,
4174
+ 0,
4175
+ src,
4176
+ mask if mask is not None else 0,
4177
+ dst,
4178
+ src_x,
4179
+ src_y,
4180
+ mask_x,
4181
+ mask_y,
4182
+ dst_x,
4183
+ dst_y,
4184
+ width,
4185
+ height,
4186
+ )
4187
+
4188
+
4189
+ def pack_render_fill_rectangles(opcode, op, dst, color, rects):
4190
+ """color: (r,g,b,a) floats 0..1 or ints 0..0xffff; rects: (x,y,w,h)."""
4191
+ n = len(rects)
4192
+ length = 5 + n * 2 # color=8 bytes=2 units; each rect=8 bytes=2 units
4193
+ header = struct.pack(
4194
+ "BBHBBHI",
4195
+ opcode,
4196
+ RenderCommand.FillRectangles,
4197
+ length,
4198
+ op,
4199
+ 0,
4200
+ 0,
4201
+ dst,
4202
+ )
4203
+ body = pack_render_color(*color) + b"".join(
4204
+ struct.pack("hhHH", *r) for r in rects
4205
+ )
4206
+ return header + body
4207
+
4208
+
4209
+ def pack_render_set_picture_transform(opcode, picture, matrix):
4210
+ """matrix: 9 Fixed values (3×3 row-major) or floats."""
4211
+ vals = [fixed(v) for v in matrix]
4212
+ if len(vals) != 9:
4213
+ raise ValueError("transform matrix must have 9 elements")
4214
+ return struct.pack(
4215
+ "BBHI9i",
4216
+ opcode,
4217
+ RenderCommand.SetPictureTransform,
4218
+ 11,
4219
+ picture,
4220
+ *vals,
4221
+ )
4222
+
4223
+
4224
+ def pack_render_set_picture_filter(opcode, picture, name, values=()):
4225
+ name_b = name.encode("latin-1") if isinstance(name, str) else bytes(name)
4226
+ n = len(name_b)
4227
+ pad = (4 - (n % 4)) % 4
4228
+ nvals = len(values)
4229
+ length = 3 + (n + pad) // 4 + nvals
4230
+ header = struct.pack(
4231
+ "BBHIHH",
4232
+ opcode,
4233
+ RenderCommand.SetPictureFilter,
4234
+ length,
4235
+ picture,
4236
+ n,
4237
+ 0,
4238
+ )
4239
+ body = name_b + b"\0" * pad
4240
+ body += b"".join(struct.pack("i", fixed(v)) for v in values)
4241
+ return header + body
4242
+
4243
+
4244
+ def pack_render_query_filters(opcode, drawable):
4245
+ return struct.pack(
4246
+ "BBHI", opcode, RenderCommand.QueryFilters, 2, int(drawable)
4247
+ )
4248
+
4249
+
4250
+ def unpack_render_query_filters(data, offset=0):
4251
+ result, offset = unpack_reply_head(data, offset)
4252
+ num_aliases, num_filters = struct.unpack_from("II", data, offset)
4253
+ offset += 8 + 16
4254
+ aliases = list(struct.unpack_from(f"{num_aliases}H", data, offset))
4255
+ offset += num_aliases * 2
4256
+ if num_aliases % 2:
4257
+ offset += 2 # pad to 32-bit
4258
+ filters = []
4259
+ for _ in range(num_filters):
4260
+ (nbytes,) = struct.unpack_from("B", data, offset)
4261
+ offset += 1
4262
+ name = data[offset : offset + nbytes].decode("latin-1")
4263
+ offset += nbytes
4264
+ filters.append(name)
4265
+ # pad remainder of reply
4266
+ result["aliases"] = aliases
4267
+ result["filters"] = filters
4268
+ return result, offset
4269
+
4270
+
4271
+ def pack_render_create_solid_fill(opcode, pid, color):
4272
+ return struct.pack(
4273
+ "BBHI",
4274
+ opcode,
4275
+ RenderCommand.CreateSolidFill,
4276
+ 4,
4277
+ pid,
4278
+ ) + pack_render_color(*color)
4279
+
4280
+
4281
+ def pack_render_create_linear_gradient(opcode, pid, p1, p2, stops):
4282
+ """stops: sequence of (offset, (r,g,b,a)) with offset in 0..1."""
4283
+ n = len(stops)
4284
+ length = 7 + n + n * 2 # points + nStops + n Fixed + n RenderColor
4285
+ header = struct.pack(
4286
+ "BBHI4iI",
4287
+ opcode,
4288
+ RenderCommand.CreateLinearGradient,
4289
+ length,
4290
+ pid,
4291
+ fixed(p1[0]),
4292
+ fixed(p1[1]),
4293
+ fixed(p2[0]),
4294
+ fixed(p2[1]),
4295
+ n,
4296
+ )
4297
+ body = b"".join(struct.pack("i", fixed(s[0])) for s in stops)
4298
+ body += b"".join(pack_render_color(*s[1]) for s in stops)
4299
+ return header + body
4300
+
4301
+
4302
+ def pack_render_create_radial_gradient(
4303
+ opcode, pid, inner, outer, inner_radius, outer_radius, stops
4304
+ ):
4305
+ n = len(stops)
4306
+ length = 9 + n + n * 2
4307
+ header = struct.pack(
4308
+ "BBHI4i2iI",
4309
+ opcode,
4310
+ RenderCommand.CreateRadialGradient,
4311
+ length,
4312
+ pid,
4313
+ fixed(inner[0]),
4314
+ fixed(inner[1]),
4315
+ fixed(outer[0]),
4316
+ fixed(outer[1]),
4317
+ fixed(inner_radius),
4318
+ fixed(outer_radius),
4319
+ n,
4320
+ )
4321
+ body = b"".join(struct.pack("i", fixed(s[0])) for s in stops)
4322
+ body += b"".join(pack_render_color(*s[1]) for s in stops)
4323
+ return header + body
4324
+
4325
+
4326
+ def pack_render_create_conical_gradient(opcode, pid, center, angle, stops):
4327
+ n = len(stops)
4328
+ length = 6 + n + n * 2
4329
+ header = struct.pack(
4330
+ "BBHI2iiI",
4331
+ opcode,
4332
+ RenderCommand.CreateConicalGradient,
4333
+ length,
4334
+ pid,
4335
+ fixed(center[0]),
4336
+ fixed(center[1]),
4337
+ fixed(angle),
4338
+ n,
4339
+ )
4340
+ body = b"".join(struct.pack("i", fixed(s[0])) for s in stops)
4341
+ body += b"".join(pack_render_color(*s[1]) for s in stops)
4342
+ return header + body
4343
+
4344
+
4345
+ def pack_render_trapezoids(opcode, op, src, dst, mask_format, src_x, src_y, traps):
4346
+ """traps: sequence of (top, bottom, left_p1, left_p2, right_p1, right_p2)
4347
+ each point is (x, y); top/bottom are Fixed y values.
4348
+ """
4349
+ n = len(traps)
4350
+ length = 6 + n * 10 # each trapezoid = 40 bytes = 10 units
4351
+ header = struct.pack(
4352
+ "BBHBBHIIIhh",
4353
+ opcode,
4354
+ RenderCommand.Trapezoids,
4355
+ length,
4356
+ op,
4357
+ 0,
4358
+ 0,
4359
+ src,
4360
+ dst,
4361
+ mask_format if mask_format else 0,
4362
+ src_x,
4363
+ src_y,
4364
+ )
4365
+ body = b""
4366
+ for top, bottom, lp1, lp2, rp1, rp2 in traps:
4367
+ body += struct.pack(
4368
+ "10i",
4369
+ fixed(top),
4370
+ fixed(bottom),
4371
+ fixed(lp1[0]),
4372
+ fixed(lp1[1]),
4373
+ fixed(lp2[0]),
4374
+ fixed(lp2[1]),
4375
+ fixed(rp1[0]),
4376
+ fixed(rp1[1]),
4377
+ fixed(rp2[0]),
4378
+ fixed(rp2[1]),
4379
+ )
4380
+ return header + body
4381
+
4382
+
4383
+ def pack_render_triangles(opcode, op, src, dst, mask_format, src_x, src_y, tris):
4384
+ """tris: sequence of ((x1,y1),(x2,y2),(x3,y3))."""
4385
+ n = len(tris)
4386
+ length = 6 + n * 6
4387
+ header = struct.pack(
4388
+ "BBHBBHIIIhh",
4389
+ opcode,
4390
+ RenderCommand.Triangles,
4391
+ length,
4392
+ op,
4393
+ 0,
4394
+ 0,
4395
+ src,
4396
+ dst,
4397
+ mask_format if mask_format else 0,
4398
+ src_x,
4399
+ src_y,
4400
+ )
4401
+ body = b""
4402
+ for p1, p2, p3 in tris:
4403
+ body += struct.pack(
4404
+ "6i",
4405
+ fixed(p1[0]),
4406
+ fixed(p1[1]),
4407
+ fixed(p2[0]),
4408
+ fixed(p2[1]),
4409
+ fixed(p3[0]),
4410
+ fixed(p3[1]),
4411
+ )
4412
+ return header + body
4413
+
4414
+
4415
+ def pack_render_create_glyphset(opcode, gsid, format):
4416
+ return struct.pack(
4417
+ "BBHII",
4418
+ opcode,
4419
+ RenderCommand.CreateGlyphSet,
4420
+ 3,
4421
+ gsid,
4422
+ format,
4423
+ )
4424
+
4425
+
4426
+ def pack_render_free_glyphset(opcode, gsid):
4427
+ return struct.pack(
4428
+ "BBHI", opcode, RenderCommand.FreeGlyphSet, 2, gsid
4429
+ )
4430
+
4431
+
4432
+ def pack_render_add_glyphs(opcode, gsid, glyph_ids, glyph_infos, data):
4433
+ """glyph_ids: list of CARD32; glyph_infos: list of (width,height,x,y,xOff,yOff);
4434
+ data: concatenated glyph image bytes (padded per glyph to 32-bit).
4435
+ """
4436
+ n = len(glyph_ids)
4437
+ if n != len(glyph_infos):
4438
+ raise ValueError("glyph_ids and glyph_infos length mismatch")
4439
+ info_bytes = b"".join(
4440
+ struct.pack("HHhh hh", *info) for info in glyph_infos
4441
+ )
4442
+ # each GlyphInfo is 12 bytes
4443
+ info_bytes = b"".join(
4444
+ struct.pack("HHhhhh", w, h, x, y, xo, yo)
4445
+ for (w, h, x, y, xo, yo) in glyph_infos
4446
+ )
4447
+ ids_bytes = b"".join(struct.pack("I", int(g)) for g in glyph_ids)
4448
+ # pad image data to 32-bit
4449
+ pad = (4 - (len(data) % 4)) % 4
4450
+ payload = ids_bytes + info_bytes + data + b"\0" * pad
4451
+ length = 3 + len(payload) // 4
4452
+ header = struct.pack(
4453
+ "BBHII",
4454
+ opcode,
4455
+ RenderCommand.AddGlyphs,
4456
+ length,
4457
+ gsid,
4458
+ n,
4459
+ )
4460
+ return header + payload
4461
+
4462
+
4463
+ def pack_render_free_glyphs(opcode, gsid, glyph_ids):
4464
+ n = len(glyph_ids)
4465
+ length = 2 + n
4466
+ header = struct.pack(
4467
+ "BBHI", opcode, RenderCommand.FreeGlyphs, length, int(gsid)
4468
+ )
4469
+ body = b"".join(struct.pack("I", int(g)) for g in glyph_ids)
4470
+ return header + body
4471
+
4472
+
4473
+ def pack_render_composite_glyphs8(
4474
+ opcode, op, src, dst, mask_format, glyphset, src_x, src_y, elements
4475
+ ):
4476
+ """elements: sequence of (delta_x, delta_y, glyphs_bytes_or_str).
4477
+
4478
+ Each element becomes an xGlyphElt: 1-byte length + deltas + glyph 8-bit ids,
4479
+ padded to 4 bytes.
4480
+ """
4481
+ body = b""
4482
+ for dx, dy, glyphs in elements:
4483
+ if isinstance(glyphs, str):
4484
+ glyphs = glyphs.encode("latin-1")
4485
+ glyphs = bytes(glyphs)
4486
+ n = len(glyphs)
4487
+ if n > 252:
4488
+ raise ValueError("glyph elt too long (max 252)")
4489
+ elt = struct.pack("BBHhh", n, 0, 0, int(dx), int(dy)) + glyphs
4490
+ pad = (4 - (len(elt) % 4)) % 4
4491
+ body += elt + b"\0" * pad
4492
+ length = 7 + len(body) // 4
4493
+ header = struct.pack(
4494
+ "BBHBBHIIIIhh",
4495
+ opcode,
4496
+ RenderCommand.CompositeGlyphs8,
4497
+ length,
4498
+ op,
4499
+ 0,
4500
+ 0,
4501
+ src,
4502
+ dst,
4503
+ mask_format if mask_format else 0,
4504
+ glyphset,
4505
+ src_x,
4506
+ src_y,
4507
+ )
4508
+ return header + body
4509
+
4510
+
4511
+ class Render(Extension):
4512
+ """X Rendering Extension (RENDER).
4513
+
4514
+ Alpha compositing, transforms, gradients, and glyph rendering.
4515
+
4516
+ Query with::
4517
+
4518
+ render = await display.query_extension("RENDER")
4519
+ ver = await render.query_version()
4520
+ formats = await render.query_pict_formats()
4521
+ """
4522
+
4523
+ Commands = RenderCommand
4524
+
4525
+ BaseBadPictFormat = 0
4526
+ BaseBadPicture = 1
4527
+ BaseBadPictOp = 2
4528
+ BaseBadGlyphSet = 3
4529
+ BaseBadGlyph = 4
4530
+
4531
+ def __init__(self, display, info):
4532
+ super().__init__(display, info)
4533
+ base = info["base_error"]
4534
+ self.BadPictFormat = base + self.BaseBadPictFormat
4535
+ self.BadPicture = base + self.BaseBadPicture
4536
+ self.BadPictOp = base + self.BaseBadPictOp
4537
+ self.BadGlyphSet = base + self.BaseBadGlyphSet
4538
+ self.BadGlyph = base + self.BaseBadGlyph
4539
+ self.errors = {
4540
+ self.BadPictFormat: "BadPictFormat",
4541
+ self.BadPicture: "BadPicture",
4542
+ self.BadPictOp: "BadPictOp",
4543
+ self.BadGlyphSet: "BadGlyphSet",
4544
+ self.BadGlyph: "BadGlyph",
4545
+ }
4546
+ self.commands = {self.code: "Render"}
4547
+ self._formats = None
4548
+
4549
+ async def query_version(self, major=0, minor=11):
4550
+ payload = pack_render_query_version(self.code, major, minor)
4551
+ return await self.display.write_read(payload, unpack_render_query_version)
4552
+
4553
+ async def query_pict_formats(self):
4554
+ payload = pack_render_query_pict_formats(self.code)
4555
+ reply = await self.display.write_read(
4556
+ payload, unpack_render_query_pict_formats
4557
+ )
4558
+ self._formats = reply
4559
+ return reply
4560
+
4561
+ def find_standard_format(self, depth, alpha=True, formats=None):
4562
+ """Pick a direct PictFormat id matching *depth* (and optional alpha).
4563
+
4564
+ Common choices: depth=32 (ARGB), depth=24 (RGB), depth=8 (A).
4565
+ """
4566
+ formats = formats or (self._formats or {}).get("formats") or []
4567
+ best = None
4568
+ for f in formats:
4569
+ if f["type"] != PictType.Direct or f["depth"] != depth:
4570
+ continue
4571
+ d = f["direct"]
4572
+ has_alpha = d["alpha_mask"] != 0
4573
+ if alpha and not has_alpha:
4574
+ continue
4575
+ if not alpha and has_alpha and depth != 8:
4576
+ # prefer non-alpha when requested for 24-bit
4577
+ continue
4578
+ best = f["id"]
4579
+ if alpha == has_alpha:
4580
+ return best
4581
+ return best
4582
+
4583
+ async def create_picture(self, drawable, format, pid=None, **attrs):
4584
+ """Create a Picture for *drawable* using PictFormat *format*."""
4585
+ if pid is None:
4586
+ pid = self.display.resources.allocate()
4587
+ payload = pack_render_create_picture(
4588
+ self.code, pid, drawable, format, **attrs
4589
+ )
4590
+ self.display.write(payload)
4591
+ return pid
4592
+
4593
+ async def change_picture(self, picture, **attrs):
4594
+ payload = pack_render_change_picture(self.code, picture, **attrs)
4595
+ self.display.write(payload)
4596
+
4597
+ async def set_clip_rectangles(self, picture, x_origin, y_origin, rects):
4598
+ payload = pack_render_set_picture_clip_rectangles(
4599
+ self.code, picture, x_origin, y_origin, rects
4600
+ )
4601
+ self.display.write(payload)
4602
+
4603
+ async def free_picture(self, picture):
4604
+ self.display.write(pack_render_free_picture(self.code, picture))
4605
+
4606
+ async def composite(
4607
+ self,
4608
+ op,
4609
+ src,
4610
+ dst,
4611
+ dst_x,
4612
+ dst_y,
4613
+ width,
4614
+ height,
4615
+ src_x=0,
4616
+ src_y=0,
4617
+ mask=None,
4618
+ mask_x=0,
4619
+ mask_y=0,
4620
+ ):
4621
+ payload = pack_render_composite(
4622
+ self.code,
4623
+ op,
4624
+ src,
4625
+ mask,
4626
+ dst,
4627
+ src_x,
4628
+ src_y,
4629
+ mask_x,
4630
+ mask_y,
4631
+ dst_x,
4632
+ dst_y,
4633
+ width,
4634
+ height,
4635
+ )
4636
+ self.display.write(payload)
4637
+
4638
+ async def fill_rectangles(self, op, dst, color, rects):
4639
+ """Fill *rects* on *dst* with solid *color* using operator *op*.
4640
+
4641
+ *color* is ``(r, g, b, a)`` with channels in 0..1 (float) or 0..65535.
4642
+ *rects* is a sequence of ``(x, y, width, height)``.
4643
+ """
4644
+ payload = pack_render_fill_rectangles(self.code, op, dst, color, rects)
4645
+ self.display.write(payload)
4646
+
4647
+ async def set_transform(self, picture, matrix):
4648
+ """Set a 3×3 projective transform (9 floats or Fixed)."""
4649
+ payload = pack_render_set_picture_transform(self.code, picture, matrix)
4650
+ self.display.write(payload)
4651
+
4652
+ async def set_filter(self, picture, name, values=()):
4653
+ """Set filter name (e.g. ``\"bilinear\"``, ``\"nearest\"``) and params."""
4654
+ payload = pack_render_set_picture_filter(
4655
+ self.code, picture, name, values
4656
+ )
4657
+ self.display.write(payload)
4658
+
4659
+ async def query_filters(self, drawable):
4660
+ payload = pack_render_query_filters(self.code, drawable)
4661
+ return await self.display.write_read(payload, unpack_render_query_filters)
4662
+
4663
+ async def create_solid_fill(self, color, pid=None):
4664
+ if pid is None:
4665
+ pid = self.display.resources.allocate()
4666
+ payload = pack_render_create_solid_fill(self.code, pid, color)
4667
+ self.display.write(payload)
4668
+ return pid
4669
+
4670
+ async def create_linear_gradient(self, p1, p2, stops, pid=None):
4671
+ if pid is None:
4672
+ pid = self.display.resources.allocate()
4673
+ payload = pack_render_create_linear_gradient(
4674
+ self.code, pid, p1, p2, stops
4675
+ )
4676
+ self.display.write(payload)
4677
+ return pid
4678
+
4679
+ async def create_radial_gradient(
4680
+ self, inner, outer, inner_radius, outer_radius, stops, pid=None
4681
+ ):
4682
+ if pid is None:
4683
+ pid = self.display.resources.allocate()
4684
+ payload = pack_render_create_radial_gradient(
4685
+ self.code, pid, inner, outer, inner_radius, outer_radius, stops
4686
+ )
4687
+ self.display.write(payload)
4688
+ return pid
4689
+
4690
+ async def create_conical_gradient(self, center, angle, stops, pid=None):
4691
+ if pid is None:
4692
+ pid = self.display.resources.allocate()
4693
+ payload = pack_render_create_conical_gradient(
4694
+ self.code, pid, center, angle, stops
4695
+ )
4696
+ self.display.write(payload)
4697
+ return pid
4698
+
4699
+ async def trapezoids(
4700
+ self, op, src, dst, src_x, src_y, traps, mask_format=0
4701
+ ):
4702
+ payload = pack_render_trapezoids(
4703
+ self.code, op, src, dst, mask_format, src_x, src_y, traps
4704
+ )
4705
+ self.display.write(payload)
4706
+
4707
+ async def triangles(
4708
+ self, op, src, dst, src_x, src_y, tris, mask_format=0
4709
+ ):
4710
+ payload = pack_render_triangles(
4711
+ self.code, op, src, dst, mask_format, src_x, src_y, tris
4712
+ )
4713
+ self.display.write(payload)
4714
+
4715
+ async def create_glyphset(self, format, gsid=None):
4716
+ if gsid is None:
4717
+ gsid = self.display.resources.allocate()
4718
+ payload = pack_render_create_glyphset(self.code, gsid, format)
4719
+ self.display.write(payload)
4720
+ return gsid
4721
+
4722
+ async def free_glyphset(self, gsid):
4723
+ self.display.write(pack_render_free_glyphset(self.code, gsid))
4724
+
4725
+ async def add_glyphs(self, gsid, glyph_ids, glyph_infos, data):
4726
+ payload = pack_render_add_glyphs(
4727
+ self.code, gsid, glyph_ids, glyph_infos, data
4728
+ )
4729
+ self.display.write(payload)
4730
+
4731
+ async def free_glyphs(self, gsid, glyph_ids):
4732
+ payload = pack_render_free_glyphs(self.code, gsid, glyph_ids)
4733
+ self.display.write(payload)
4734
+
4735
+ async def composite_glyphs8(
4736
+ self,
4737
+ op,
4738
+ src,
4739
+ dst,
4740
+ glyphset,
4741
+ src_x,
4742
+ src_y,
4743
+ elements,
4744
+ mask_format=0,
4745
+ ):
4746
+ payload = pack_render_composite_glyphs8(
4747
+ self.code,
4748
+ op,
4749
+ src,
4750
+ dst,
4751
+ mask_format,
4752
+ glyphset,
4753
+ src_x,
4754
+ src_y,
4755
+ elements,
4756
+ )
4757
+ self.display.write(payload)
4758
+
4759
+
3774
4760
  EXTENSIONS = {
3775
4761
  "MIT-SHM": SharedMemory,
3776
4762
  "DOUBLE-BUFFER": DoubleBuffer,
@@ -3778,6 +4764,7 @@ EXTENSIONS = {
3778
4764
  "GLX": GLX,
3779
4765
  "DRI3": DRI3,
3780
4766
  "Present": Present,
4767
+ "RENDER": Render,
3781
4768
  }
3782
4769
 
3783
4770
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aioxlib
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Summary: Human friendly interface to XLib subsystems using asyncio python
5
5
  Author-email: Jose Tiago Macara Coutinho <coutinhotiago@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
File without changes
File without changes
File without changes
File without changes