1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
21 * GtkTicker Copyright 2000 Syd Logan
24 #include "gtkticker.h"
27 static void gtk_ticker_compute_offsets (GtkTicker
*ticker
);
28 static void gtk_ticker_class_init (GtkTickerClass
*klass
);
29 static void gtk_ticker_init (GtkTicker
*ticker
);
30 static void gtk_ticker_map (GtkWidget
*widget
);
31 static void gtk_ticker_realize (GtkWidget
*widget
);
32 static void gtk_ticker_size_request (GtkWidget
*widget
,
33 GtkRequisition
*requisition
);
34 static void gtk_ticker_size_allocate (GtkWidget
*widget
,
35 GtkAllocation
*allocation
);
36 static void gtk_ticker_paint (GtkWidget
*widget
,
38 static void gtk_ticker_draw (GtkWidget
*widget
,
40 static gint
gtk_ticker_expose (GtkWidget
*widget
,
41 GdkEventExpose
*event
);
42 static void gtk_ticker_add_real (GtkContainer
*container
,
44 static void gtk_ticker_remove_real (GtkContainer
*container
,
46 static void gtk_ticker_forall (GtkContainer
*container
,
47 gboolean include_internals
,
49 gpointer callback_data
);
50 static GtkType
gtk_ticker_child_type (GtkContainer
*container
);
53 static GtkContainerClass
*parent_class
= NULL
;
57 gtk_ticker_get_type (void)
59 static GtkType ticker_type
= 0;
63 static const GtkTypeInfo ticker_info
=
67 sizeof (GtkTickerClass
),
68 (GtkClassInitFunc
) gtk_ticker_class_init
,
69 (GtkObjectInitFunc
) gtk_ticker_init
,
70 /* reserved_1 */ NULL
,
71 /* reserved_2 */ NULL
,
72 (GtkClassInitFunc
) NULL
,
75 ticker_type
= gtk_type_unique (GTK_TYPE_CONTAINER
, &ticker_info
);
82 gtk_ticker_class_init (GtkTickerClass
*class)
84 GtkObjectClass
*object_class
;
85 GtkWidgetClass
*widget_class
;
86 GtkContainerClass
*container_class
;
88 object_class
= (GtkObjectClass
*) class;
89 widget_class
= (GtkWidgetClass
*) class;
90 container_class
= (GtkContainerClass
*) class;
92 parent_class
= gtk_type_class (GTK_TYPE_CONTAINER
);
94 widget_class
->map
= gtk_ticker_map
;
95 widget_class
->realize
= gtk_ticker_realize
;
96 widget_class
->size_request
= gtk_ticker_size_request
;
97 widget_class
->size_allocate
= gtk_ticker_size_allocate
;
98 #if ! GTK_CHECK_VERSION(1,3,0)
99 widget_class
->draw
= gtk_ticker_draw
;
101 widget_class
->expose_event
= gtk_ticker_expose
;
103 container_class
->add
= gtk_ticker_add_real
;
104 container_class
->remove
= gtk_ticker_remove_real
;
105 container_class
->forall
= gtk_ticker_forall
;
106 container_class
->child_type
= gtk_ticker_child_type
;
110 gtk_ticker_child_type (GtkContainer
*container
)
112 return GTK_TYPE_WIDGET
;
116 gtk_ticker_init (GtkTicker
*ticker
)
118 GTK_WIDGET_UNSET_FLAGS (ticker
, GTK_NO_WINDOW
);
120 ticker
->interval
= (guint
) 200;
121 ticker
->scootch
= (guint
) 2;
122 ticker
->children
= NULL
;
124 ticker
->dirty
= TRUE
;
128 gtk_ticker_new (void)
132 ticker
= gtk_type_new (GTK_TYPE_TICKER
);
133 return GTK_WIDGET (ticker
);
137 gtk_ticker_put (GtkTicker
*ticker
,
140 GtkTickerChild
*child_info
;
142 g_return_if_fail (ticker
!= NULL
);
143 g_return_if_fail (GTK_IS_TICKER (ticker
));
144 g_return_if_fail (widget
!= NULL
);
146 child_info
= g_new(GtkTickerChild
, 1);
147 child_info
->widget
= widget
;
150 gtk_widget_set_parent(widget
, GTK_WIDGET (ticker
));
152 ticker
->children
= g_list_append (ticker
->children
, child_info
);
154 if (GTK_WIDGET_REALIZED (ticker
))
155 gtk_widget_realize (widget
);
157 if (GTK_WIDGET_VISIBLE (ticker
) && GTK_WIDGET_VISIBLE (widget
))
159 if (GTK_WIDGET_MAPPED (ticker
))
160 gtk_widget_map (widget
);
162 gtk_widget_queue_resize (GTK_WIDGET (ticker
));
167 gtk_ticker_set_interval (GtkTicker
*ticker
, gint interval
)
169 g_return_if_fail (ticker
!= NULL
);
170 g_return_if_fail (GTK_IS_TICKER (ticker
));
174 ticker
->interval
= interval
;
179 gtk_ticker_get_interval (GtkTicker
*ticker
)
181 g_return_val_if_fail (ticker
!= NULL
, -1);
182 g_return_val_if_fail (GTK_IS_TICKER (ticker
), -1);
184 return ticker
->interval
;
188 gtk_ticker_set_scootch (GtkTicker
*ticker
, gint scootch
)
190 g_return_if_fail (ticker
!= NULL
);
191 g_return_if_fail (GTK_IS_TICKER (ticker
));
195 ticker
->scootch
= scootch
;
196 ticker
->dirty
= TRUE
;
200 gtk_ticker_get_scootch (GtkTicker
*ticker
)
202 g_return_val_if_fail (ticker
!= NULL
, -1);
203 g_return_val_if_fail (GTK_IS_TICKER (ticker
), -1);
205 return ticker
->scootch
;
209 gtk_ticker_set_spacing (GtkTicker
*ticker
, gint spacing
)
211 g_return_if_fail (ticker
!= NULL
);
212 g_return_if_fail (GTK_IS_TICKER (ticker
));
216 ticker
->spacing
= spacing
;
217 ticker
->dirty
= TRUE
;
222 ticker_timeout( gpointer data
)
224 GtkTicker
*ticker
= (GtkTicker
*) data
;
226 if (GTK_WIDGET_VISIBLE (ticker
))
227 gtk_widget_queue_resize (GTK_WIDGET (ticker
));
233 gtk_ticker_start_scroll(GtkTicker
*ticker
)
235 g_return_if_fail (ticker
!= NULL
);
236 g_return_if_fail (GTK_IS_TICKER (ticker
));
237 if ( ticker
->timer
!= 0 )
239 ticker
->timer
= g_timeout_add(ticker
->interval
,
240 ticker_timeout
, ticker
);
244 gtk_ticker_stop_scroll(GtkTicker
*ticker
)
246 g_return_if_fail (ticker
!= NULL
);
247 g_return_if_fail (GTK_IS_TICKER (ticker
));
248 if ( ticker
->timer
== 0 )
250 g_source_remove(ticker
->timer
);
256 gtk_ticker_get_spacing (GtkTicker
*ticker
)
258 g_return_val_if_fail (ticker
!= NULL
, -1);
259 g_return_val_if_fail (GTK_IS_TICKER (ticker
), -1);
261 return ticker
->spacing
;
265 gtk_ticker_map (GtkWidget
*widget
)
268 GtkTickerChild
*child
;
271 g_return_if_fail (widget
!= NULL
);
272 g_return_if_fail (GTK_IS_TICKER (widget
));
274 GTK_WIDGET_SET_FLAGS (widget
, GTK_MAPPED
);
275 ticker
= GTK_TICKER (widget
);
277 children
= ticker
->children
;
280 child
= children
->data
;
281 children
= children
->next
;
283 if (GTK_WIDGET_VISIBLE (child
->widget
) &&
284 !GTK_WIDGET_MAPPED (child
->widget
))
285 gtk_widget_map (child
->widget
);
288 gdk_window_show (widget
->window
);
292 gtk_ticker_realize (GtkWidget
*widget
)
294 GdkWindowAttr attributes
;
295 gint attributes_mask
;
297 g_return_if_fail (widget
!= NULL
);
298 g_return_if_fail (GTK_IS_TICKER (widget
));
300 GTK_WIDGET_SET_FLAGS (widget
, GTK_REALIZED
);
302 attributes
.window_type
= GDK_WINDOW_CHILD
;
303 attributes
.x
= widget
->allocation
.x
;
304 attributes
.y
= widget
->allocation
.y
;
305 attributes
.width
= widget
->allocation
.width
;
306 attributes
.height
= widget
->allocation
.height
;
307 attributes
.wclass
= GDK_INPUT_OUTPUT
;
308 attributes
.visual
= gtk_widget_get_visual (widget
);
309 attributes
.colormap
= gtk_widget_get_colormap (widget
);
310 attributes
.event_mask
= gtk_widget_get_events (widget
);
311 attributes
.event_mask
|= GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
;
313 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
;
315 widget
->window
= gdk_window_new (gtk_widget_get_parent_window (widget
),
316 &attributes
, attributes_mask
);
317 gdk_window_set_user_data (widget
->window
, widget
);
319 widget
->style
= gtk_style_attach (widget
->style
, widget
->window
);
320 gtk_style_set_background (widget
->style
, widget
->window
, GTK_STATE_NORMAL
);
324 gtk_ticker_size_request (GtkWidget
*widget
,
325 GtkRequisition
*requisition
)
328 GtkTickerChild
*child
;
330 GtkRequisition child_requisition
;
332 g_return_if_fail (widget
!= NULL
);
333 g_return_if_fail (GTK_IS_TICKER (widget
));
334 g_return_if_fail (requisition
!= NULL
);
336 ticker
= GTK_TICKER (widget
);
337 requisition
->width
= 0;
338 requisition
->height
= 0;
340 children
= ticker
->children
;
343 child
= children
->data
;
344 children
= children
->next
;
346 if (GTK_WIDGET_VISIBLE (child
->widget
))
348 gtk_widget_size_request (child
->widget
, &child_requisition
);
350 requisition
->height
= MAX (requisition
->height
,
351 child_requisition
.height
);
352 requisition
->width
+= child_requisition
.width
+ ticker
->spacing
;
355 if ( requisition
->width
> ticker
->spacing
)
356 requisition
->width
-= ticker
->spacing
;
358 requisition
->height
+= GTK_CONTAINER (ticker
)->border_width
* 2;
359 requisition
->width
+= GTK_CONTAINER (ticker
)->border_width
* 2;
363 gtk_ticker_compute_offsets (GtkTicker
*ticker
)
365 GtkTickerChild
*child
;
366 GtkRequisition child_requisition
;
368 guint16 border_width
;
370 g_return_if_fail (ticker
!= NULL
);
371 g_return_if_fail (GTK_IS_TICKER(ticker
));
373 border_width
= GTK_CONTAINER (ticker
)->border_width
;
375 ticker
->width
= GTK_WIDGET(ticker
)->allocation
.width
;
377 children
= ticker
->children
;
379 child
= children
->data
;
382 if (GTK_WIDGET_VISIBLE (child
->widget
)) {
383 gtk_widget_get_child_requisition (child
->widget
, &child_requisition
);
384 child
->offset
= ticker
->total
;
386 child_requisition
.width
+ border_width
+ ticker
->spacing
;
388 children
= children
->next
;
390 ticker
->dirty
= FALSE
;
394 gtk_ticker_size_allocate (GtkWidget
*widget
,
395 GtkAllocation
*allocation
)
398 GtkTickerChild
*child
;
399 GtkAllocation child_allocation
;
400 GtkRequisition child_requisition
;
402 guint16 border_width
;
404 g_return_if_fail (widget
!= NULL
);
405 g_return_if_fail (GTK_IS_TICKER(widget
));
406 g_return_if_fail (allocation
!= NULL
);
408 ticker
= GTK_TICKER (widget
);
410 if ( GTK_WIDGET(ticker
)->allocation
.width
!= ticker
->width
)
411 ticker
->dirty
= TRUE
;
413 if ( ticker
->dirty
== TRUE
) {
414 gtk_ticker_compute_offsets( ticker
);
417 widget
->allocation
= *allocation
;
418 if (GTK_WIDGET_REALIZED (widget
))
419 gdk_window_move_resize (widget
->window
,
425 border_width
= GTK_CONTAINER (ticker
)->border_width
;
427 children
= ticker
->children
;
430 child
= children
->data
;
431 child
->x
-= ticker
->scootch
;
433 if (GTK_WIDGET_VISIBLE (child
->widget
)) {
434 gtk_widget_get_child_requisition (child
->widget
, &child_requisition
);
435 child_allocation
.width
= child_requisition
.width
;
436 child_allocation
.x
= child
->offset
+ border_width
+ child
->x
;
437 if ( ( child_allocation
.x
+ child_allocation
.width
) < GTK_WIDGET(ticker
)->allocation
.x
) {
438 if ( ticker
->total
>= GTK_WIDGET(ticker
)->allocation
.width
) {
439 child
->x
+= GTK_WIDGET(ticker
)->allocation
.x
+ GTK_WIDGET(ticker
)->allocation
.width
+ ( ticker
->total
- ( GTK_WIDGET(ticker
)->allocation
.x
+ GTK_WIDGET(ticker
)->allocation
.width
) );
442 child
->x
+= GTK_WIDGET(ticker
)->allocation
.x
+ GTK_WIDGET(ticker
)->allocation
.width
;
445 child_allocation
.y
= border_width
;
446 child_allocation
.height
= child_requisition
.height
;
447 gtk_widget_size_allocate (child
->widget
, &child_allocation
);
449 children
= children
->next
;
454 gtk_ticker_paint (GtkWidget
*widget
,
457 g_return_if_fail (widget
!= NULL
);
458 g_return_if_fail (GTK_IS_TICKER (widget
));
459 g_return_if_fail (area
!= NULL
);
461 if (GTK_WIDGET_DRAWABLE (widget
))
462 gdk_window_clear_area (widget
->window
, 0, 0, widget
->allocation
.width
,
463 widget
->allocation
.height
);
467 gtk_ticker_draw (GtkWidget
*widget
,
471 GtkTickerChild
*child
;
474 g_return_if_fail (widget
!= NULL
);
475 g_return_if_fail (GTK_IS_TICKER (widget
));
477 if (GTK_WIDGET_DRAWABLE (widget
))
479 ticker
= GTK_TICKER (widget
);
480 gtk_ticker_paint (widget
, area
);
482 children
= ticker
->children
;
485 child
= children
->data
;
486 children
= children
->next
;
487 gtk_widget_draw (child
->widget
, NULL
);
493 gtk_ticker_expose (GtkWidget
*widget
, GdkEventExpose
*event
)
496 GtkTickerChild
*child
;
497 GdkEventExpose child_event
;
500 g_return_val_if_fail (widget
!= NULL
, FALSE
);
501 g_return_val_if_fail (GTK_IS_TICKER (widget
), FALSE
);
502 g_return_val_if_fail (event
!= NULL
, FALSE
);
504 if (GTK_WIDGET_DRAWABLE (widget
))
506 ticker
= GTK_TICKER (widget
);
508 child_event
= *event
;
510 children
= ticker
->children
;
513 child
= children
->data
;
514 children
= children
->next
;
516 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
517 gtk_widget_intersect (child
->widget
, &event
->area
,
519 gtk_widget_event (child
->widget
, (GdkEvent
*) &child_event
);
527 gtk_ticker_add(GtkTicker
*ticker
, GtkWidget
*widget
)
529 gtk_ticker_add_real( GTK_CONTAINER( ticker
), widget
);
530 ticker
->dirty
= TRUE
;
534 gtk_ticker_remove(GtkTicker
*ticker
, GtkWidget
*widget
)
536 gtk_ticker_remove_real( GTK_CONTAINER( ticker
), widget
);
537 ticker
->dirty
= TRUE
;
541 gtk_ticker_add_real(GtkContainer
*container
,
544 g_return_if_fail (container
!= NULL
);
545 g_return_if_fail (GTK_IS_TICKER (container
));
546 g_return_if_fail (widget
!= NULL
);
548 gtk_ticker_put(GTK_TICKER (container
), widget
);
552 gtk_ticker_remove_real(GtkContainer
*container
,
556 GtkTickerChild
*child
;
559 g_return_if_fail (container
!= NULL
);
560 g_return_if_fail (GTK_IS_TICKER (container
));
561 g_return_if_fail (widget
!= NULL
);
563 ticker
= GTK_TICKER (container
);
565 children
= ticker
->children
;
568 child
= children
->data
;
570 if (child
->widget
== widget
)
572 gboolean was_visible
= GTK_WIDGET_VISIBLE (widget
);
574 gtk_widget_unparent (widget
);
576 ticker
->children
= g_list_remove_link (ticker
->children
, children
);
577 g_list_free (children
);
580 if (was_visible
&& GTK_WIDGET_VISIBLE (container
))
581 gtk_widget_queue_resize (GTK_WIDGET (container
));
586 children
= children
->next
;
591 gtk_ticker_forall (GtkContainer
*container
,
592 gboolean include_internals
,
593 GtkCallback callback
,
594 gpointer callback_data
)
597 GtkTickerChild
*child
;
600 g_return_if_fail (container
!= NULL
);
601 g_return_if_fail (GTK_IS_TICKER (container
));
602 g_return_if_fail (callback
!= NULL
);
604 ticker
= GTK_TICKER (container
);
606 children
= ticker
->children
;
609 child
= children
->data
;
610 children
= children
->next
;
612 (* callback
) (child
->widget
, callback_data
);