1 | /* gtkatspicomponent.c: AT-SPI Component implementation |
2 | * |
3 | * Copyright 2020 Red Hat, Inc. |
4 | * |
5 | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #include "gtkatspicomponentprivate.h" |
24 | |
25 | #include "gtkatspicontextprivate.h" |
26 | #include "gtkatspiprivate.h" |
27 | #include "gtkatspiutilsprivate.h" |
28 | #include "gtkaccessibleprivate.h" |
29 | #include "gtkpopover.h" |
30 | #include "gtkwidget.h" |
31 | #include "gtkwindow.h" |
32 | |
33 | #include "a11y/atspi/atspi-component.h" |
34 | |
35 | #include "gtkdebug.h" |
36 | |
37 | #include <gio/gio.h> |
38 | |
39 | static void |
40 | translate_coordinates_to_widget (GtkWidget *widget, |
41 | AtspiCoordType coordtype, |
42 | int xi, |
43 | int yi, |
44 | int *xo, |
45 | int *yo) |
46 | { |
47 | double x = xi; |
48 | double y = yi; |
49 | |
50 | switch (coordtype) |
51 | { |
52 | case ATSPI_COORD_TYPE_SCREEN: |
53 | g_warning ("Screen coordinates not supported, reported positions will be wrong" ); |
54 | G_GNUC_FALLTHROUGH; |
55 | |
56 | case ATSPI_COORD_TYPE_WINDOW: |
57 | gtk_widget_translate_coordinates (GTK_WIDGET (gtk_widget_get_root (widget)), |
58 | dest_widget: widget, |
59 | src_x: x, src_y: y, |
60 | dest_x: &x, dest_y: &y); |
61 | break; |
62 | |
63 | case ATSPI_COORD_TYPE_PARENT: |
64 | gtk_widget_translate_coordinates (src_widget: gtk_widget_get_parent (widget), |
65 | dest_widget: widget, |
66 | src_x: x, src_y: y, |
67 | dest_x: &x, dest_y: &y); |
68 | break; |
69 | |
70 | default: |
71 | g_assert_not_reached (); |
72 | } |
73 | |
74 | *xo = (int)x; |
75 | *yo = (int)y; |
76 | } |
77 | |
78 | static void |
79 | translate_coordinates_from_widget (GtkWidget *widget, |
80 | AtspiCoordType coordtype, |
81 | int xi, |
82 | int yi, |
83 | int *xo, |
84 | int *yo) |
85 | { |
86 | double x = xi; |
87 | double y = yi; |
88 | |
89 | switch (coordtype) |
90 | { |
91 | case ATSPI_COORD_TYPE_SCREEN: |
92 | g_warning ("Screen coordinates not supported, reported positions will be wrong" ); |
93 | G_GNUC_FALLTHROUGH; |
94 | |
95 | case ATSPI_COORD_TYPE_WINDOW: |
96 | gtk_widget_translate_coordinates (src_widget: widget, |
97 | GTK_WIDGET (gtk_widget_get_root (widget)), |
98 | src_x: x, src_y: y, |
99 | dest_x: &x, dest_y: &y); |
100 | break; |
101 | |
102 | case ATSPI_COORD_TYPE_PARENT: |
103 | gtk_widget_translate_coordinates (src_widget: widget, |
104 | dest_widget: gtk_widget_get_parent (widget), |
105 | src_x: x, src_y: y, |
106 | dest_x: &x, dest_y: &y); |
107 | break; |
108 | |
109 | default: |
110 | g_assert_not_reached (); |
111 | } |
112 | |
113 | *xo = (int)x; |
114 | *yo = (int)y; |
115 | } |
116 | |
117 | static void |
118 | component_handle_method (GDBusConnection *connection, |
119 | const gchar *sender, |
120 | const gchar *object_path, |
121 | const gchar *interface_name, |
122 | const gchar *method_name, |
123 | GVariant *parameters, |
124 | GDBusMethodInvocation *invocation, |
125 | gpointer user_data) |
126 | { |
127 | GtkATContext *self = user_data; |
128 | GtkAccessible *accessible = gtk_at_context_get_accessible (self); |
129 | GtkWidget *widget = GTK_WIDGET (accessible); |
130 | |
131 | if (g_strcmp0 (str1: method_name, str2: "Contains" ) == 0) |
132 | { |
133 | int x, y; |
134 | AtspiCoordType coordtype; |
135 | gboolean ret; |
136 | |
137 | g_variant_get (value: parameters, format_string: "(iiu)" , &x, &y, &coordtype); |
138 | |
139 | translate_coordinates_to_widget (widget, coordtype, xi: x, yi: y, xo: &x, yo: &y); |
140 | |
141 | ret = gtk_widget_contains (widget, x, y); |
142 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(b)" , ret)); |
143 | } |
144 | else if (g_strcmp0 (str1: method_name, str2: "GetAccessibleAtPoint" ) == 0) |
145 | { |
146 | int x, y; |
147 | AtspiCoordType coordtype; |
148 | GtkWidget *child; |
149 | |
150 | g_variant_get (value: parameters, format_string: "(iiu)" , &x, &y, &coordtype); |
151 | |
152 | translate_coordinates_to_widget (widget, coordtype, xi: x, yi: y, xo: &x, yo: &y); |
153 | |
154 | child = gtk_widget_pick (widget, x, y, flags: GTK_PICK_DEFAULT); |
155 | if (!child) |
156 | { |
157 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(@(so))" , gtk_at_spi_null_ref ())); |
158 | } |
159 | else |
160 | { |
161 | GtkAtSpiContext *ctx = GTK_AT_SPI_CONTEXT (ptr: gtk_accessible_get_at_context (self: GTK_ACCESSIBLE (ptr: child))); |
162 | |
163 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(@(so))" , gtk_at_spi_context_to_ref (self: ctx))); |
164 | } |
165 | } |
166 | else if (g_strcmp0 (str1: method_name, str2: "GetExtents" ) == 0) |
167 | { |
168 | AtspiCoordType coordtype; |
169 | int x, y; |
170 | int width = gtk_widget_get_width (widget); |
171 | int height = gtk_widget_get_height (widget); |
172 | |
173 | g_variant_get (value: parameters, format_string: "(u)" , &coordtype); |
174 | |
175 | translate_coordinates_from_widget (widget, coordtype, xi: 0, yi: 0, xo: &x, yo: &y); |
176 | |
177 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "((iiii))" , x, y, width, height)); |
178 | } |
179 | else if (g_strcmp0 (str1: method_name, str2: "GetPosition" ) == 0) |
180 | { |
181 | AtspiCoordType coordtype; |
182 | int x, y; |
183 | |
184 | g_variant_get (value: parameters, format_string: "(u)" , &coordtype); |
185 | |
186 | translate_coordinates_from_widget (widget, coordtype, xi: 0, yi: 0, xo: &x, yo: &y); |
187 | |
188 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(ii)" , x, y)); |
189 | } |
190 | else if (g_strcmp0 (str1: method_name, str2: "GetSize" ) == 0) |
191 | { |
192 | int width = gtk_widget_get_width (widget); |
193 | int height = gtk_widget_get_height (widget); |
194 | |
195 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(ii)" , width, height)); |
196 | } |
197 | else if (g_strcmp0 (str1: method_name, str2: "GetLayer" ) == 0) |
198 | { |
199 | AtspiComponentLayer layer; |
200 | |
201 | if (GTK_IS_WINDOW (widget)) |
202 | layer = ATSPI_COMPONENT_LAYER_WINDOW; |
203 | else if (GTK_IS_POPOVER (widget)) |
204 | layer = ATSPI_COMPONENT_LAYER_POPUP; |
205 | else |
206 | layer = ATSPI_COMPONENT_LAYER_WIDGET; |
207 | |
208 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(u)" , layer)); |
209 | } |
210 | else if (g_strcmp0 (str1: method_name, str2: "GetMDIZOrder" ) == 0) |
211 | { |
212 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(n)" , 0)); |
213 | } |
214 | else if (g_strcmp0 (str1: method_name, str2: "GrabFocus" ) == 0) |
215 | { |
216 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
217 | } |
218 | else if (g_strcmp0 (str1: method_name, str2: "GetAlpha" ) == 0) |
219 | { |
220 | double opacity = gtk_widget_get_opacity (widget); |
221 | |
222 | g_dbus_method_invocation_return_value (invocation, parameters: g_variant_new (format_string: "(d)" , opacity)); |
223 | } |
224 | else if (g_strcmp0 (str1: method_name, str2: "SetExtents" ) == 0) |
225 | { |
226 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
227 | } |
228 | else if (g_strcmp0 (str1: method_name, str2: "SetPosition" ) == 0) |
229 | { |
230 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
231 | } |
232 | else if (g_strcmp0 (str1: method_name, str2: "SetSize" ) == 0) |
233 | { |
234 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
235 | } |
236 | else if (g_strcmp0 (str1: method_name, str2: "ScrollTo" ) == 0) |
237 | { |
238 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
239 | } |
240 | else if (g_strcmp0 (str1: method_name, str2: "ScrollToPoint" ) == 0) |
241 | { |
242 | g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, code: G_DBUS_ERROR_NOT_SUPPORTED, message: "" ); |
243 | } |
244 | } |
245 | |
246 | static const GDBusInterfaceVTable component_vtable = { |
247 | component_handle_method, |
248 | }; |
249 | |
250 | const GDBusInterfaceVTable * |
251 | gtk_atspi_get_component_vtable (GtkAccessible *accessible) |
252 | { |
253 | if (GTK_IS_WIDGET (accessible)) |
254 | return &component_vtable; |
255 | |
256 | return NULL; |
257 | } |
258 | |