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
39static void
40translate_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
78static void
79translate_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
117static void
118component_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
246static const GDBusInterfaceVTable component_vtable = {
247 component_handle_method,
248};
249
250const GDBusInterfaceVTable *
251gtk_atspi_get_component_vtable (GtkAccessible *accessible)
252{
253 if (GTK_IS_WIDGET (accessible))
254 return &component_vtable;
255
256 return NULL;
257}
258

source code of gtk/gtk/a11y/gtkatspicomponent.c