1
/* ATK -  Accessibility Toolkit
2
 * Copyright 2001 Sun Microsystems Inc.
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, write to the
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
 * Boston, MA 02111-1307, USA.
18
 */
19

            
20
#include "config.h"
21

            
22
#include "atkcomponent.h"
23

            
24
/**
25
 * AtkComponent:
26
 *
27
 * The ATK interface provided by UI components
28
 * which occupy a physical area on the screen.
29
 * which the user can activate/interact with.
30
 *
31
 * #AtkComponent should be implemented by most if not all UI elements
32
 * with an actual on-screen presence, i.e. components which can be
33
 * said to have a screen-coordinate bounding box.  Virtually all
34
 * widgets will need to have #AtkComponent implementations provided
35
 * for their corresponding #AtkObject class.  In short, only UI
36
 * elements which are *not* GUI elements will omit this ATK interface.
37
 *
38
 * A possible exception might be textual information with a
39
 * transparent background, in which case text glyph bounding box
40
 * information is provided by #AtkText.
41
 */
42

            
43
enum
44
{
45
  BOUNDS_CHANGED,
46
  LAST_SIGNAL
47
};
48

            
49
static void atk_component_base_init (AtkComponentIface *class);
50

            
51
static gboolean atk_component_real_contains (AtkComponent *component,
52
                                             gint x,
53
                                             gint y,
54
                                             AtkCoordType coord_type);
55

            
56
static AtkObject *atk_component_real_ref_accessible_at_point (AtkComponent *component,
57
                                                              gint x,
58
                                                              gint y,
59
                                                              AtkCoordType coord_type);
60

            
61
static void atk_component_real_get_position (AtkComponent *component,
62
                                             gint *x,
63
                                             gint *y,
64
                                             AtkCoordType coord_type);
65

            
66
static void atk_component_real_get_size (AtkComponent *component,
67
                                         gint *width,
68
                                         gint *height);
69

            
70
static guint atk_component_signals[LAST_SIGNAL] = { 0 };
71

            
72
GType
73
2389
atk_component_get_type (void)
74
{
75
  static GType type = 0;
76

            
77
2389
  if (!type)
78
    {
79
      static const GTypeInfo tinfo = {
80
        sizeof (AtkComponentIface),
81
        (GBaseInitFunc) atk_component_base_init,
82
        (GBaseFinalizeFunc) NULL,
83

            
84
      };
85

            
86
161
      type = g_type_register_static (G_TYPE_INTERFACE, "AtkComponent", &tinfo, 0);
87
    }
88

            
89
2389
  return type;
90
}
91

            
92
static void
93
653
atk_component_base_init (AtkComponentIface *class)
94
{
95
  static gboolean initialized = FALSE;
96

            
97
653
  if (!initialized)
98
    {
99
161
      class->ref_accessible_at_point = atk_component_real_ref_accessible_at_point;
100
161
      class->contains = atk_component_real_contains;
101
161
      class->get_position = atk_component_real_get_position;
102
161
      class->get_size = atk_component_real_get_size;
103

            
104
      /**
105
       * AtkComponent::bounds-changed:
106
       * @atkcomponent: the object which received the signal.
107
       * @arg1: The AtkRectangle giving the new position and size.
108
       *
109
       * The 'bounds-changed" signal is emitted when the position or
110
       * size of the component changes.
111
       */
112
161
      atk_component_signals[BOUNDS_CHANGED] =
113
161
          g_signal_new ("bounds_changed",
114
                        ATK_TYPE_COMPONENT,
115
                        G_SIGNAL_RUN_LAST,
116
                        G_STRUCT_OFFSET (AtkComponentIface, bounds_changed),
117
                        (GSignalAccumulator) NULL, NULL,
118
                        g_cclosure_marshal_VOID__BOXED,
119
                        G_TYPE_NONE, 1,
120
161
                        ATK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
121

            
122
161
      initialized = TRUE;
123
    }
124
653
}
125

            
126
/**
127
 * atk_component_add_focus_handler: (skip)
128
 * @component: The #AtkComponent to attach the @handler to
129
 * @handler: The #AtkFocusHandler to be attached to @component
130
 *
131
 * Add the specified handler to the set of functions to be called
132
 * when this object receives focus events (in or out). If the handler is
133
 * already added it is not added again
134
 *
135
 * Deprecated: 2.9.4: If you need to track when an object gains or
136
 * lose the focus, use the #AtkObject::state-change "focused" notification instead.
137
 *
138
 * Returns: a handler id which can be used in atk_component_remove_focus_handler()
139
 * or zero if the handler was already added.
140
 **/
141
guint
142
atk_component_add_focus_handler (AtkComponent *component,
143
                                 AtkFocusHandler handler)
144
{
145
  AtkComponentIface *iface = NULL;
146
  g_return_val_if_fail (ATK_IS_COMPONENT (component), 0);
147

            
148
  iface = ATK_COMPONENT_GET_IFACE (component);
149

            
150
  if (iface->add_focus_handler)
151
    return (iface->add_focus_handler) (component, handler);
152
  else
153
    return 0;
154
}
155

            
156
/**
157
 * atk_component_remove_focus_handler:
158
 * @component: the #AtkComponent to remove the focus handler from
159
 * @handler_id: the handler id of the focus handler to be removed
160
 * from @component
161
 *
162
 * Remove the handler specified by @handler_id from the list of
163
 * functions to be executed when this object receives focus events
164
 * (in or out).
165
 *
166
 * Deprecated: 2.9.4: If you need to track when an object gains or
167
 * lose the focus, use the #AtkObject::state-change "focused" notification instead.
168
 *
169
 **/
170
void
171
atk_component_remove_focus_handler (AtkComponent *component,
172
                                    guint handler_id)
173
{
174
  AtkComponentIface *iface = NULL;
175
  g_return_if_fail (ATK_IS_COMPONENT (component));
176

            
177
  iface = ATK_COMPONENT_GET_IFACE (component);
178

            
179
  if (iface->remove_focus_handler)
180
    (iface->remove_focus_handler) (component, handler_id);
181
}
182

            
183
/**
184
 * atk_component_contains:
185
 * @component: the #AtkComponent
186
 * @x: x coordinate
187
 * @y: y coordinate
188
 * @coord_type: specifies whether the coordinates are relative to the screen
189
 * or to the components top level window
190
 *
191
 * Checks whether the specified point is within the extent of the @component.
192
 *
193
 * Toolkit implementor note: ATK provides a default implementation for
194
 * this virtual method. In general there are little reason to
195
 * re-implement it.
196
 *
197
 * Returns: %TRUE or %FALSE indicating whether the specified point is within
198
 * the extent of the @component or not
199
 **/
200
gboolean
201
2
atk_component_contains (AtkComponent *component,
202
                        gint x,
203
                        gint y,
204
                        AtkCoordType coord_type)
205
{
206
2
  AtkComponentIface *iface = NULL;
207
2
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
208

            
209
2
  iface = ATK_COMPONENT_GET_IFACE (component);
210

            
211
2
  if (iface->contains)
212
2
    return (iface->contains) (component, x, y, coord_type);
213
  else
214
    return FALSE;
215
}
216

            
217
/**
218
 * atk_component_ref_accessible_at_point:
219
 * @component: the #AtkComponent
220
 * @x: x coordinate
221
 * @y: y coordinate
222
 * @coord_type: specifies whether the coordinates are relative to the screen
223
 * or to the components top level window
224
 *
225
 * Gets a reference to the accessible child, if one exists, at the
226
 * coordinate point specified by @x and @y.
227
 *
228
 * Returns: (nullable) (transfer full): a reference to the accessible
229
 * child, if one exists
230
 **/
231
AtkObject *
232
1
atk_component_ref_accessible_at_point (AtkComponent *component,
233
                                       gint x,
234
                                       gint y,
235
                                       AtkCoordType coord_type)
236
{
237
1
  AtkComponentIface *iface = NULL;
238
1
  g_return_val_if_fail (ATK_IS_COMPONENT (component), NULL);
239

            
240
1
  iface = ATK_COMPONENT_GET_IFACE (component);
241

            
242
1
  if (iface->ref_accessible_at_point)
243
1
    return (iface->ref_accessible_at_point) (component, x, y, coord_type);
244
  else
245
    return NULL;
246
}
247

            
248
/**
249
 * atk_component_get_extents:
250
 * @component: an #AtkComponent
251
 * @x: (out) (optional): address of #gint to put x coordinate
252
 * @y: (out) (optional): address of #gint to put y coordinate
253
 * @width: (out) (optional): address of #gint to put width
254
 * @height: (out) (optional): address of #gint to put height
255
 * @coord_type: specifies whether the coordinates are relative to the screen
256
 * or to the components top level window
257
 *
258
 * Gets the rectangle which gives the extent of the @component.
259
 *
260
 * If the extent can not be obtained (e.g. a non-embedded plug or missing
261
 * support), all of x, y, width, height are set to -1.
262
 *
263
 **/
264
void
265
3
atk_component_get_extents (AtkComponent *component,
266
                           gint *x,
267
                           gint *y,
268
                           gint *width,
269
                           gint *height,
270
                           AtkCoordType coord_type)
271
{
272
3
  AtkComponentIface *iface = NULL;
273
  gint local_x, local_y, local_width, local_height;
274
  gint *real_x, *real_y, *real_width, *real_height;
275

            
276
3
  g_return_if_fail (ATK_IS_COMPONENT (component));
277

            
278
3
  if (x)
279
3
    real_x = x;
280
  else
281
    real_x = &local_x;
282
3
  if (y)
283
3
    real_y = y;
284
  else
285
    real_y = &local_y;
286
3
  if (width)
287
3
    real_width = width;
288
  else
289
    real_width = &local_width;
290
3
  if (height)
291
3
    real_height = height;
292
  else
293
    real_height = &local_height;
294

            
295
3
  iface = ATK_COMPONENT_GET_IFACE (component);
296

            
297
3
  if (iface->get_extents)
298
3
    (iface->get_extents) (component, real_x, real_y, real_width, real_height, coord_type);
299
  else
300
    {
301
      *real_x = -1;
302
      *real_y = -1;
303
      *real_width = -1;
304
      *real_height = -1;
305
    }
306
}
307

            
308
/**
309
 * atk_component_get_position:
310
 * @component: an #AtkComponent
311
 * @x: (out) (optional): address of #gint to put x coordinate position
312
 * @y: (out) (optional): address of #gint to put y coordinate position
313
 * @coord_type: specifies whether the coordinates are relative to the screen
314
 * or to the components top level window
315
 *
316
 * Gets the position of @component in the form of
317
 * a point specifying @component's top-left corner.
318
 *
319
 * If the position can not be obtained (e.g. a non-embedded plug or missing
320
 * support), x and y are set to -1.
321
 *
322
 * Deprecated: Since 2.12. Use atk_component_get_extents() instead.
323
 **/
324
void
325
atk_component_get_position (AtkComponent *component,
326
                            gint *x,
327
                            gint *y,
328
                            AtkCoordType coord_type)
329
{
330
  AtkComponentIface *iface = NULL;
331
  gint local_x, local_y;
332
  gint *real_x, *real_y;
333

            
334
  g_return_if_fail (ATK_IS_COMPONENT (component));
335

            
336
  if (x)
337
    real_x = x;
338
  else
339
    real_x = &local_x;
340
  if (y)
341
    real_y = y;
342
  else
343
    real_y = &local_y;
344

            
345
  iface = ATK_COMPONENT_GET_IFACE (component);
346

            
347
  if (iface->get_position)
348
    (iface->get_position) (component, real_x, real_y, coord_type);
349
  else
350
    {
351
      *real_x = -1;
352
      *real_y = -1;
353
    }
354
}
355

            
356
/**
357
 * atk_component_get_size:
358
 * @component: an #AtkComponent
359
 * @width: (out) (optional): address of #gint to put width of @component
360
 * @height: (out) (optional): address of #gint to put height of @component
361
 *
362
 * Gets the size of the @component in terms of width and height.
363
 *
364
 * If the size can not be obtained (e.g. a non-embedded plug or missing
365
 * support), width and height are set to -1.
366
 *
367
 * Deprecated: Since 2.12. Use atk_component_get_extents() instead.
368
 **/
369
void
370
atk_component_get_size (AtkComponent *component,
371
                        gint *width,
372
                        gint *height)
373
{
374
  AtkComponentIface *iface = NULL;
375
  gint local_width, local_height;
376
  gint *real_width, *real_height;
377

            
378
  g_return_if_fail (ATK_IS_COMPONENT (component));
379

            
380
  if (width)
381
    real_width = width;
382
  else
383
    real_width = &local_width;
384
  if (height)
385
    real_height = height;
386
  else
387
    real_height = &local_height;
388

            
389
  g_return_if_fail (ATK_IS_COMPONENT (component));
390

            
391
  iface = ATK_COMPONENT_GET_IFACE (component);
392

            
393
  if (iface->get_size)
394
    (iface->get_size) (component, real_width, real_height);
395
  else
396
    {
397
      *real_width = -1;
398
      *real_height = -1;
399
    }
400
}
401

            
402
/**
403
 * atk_component_get_layer:
404
 * @component: an #AtkComponent
405
 *
406
 * Gets the layer of the component.
407
 *
408
 * Returns: an #AtkLayer which is the layer of the component
409
 **/
410
AtkLayer
411
1
atk_component_get_layer (AtkComponent *component)
412
{
413
  AtkComponentIface *iface;
414

            
415
1
  g_return_val_if_fail (ATK_IS_COMPONENT (component), ATK_LAYER_INVALID);
416

            
417
1
  iface = ATK_COMPONENT_GET_IFACE (component);
418
1
  if (iface->get_layer)
419
1
    return (iface->get_layer) (component);
420
  else
421
    return ATK_LAYER_WIDGET;
422
}
423

            
424
/**
425
 * atk_component_get_mdi_zorder:
426
 * @component: an #AtkComponent
427
 *
428
 * Gets the zorder of the component. The value G_MININT will be returned
429
 * if the layer of the component is not ATK_LAYER_MDI or ATK_LAYER_WINDOW.
430
 *
431
 * Returns: a gint which is the zorder of the component, i.e. the depth at
432
 * which the component is shown in relation to other components in the same
433
 * container.
434
 **/
435
gint
436
1
atk_component_get_mdi_zorder (AtkComponent *component)
437
{
438
  AtkComponentIface *iface;
439

            
440
1
  g_return_val_if_fail (ATK_IS_COMPONENT (component), G_MININT);
441

            
442
1
  iface = ATK_COMPONENT_GET_IFACE (component);
443
1
  if (iface->get_mdi_zorder)
444
1
    return (iface->get_mdi_zorder) (component);
445
  else
446
    return G_MININT;
447
}
448

            
449
/**
450
 * atk_component_get_alpha:
451
 * @component: an #AtkComponent
452
 *
453
 * Returns the alpha value (i.e. the opacity) for this
454
 * @component, on a scale from 0 (fully transparent) to 1.0
455
 * (fully opaque).
456
 *
457
 * Returns: An alpha value from 0 to 1.0, inclusive.
458
 * Since: 1.12
459
 **/
460
gdouble
461
1
atk_component_get_alpha (AtkComponent *component)
462
{
463
  AtkComponentIface *iface;
464

            
465
1
  g_return_val_if_fail (ATK_IS_COMPONENT (component), G_MININT);
466

            
467
1
  iface = ATK_COMPONENT_GET_IFACE (component);
468
1
  if (iface->get_alpha)
469
1
    return (iface->get_alpha) (component);
470
  else
471
    return (gdouble) 1.0;
472
}
473

            
474
/**
475
 * atk_component_grab_focus:
476
 * @component: an #AtkComponent
477
 *
478
 * Grabs focus for this @component.
479
 *
480
 * Returns: %TRUE if successful, %FALSE otherwise.
481
 **/
482
gboolean
483
1
atk_component_grab_focus (AtkComponent *component)
484
{
485
1
  AtkComponentIface *iface = NULL;
486
1
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
487

            
488
1
  iface = ATK_COMPONENT_GET_IFACE (component);
489

            
490
1
  if (iface->grab_focus)
491
1
    return (iface->grab_focus) (component);
492
  else
493
    return FALSE;
494
}
495

            
496
/**
497
 * atk_component_set_extents:
498
 * @component: an #AtkComponent
499
 * @x: x coordinate
500
 * @y: y coordinate
501
 * @width: width to set for @component
502
 * @height: height to set for @component
503
 * @coord_type: specifies whether the coordinates are relative to the screen
504
 * or to the components top level window
505
 *
506
 * Sets the extents of @component.
507
 *
508
 * Returns: %TRUE or %FALSE whether the extents were set or not
509
 **/
510
gboolean
511
28
atk_component_set_extents (AtkComponent *component,
512
                           gint x,
513
                           gint y,
514
                           gint width,
515
                           gint height,
516
                           AtkCoordType coord_type)
517
{
518
28
  AtkComponentIface *iface = NULL;
519
28
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
520

            
521
28
  iface = ATK_COMPONENT_GET_IFACE (component);
522

            
523
28
  if (iface->set_extents)
524
28
    return (iface->set_extents) (component, x, y, width, height, coord_type);
525
  else
526
    return FALSE;
527
}
528

            
529
/**
530
 * atk_component_set_position:
531
 * @component: an #AtkComponent
532
 * @x: x coordinate
533
 * @y: y coordinate
534
 * @coord_type: specifies whether the coordinates are relative to the screen
535
 * or to the component's top level window
536
 *
537
 * Sets the position of @component.
538
 *
539
 * Contrary to atk_component_scroll_to, this does not trigger any scrolling,
540
 * this just moves @component in its parent.
541
 *
542
 * Returns: %TRUE or %FALSE whether or not the position was set or not
543
 **/
544
gboolean
545
atk_component_set_position (AtkComponent *component,
546
                            gint x,
547
                            gint y,
548
                            AtkCoordType coord_type)
549
{
550
  AtkComponentIface *iface = NULL;
551
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
552

            
553
  iface = ATK_COMPONENT_GET_IFACE (component);
554

            
555
  if (iface->set_position)
556
    return (iface->set_position) (component, x, y, coord_type);
557
  else
558
    return FALSE;
559
}
560

            
561
/**
562
 * atk_component_set_size:
563
 * @component: an #AtkComponent
564
 * @width: width to set for @component
565
 * @height: height to set for @component
566
 *
567
 * Set the size of the @component in terms of width and height.
568
 *
569
 * Returns: %TRUE or %FALSE whether the size was set or not
570
 **/
571
gboolean
572
atk_component_set_size (AtkComponent *component,
573
                        gint x,
574
                        gint y)
575
{
576
  AtkComponentIface *iface = NULL;
577
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
578

            
579
  iface = ATK_COMPONENT_GET_IFACE (component);
580

            
581
  if (iface->set_size)
582
    return (iface->set_size) (component, x, y);
583
  else
584
    return FALSE;
585
}
586

            
587
/**
588
 * atk_component_scroll_to:
589
 * @component: an #AtkComponent
590
 * @type: specify where the object should be made visible.
591
 *
592
 * Makes @component visible on the screen by scrolling all necessary parents.
593
 *
594
 * Contrary to atk_component_set_position, this does not actually move
595
 * @component in its parent, this only makes the parents scroll so that the
596
 * object shows up on the screen, given its current position within the parents.
597
 *
598
 * Returns: whether scrolling was successful.
599
 *
600
 * Since: 2.30
601
 */
602
gboolean
603
atk_component_scroll_to (AtkComponent *component,
604
                         AtkScrollType type)
605
{
606
  AtkComponentIface *iface = NULL;
607
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
608

            
609
  iface = ATK_COMPONENT_GET_IFACE (component);
610

            
611
  if (iface->scroll_to)
612
    return (iface->scroll_to) (component, type);
613

            
614
  return FALSE;
615
}
616

            
617
/**
618
 * atk_component_scroll_to_point:
619
 * @component: an #AtkComponent
620
 * @coords: specify whether coordinates are relative to the screen or to the
621
 * parent object.
622
 * @x: x-position where to scroll to
623
 * @y: y-position where to scroll to
624
 *
625
 * Move the top-left of @component to a given position of the screen by
626
 * scrolling all necessary parents.
627
 *
628
 * Returns: whether scrolling was successful.
629
 *
630
 * Since: 2.30
631
 */
632
gboolean
633
atk_component_scroll_to_point (AtkComponent *component,
634
                               AtkCoordType coords,
635
                               gint x,
636
                               gint y)
637
{
638
  AtkComponentIface *iface = NULL;
639
  g_return_val_if_fail (ATK_IS_COMPONENT (component), FALSE);
640

            
641
  iface = ATK_COMPONENT_GET_IFACE (component);
642

            
643
  if (iface->scroll_to_point)
644
    return (iface->scroll_to_point) (component, coords, x, y);
645

            
646
  return FALSE;
647
}
648

            
649
static gboolean
650
atk_component_real_contains (AtkComponent *component,
651
                             gint x,
652
                             gint y,
653
                             AtkCoordType coord_type)
654
{
655
  gint real_x, real_y, width, height;
656

            
657
  real_x = real_y = width = height = 0;
658

            
659
  atk_component_get_extents (component, &real_x, &real_y, &width, &height, coord_type);
660

            
661
  if ((x >= real_x) &&
662
      (x < real_x + width) &&
663
      (y >= real_y) &&
664
      (y < real_y + height))
665
    return TRUE;
666
  else
667
    return FALSE;
668
}
669

            
670
static AtkObject *
671
atk_component_real_ref_accessible_at_point (AtkComponent *component,
672
                                            gint x,
673
                                            gint y,
674
                                            AtkCoordType coord_type)
675
{
676
  gint count, i;
677

            
678
  count = atk_object_get_n_accessible_children (ATK_OBJECT (component));
679

            
680
  for (i = 0; i < count; i++)
681
    {
682
      AtkObject *obj;
683

            
684
      obj = atk_object_ref_accessible_child (ATK_OBJECT (component), i);
685

            
686
      if (obj != NULL)
687
        {
688
          if (atk_component_contains (ATK_COMPONENT (obj), x, y, coord_type))
689
            {
690
              return obj;
691
            }
692
          else
693
            {
694
              g_object_unref (obj);
695
            }
696
        }
697
    }
698
  return NULL;
699
}
700

            
701
static void
702
atk_component_real_get_position (AtkComponent *component,
703
                                 gint *x,
704
                                 gint *y,
705
                                 AtkCoordType coord_type)
706
{
707
  gint width, height;
708

            
709
  atk_component_get_extents (component, x, y, &width, &height, coord_type);
710
}
711

            
712
static void
713
atk_component_real_get_size (AtkComponent *component,
714
                             gint *width,
715
                             gint *height)
716
{
717
  gint x, y;
718
  AtkCoordType coord_type;
719

            
720
  /*
721
   * Pick one coordinate type; it does not matter for size
722
   */
723
  coord_type = ATK_XY_WINDOW;
724

            
725
  atk_component_get_extents (component, &x, &y, width, height, coord_type);
726
}
727

            
728
static AtkRectangle *
729
atk_rectangle_copy (const AtkRectangle *rectangle)
730
{
731
  AtkRectangle *result = g_new (AtkRectangle, 1);
732
  *result = *rectangle;
733

            
734
  return result;
735
}
736

            
737
GType
738
161
atk_rectangle_get_type (void)
739
{
740
  static GType our_type = 0;
741

            
742
161
  if (our_type == 0)
743
161
    our_type = g_boxed_type_register_static ("AtkRectangle",
744
                                             (GBoxedCopyFunc) atk_rectangle_copy,
745
                                             (GBoxedFreeFunc) g_free);
746
161
  return our_type;
747
}