1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
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, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include "gtkprogressbar.h" |
28 | |
29 | #include "gtkboxlayout.h" |
30 | #include "gtkgizmoprivate.h" |
31 | #include "gtkintl.h" |
32 | #include "gtklabel.h" |
33 | #include "gtkorientable.h" |
34 | #include "gtkprogresstrackerprivate.h" |
35 | #include "gtkprivate.h" |
36 | #include "gtkwidgetprivate.h" |
37 | |
38 | #include <string.h> |
39 | |
40 | /** |
41 | * GtkProgressBar: |
42 | * |
43 | * `GtkProgressBar` is typically used to display the progress of a long |
44 | * running operation. |
45 | * |
46 | * It provides a visual clue that processing is underway. `GtkProgressBar` |
47 | * can be used in two different modes: percentage mode and activity mode. |
48 | * |
49 | * ![An example GtkProgressBar](progressbar.png) |
50 | * |
51 | * When an application can determine how much work needs to take place |
52 | * (e.g. read a fixed number of bytes from a file) and can monitor its |
53 | * progress, it can use the `GtkProgressBar` in percentage mode and the |
54 | * user sees a growing bar indicating the percentage of the work that |
55 | * has been completed. In this mode, the application is required to call |
56 | * [method@Gtk.ProgressBar.set_fraction] periodically to update the progress bar. |
57 | * |
58 | * When an application has no accurate way of knowing the amount of work |
59 | * to do, it can use the `GtkProgressBar` in activity mode, which shows |
60 | * activity by a block moving back and forth within the progress area. In |
61 | * this mode, the application is required to call [method@Gtk.ProgressBar.pulse] |
62 | * periodically to update the progress bar. |
63 | * |
64 | * There is quite a bit of flexibility provided to control the appearance |
65 | * of the `GtkProgressBar`. Functions are provided to control the orientation |
66 | * of the bar, optional text can be displayed along with the bar, and the |
67 | * step size used in activity mode can be set. |
68 | * |
69 | * # CSS nodes |
70 | * |
71 | * ``` |
72 | * progressbar[.osd] |
73 | * ├── [text] |
74 | * ╰── trough[.empty][.full] |
75 | * ╰── progress[.pulse] |
76 | * ``` |
77 | * |
78 | * `GtkProgressBar` has a main CSS node with name progressbar and subnodes with |
79 | * names text and trough, of which the latter has a subnode named progress. The |
80 | * text subnode is only present if text is shown. The progress subnode has the |
81 | * style class .pulse when in activity mode. It gets the style classes .left, |
82 | * .right, .top or .bottom added when the progress 'touches' the corresponding |
83 | * end of the GtkProgressBar. The .osd class on the progressbar node is for use |
84 | * in overlays like the one Epiphany has for page loading progress. |
85 | * |
86 | * # Accessibility |
87 | * |
88 | * `GtkProgressBar` uses the %GTK_ACCESSIBLE_ROLE_PROGRESS_BAR role. |
89 | */ |
90 | |
91 | typedef struct _GtkProgressBarClass GtkProgressBarClass; |
92 | |
93 | struct _GtkProgressBar |
94 | { |
95 | GtkWidget parent_instance; |
96 | |
97 | char *text; |
98 | |
99 | GtkWidget *label; |
100 | GtkWidget *trough_widget; |
101 | GtkWidget *progress_widget; |
102 | |
103 | double fraction; |
104 | double pulse_fraction; |
105 | |
106 | double activity_pos; |
107 | guint activity_blocks; |
108 | |
109 | GtkOrientation orientation; |
110 | |
111 | guint tick_id; |
112 | GtkProgressTracker tracker; |
113 | gint64 pulse1; |
114 | gint64 pulse2; |
115 | double last_iteration; |
116 | |
117 | guint activity_dir : 1; |
118 | guint activity_mode : 1; |
119 | guint ellipsize : 3; |
120 | guint show_text : 1; |
121 | guint inverted : 1; |
122 | }; |
123 | |
124 | struct _GtkProgressBarClass |
125 | { |
126 | GtkWidgetClass parent_class; |
127 | }; |
128 | |
129 | enum { |
130 | PROP_0, |
131 | PROP_FRACTION, |
132 | PROP_PULSE_STEP, |
133 | PROP_INVERTED, |
134 | PROP_TEXT, |
135 | PROP_SHOW_TEXT, |
136 | PROP_ELLIPSIZE, |
137 | PROP_ORIENTATION, |
138 | NUM_PROPERTIES = PROP_ORIENTATION |
139 | }; |
140 | |
141 | static GParamSpec *progress_props[NUM_PROPERTIES] = { NULL, }; |
142 | |
143 | static void gtk_progress_bar_set_property (GObject *object, |
144 | guint prop_id, |
145 | const GValue *value, |
146 | GParamSpec *pspec); |
147 | static void gtk_progress_bar_get_property (GObject *object, |
148 | guint prop_id, |
149 | GValue *value, |
150 | GParamSpec *pspec); |
151 | static void gtk_progress_bar_act_mode_enter (GtkProgressBar *progress); |
152 | static void gtk_progress_bar_act_mode_leave (GtkProgressBar *progress); |
153 | static void gtk_progress_bar_finalize (GObject *object); |
154 | static void gtk_progress_bar_dispose (GObject *object); |
155 | static void gtk_progress_bar_set_orientation (GtkProgressBar *progress, |
156 | GtkOrientation orientation); |
157 | static void gtk_progress_bar_direction_changed (GtkWidget *widget, |
158 | GtkTextDirection previous_dir); |
159 | |
160 | G_DEFINE_TYPE_WITH_CODE (GtkProgressBar, gtk_progress_bar, GTK_TYPE_WIDGET, |
161 | G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)) |
162 | |
163 | static void |
164 | gtk_progress_bar_class_init (GtkProgressBarClass *class) |
165 | { |
166 | GObjectClass *gobject_class; |
167 | GtkWidgetClass *widget_class; |
168 | |
169 | gobject_class = G_OBJECT_CLASS (class); |
170 | widget_class = (GtkWidgetClass *) class; |
171 | |
172 | gobject_class->set_property = gtk_progress_bar_set_property; |
173 | gobject_class->get_property = gtk_progress_bar_get_property; |
174 | gobject_class->dispose = gtk_progress_bar_dispose; |
175 | gobject_class->finalize = gtk_progress_bar_finalize; |
176 | |
177 | widget_class->direction_changed = gtk_progress_bar_direction_changed; |
178 | |
179 | g_object_class_override_property (oclass: gobject_class, property_id: PROP_ORIENTATION, name: "orientation" ); |
180 | |
181 | /** |
182 | * GtkProgressBar:inverted: (attributes org.gtk.Property.get=gtk_progress_bar_get_inverted org.gtk.Property.set=gtk_progress_bar_set_inverted) |
183 | * |
184 | * Invert the direction in which the progress bar grows. |
185 | */ |
186 | progress_props[PROP_INVERTED] = |
187 | g_param_spec_boolean (name: "inverted" , |
188 | P_("Inverted" ), |
189 | P_("Invert the direction in which the progress bar grows" ), |
190 | FALSE, |
191 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
192 | |
193 | /** |
194 | * GtkProgressBar:fraction: (attributes org.gtk.Property.get=gtk_progress_bar_get_fraction org.gtk.Property.set=gtk_progress_bar_set_fraction) |
195 | * |
196 | * The fraction of total work that has been completed. |
197 | */ |
198 | progress_props[PROP_FRACTION] = |
199 | g_param_spec_double (name: "fraction" , |
200 | P_("Fraction" ), |
201 | P_("The fraction of total work that has been completed" ), |
202 | minimum: 0.0, maximum: 1.0, |
203 | default_value: 0.0, |
204 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
205 | |
206 | /** |
207 | * GtkProgressBar:pulse-step: (attributes org.gtk.Property.get=gtk_progress_bar_get_pulse_step org.gtk.Property.set=gtk_progress_bar_set_pulse_step) |
208 | * |
209 | * The fraction of total progress to move the bounding block when pulsed. |
210 | */ |
211 | progress_props[PROP_PULSE_STEP] = |
212 | g_param_spec_double (name: "pulse-step" , |
213 | P_("Pulse Step" ), |
214 | P_("The fraction of total progress to move the bouncing block when pulsed" ), |
215 | minimum: 0.0, maximum: 1.0, |
216 | default_value: 0.1, |
217 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
218 | |
219 | /** |
220 | * GtkProgressBar:text: (attributes org.gtk.Property.get=gtk_progress_bar_get_text org.gtk.Property.set=gtk_progress_bar_set_text) |
221 | * |
222 | * Text to be displayed in the progress bar. |
223 | */ |
224 | progress_props[PROP_TEXT] = |
225 | g_param_spec_string (name: "text" , |
226 | P_("Text" ), |
227 | P_("Text to be displayed in the progress bar" ), |
228 | NULL, |
229 | GTK_PARAM_READWRITE); |
230 | |
231 | /** |
232 | * GtkProgressBar:show-text: (attributes org.gtk.Property.get=gtk_progress_bar_get_show_text org.gtk.Property.set=gtk_progress_bar_set_show_text) |
233 | * |
234 | * Sets whether the progress bar will show a text in addition |
235 | * to the bar itself. |
236 | * |
237 | * The shown text is either the value of the [property@Gtk.ProgressBar:text] |
238 | * property or, if that is %NULL, the [property@Gtk.ProgressBar:fraction] |
239 | * value, as a percentage. |
240 | * |
241 | * To make a progress bar that is styled and sized suitably for showing text |
242 | * (even if the actual text is blank), set [property@Gtk.ProgressBar:show-text] |
243 | * to %TRUE and [property@Gtk.ProgressBar:text] to the empty string (not %NULL). |
244 | */ |
245 | progress_props[PROP_SHOW_TEXT] = |
246 | g_param_spec_boolean (name: "show-text" , |
247 | P_("Show text" ), |
248 | P_("Whether the progress is shown as text." ), |
249 | FALSE, |
250 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
251 | |
252 | /** |
253 | * GtkProgressBar:ellipsize: (attributes org.gtk.Property.get=gtk_progress_bar_get_ellipsize org.gtk.Property.set=gtk_progress_bar_set_ellipsize) |
254 | * |
255 | * The preferred place to ellipsize the string. |
256 | * |
257 | * The text will be ellipsized if the progress bar does not have enough room |
258 | * to display the entire string, specified as a `PangoEllipsizeMode`. |
259 | * |
260 | * Note that setting this property to a value other than |
261 | * %PANGO_ELLIPSIZE_NONE has the side-effect that the progress bar requests |
262 | * only enough space to display the ellipsis ("..."). Another means to set a |
263 | * progress bar's width is [method@Gtk.Widget.set_size_request]. |
264 | */ |
265 | progress_props[PROP_ELLIPSIZE] = |
266 | g_param_spec_enum (name: "ellipsize" , |
267 | P_("Ellipsize" ), |
268 | P_("The preferred place to ellipsize the string, if the progress bar " |
269 | "does not have enough room to display the entire string, if at all." ), |
270 | enum_type: PANGO_TYPE_ELLIPSIZE_MODE, |
271 | default_value: PANGO_ELLIPSIZE_NONE, |
272 | GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); |
273 | |
274 | g_object_class_install_properties (oclass: gobject_class, n_pspecs: NUM_PROPERTIES, pspecs: progress_props); |
275 | |
276 | gtk_widget_class_set_css_name (widget_class, I_("progressbar" )); |
277 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); |
278 | gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_PROGRESS_BAR); |
279 | } |
280 | |
281 | static void |
282 | update_fraction_classes (GtkProgressBar *pbar) |
283 | { |
284 | gboolean empty = FALSE; |
285 | gboolean full = FALSE; |
286 | |
287 | /* Here we set classes based on fill-level unless we're in activity-mode. |
288 | */ |
289 | |
290 | if (!pbar->activity_mode) |
291 | { |
292 | if (pbar->fraction <= 0.0) |
293 | empty = TRUE; |
294 | else if (pbar->fraction >= 1.0) |
295 | full = TRUE; |
296 | } |
297 | |
298 | if (empty) |
299 | gtk_widget_add_css_class (widget: pbar->trough_widget, css_class: "empty" ); |
300 | else |
301 | gtk_widget_remove_css_class (widget: pbar->trough_widget, css_class: "empty" ); |
302 | |
303 | if (full) |
304 | gtk_widget_add_css_class (widget: pbar->trough_widget, css_class: "full" ); |
305 | else |
306 | gtk_widget_remove_css_class (widget: pbar->trough_widget, css_class: "full" ); |
307 | } |
308 | |
309 | static void |
310 | update_node_classes (GtkProgressBar *pbar) |
311 | { |
312 | gboolean left = FALSE; |
313 | gboolean right = FALSE; |
314 | gboolean top = FALSE; |
315 | gboolean bottom = FALSE; |
316 | |
317 | /* Here we set positional classes, depending on which end of the |
318 | * progressbar the progress touches. |
319 | */ |
320 | |
321 | if (pbar->activity_mode) |
322 | { |
323 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
324 | { |
325 | left = pbar->activity_pos <= 0.0; |
326 | right = pbar->activity_pos >= 1.0; |
327 | } |
328 | else |
329 | { |
330 | top = pbar->activity_pos <= 0.0; |
331 | bottom = pbar->activity_pos >= 1.0; |
332 | } |
333 | } |
334 | else /* continuous */ |
335 | { |
336 | gboolean inverted; |
337 | |
338 | inverted = pbar->inverted; |
339 | if (gtk_widget_get_direction (GTK_WIDGET (pbar)) == GTK_TEXT_DIR_RTL) |
340 | { |
341 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
342 | inverted = !inverted; |
343 | } |
344 | |
345 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
346 | { |
347 | left = !inverted || pbar->fraction >= 1.0; |
348 | right = inverted || pbar->fraction >= 1.0; |
349 | } |
350 | else |
351 | { |
352 | top = !inverted || pbar->fraction >= 1.0; |
353 | bottom = inverted || pbar->fraction >= 1.0; |
354 | } |
355 | } |
356 | |
357 | if (left) |
358 | gtk_widget_add_css_class (widget: pbar->progress_widget, css_class: "left" ); |
359 | else |
360 | gtk_widget_remove_css_class (widget: pbar->progress_widget, css_class: "left" ); |
361 | |
362 | if (right) |
363 | gtk_widget_add_css_class (widget: pbar->progress_widget, css_class: "right" ); |
364 | else |
365 | gtk_widget_remove_css_class (widget: pbar->progress_widget, css_class: "right" ); |
366 | |
367 | if (top) |
368 | gtk_widget_add_css_class (widget: pbar->progress_widget, css_class: "top" ); |
369 | else |
370 | gtk_widget_remove_css_class (widget: pbar->progress_widget, css_class: "top" ); |
371 | |
372 | if (bottom) |
373 | gtk_widget_add_css_class (widget: pbar->progress_widget, css_class: "bottom" ); |
374 | else |
375 | gtk_widget_remove_css_class (widget: pbar->progress_widget, css_class: "bottom" ); |
376 | |
377 | update_fraction_classes (pbar); |
378 | } |
379 | |
380 | static void |
381 | allocate_trough (GtkGizmo *gizmo, |
382 | int width, |
383 | int height, |
384 | int baseline) |
385 | |
386 | { |
387 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (gtk_widget_get_parent (GTK_WIDGET (gizmo))); |
388 | GtkAllocation alloc; |
389 | int progress_width, progress_height; |
390 | gboolean inverted; |
391 | |
392 | inverted = pbar->inverted; |
393 | if (gtk_widget_get_direction (GTK_WIDGET (pbar)) == GTK_TEXT_DIR_RTL) |
394 | { |
395 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
396 | inverted = !inverted; |
397 | } |
398 | |
399 | gtk_widget_measure (widget: pbar->progress_widget, orientation: GTK_ORIENTATION_VERTICAL, for_size: -1, |
400 | minimum: &progress_height, NULL, |
401 | NULL, NULL); |
402 | |
403 | gtk_widget_measure (widget: pbar->progress_widget, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, |
404 | minimum: &progress_width, NULL, |
405 | NULL, NULL); |
406 | |
407 | if (pbar->activity_mode) |
408 | { |
409 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
410 | { |
411 | alloc.width = progress_width + (width - progress_width) / pbar->activity_blocks; |
412 | alloc.x = pbar->activity_pos * (width - alloc.width); |
413 | alloc.y = (height - progress_height) / 2; |
414 | alloc.height = progress_height; |
415 | } |
416 | else |
417 | { |
418 | |
419 | alloc.height = progress_height + (height - progress_height) / pbar->activity_blocks; |
420 | alloc.y = pbar->activity_pos * (height - alloc.height); |
421 | alloc.x = (width - progress_width) / 2; |
422 | alloc.width = progress_width; |
423 | } |
424 | } |
425 | else |
426 | { |
427 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
428 | { |
429 | alloc.width = progress_width + (width - progress_width) * pbar->fraction; |
430 | alloc.height = progress_height; |
431 | alloc.y = (height - progress_height) / 2; |
432 | |
433 | if (!inverted) |
434 | alloc.x = 0; |
435 | else |
436 | alloc.x = width - alloc.width; |
437 | } |
438 | else |
439 | { |
440 | alloc.width = progress_width; |
441 | alloc.height = progress_height + (height - progress_height) * pbar->fraction; |
442 | alloc.x = (width - progress_width) / 2; |
443 | |
444 | if (!inverted) |
445 | alloc.y = 0; |
446 | else |
447 | alloc.y = height - alloc.height; |
448 | } |
449 | } |
450 | |
451 | gtk_widget_size_allocate (widget: pbar->progress_widget, allocation: &alloc, baseline: -1); |
452 | |
453 | } |
454 | |
455 | static void |
456 | gtk_progress_bar_init (GtkProgressBar *pbar) |
457 | { |
458 | pbar->inverted = FALSE; |
459 | pbar->pulse_fraction = 0.1; |
460 | pbar->activity_pos = 0; |
461 | pbar->activity_dir = 1; |
462 | pbar->activity_blocks = 5; |
463 | pbar->ellipsize = PANGO_ELLIPSIZE_NONE; |
464 | pbar->show_text = FALSE; |
465 | |
466 | pbar->text = NULL; |
467 | pbar->fraction = 0.0; |
468 | |
469 | pbar->trough_widget = gtk_gizmo_new_with_role (css_name: "trough" , |
470 | role: GTK_ACCESSIBLE_ROLE_NONE, |
471 | NULL, |
472 | allocate_func: allocate_trough, |
473 | NULL, |
474 | NULL, |
475 | NULL, NULL); |
476 | gtk_widget_set_parent (widget: pbar->trough_widget, GTK_WIDGET (pbar)); |
477 | |
478 | pbar->progress_widget = gtk_gizmo_new_with_role (css_name: "progress" , |
479 | role: GTK_ACCESSIBLE_ROLE_NONE, |
480 | NULL, NULL, NULL, NULL, NULL, NULL); |
481 | gtk_widget_set_parent (widget: pbar->progress_widget, parent: pbar->trough_widget); |
482 | |
483 | /* horizontal is default */ |
484 | pbar->orientation = GTK_ORIENTATION_VERTICAL; /* Just to force an update... */ |
485 | gtk_progress_bar_set_orientation (progress: pbar, orientation: GTK_ORIENTATION_HORIZONTAL); |
486 | gtk_widget_update_orientation (GTK_WIDGET (pbar), orientation: pbar->orientation); |
487 | |
488 | gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: pbar), |
489 | first_property: GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, 1.0, |
490 | GTK_ACCESSIBLE_PROPERTY_VALUE_MIN, 0.0, |
491 | GTK_ACCESSIBLE_PROPERTY_VALUE_NOW, 0.0, |
492 | -1); |
493 | } |
494 | |
495 | static void |
496 | gtk_progress_bar_set_property (GObject *object, |
497 | guint prop_id, |
498 | const GValue *value, |
499 | GParamSpec *pspec) |
500 | { |
501 | GtkProgressBar *pbar; |
502 | |
503 | pbar = GTK_PROGRESS_BAR (object); |
504 | |
505 | switch (prop_id) |
506 | { |
507 | case PROP_ORIENTATION: |
508 | gtk_progress_bar_set_orientation (progress: pbar, orientation: g_value_get_enum (value)); |
509 | break; |
510 | case PROP_INVERTED: |
511 | gtk_progress_bar_set_inverted (pbar, inverted: g_value_get_boolean (value)); |
512 | break; |
513 | case PROP_FRACTION: |
514 | gtk_progress_bar_set_fraction (pbar, fraction: g_value_get_double (value)); |
515 | break; |
516 | case PROP_PULSE_STEP: |
517 | gtk_progress_bar_set_pulse_step (pbar, fraction: g_value_get_double (value)); |
518 | break; |
519 | case PROP_TEXT: |
520 | gtk_progress_bar_set_text (pbar, text: g_value_get_string (value)); |
521 | break; |
522 | case PROP_SHOW_TEXT: |
523 | gtk_progress_bar_set_show_text (pbar, show_text: g_value_get_boolean (value)); |
524 | break; |
525 | case PROP_ELLIPSIZE: |
526 | gtk_progress_bar_set_ellipsize (pbar, mode: g_value_get_enum (value)); |
527 | break; |
528 | default: |
529 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
530 | break; |
531 | } |
532 | } |
533 | |
534 | static void |
535 | gtk_progress_bar_get_property (GObject *object, |
536 | guint prop_id, |
537 | GValue *value, |
538 | GParamSpec *pspec) |
539 | { |
540 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (object); |
541 | |
542 | switch (prop_id) |
543 | { |
544 | case PROP_ORIENTATION: |
545 | g_value_set_enum (value, v_enum: pbar->orientation); |
546 | break; |
547 | case PROP_INVERTED: |
548 | g_value_set_boolean (value, v_boolean: pbar->inverted); |
549 | break; |
550 | case PROP_FRACTION: |
551 | g_value_set_double (value, v_double: pbar->fraction); |
552 | break; |
553 | case PROP_PULSE_STEP: |
554 | g_value_set_double (value, v_double: pbar->pulse_fraction); |
555 | break; |
556 | case PROP_TEXT: |
557 | g_value_set_string (value, v_string: pbar->text); |
558 | break; |
559 | case PROP_SHOW_TEXT: |
560 | g_value_set_boolean (value, v_boolean: pbar->show_text); |
561 | break; |
562 | case PROP_ELLIPSIZE: |
563 | g_value_set_enum (value, v_enum: pbar->ellipsize); |
564 | break; |
565 | default: |
566 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
567 | break; |
568 | } |
569 | } |
570 | |
571 | /** |
572 | * gtk_progress_bar_new: |
573 | * |
574 | * Creates a new `GtkProgressBar`. |
575 | * |
576 | * Returns: a `GtkProgressBar`. |
577 | */ |
578 | GtkWidget* |
579 | gtk_progress_bar_new (void) |
580 | { |
581 | GtkWidget *pbar; |
582 | |
583 | pbar = g_object_new (GTK_TYPE_PROGRESS_BAR, NULL); |
584 | |
585 | return pbar; |
586 | } |
587 | |
588 | static void |
589 | gtk_progress_bar_dispose (GObject *object) |
590 | { |
591 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (object); |
592 | |
593 | if (pbar->activity_mode) |
594 | gtk_progress_bar_act_mode_leave (progress: pbar); |
595 | |
596 | g_clear_pointer (&pbar->label, gtk_widget_unparent); |
597 | g_clear_pointer (&pbar->progress_widget, gtk_widget_unparent); |
598 | g_clear_pointer (&pbar->trough_widget, gtk_widget_unparent); |
599 | |
600 | G_OBJECT_CLASS (gtk_progress_bar_parent_class)->dispose (object); |
601 | } |
602 | |
603 | static void |
604 | gtk_progress_bar_finalize (GObject *object) |
605 | { |
606 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (object); |
607 | |
608 | g_free (mem: pbar->text); |
609 | |
610 | G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object); |
611 | } |
612 | |
613 | static char * |
614 | get_current_text (GtkProgressBar *pbar) |
615 | { |
616 | if (pbar->text) |
617 | return g_strdup (str: pbar->text); |
618 | else |
619 | return g_strdup_printf (C_("progress bar label" , "%.0f %%" ), pbar->fraction * 100.0); |
620 | } |
621 | |
622 | static gboolean |
623 | tick_cb (GtkWidget *widget, |
624 | GdkFrameClock *frame_clock, |
625 | gpointer user_data) |
626 | { |
627 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget); |
628 | gint64 frame_time; |
629 | double iteration, pulse_iterations, current_iterations, fraction; |
630 | |
631 | if (pbar->pulse2 == 0 && pbar->pulse1 == 0) |
632 | return G_SOURCE_CONTINUE; |
633 | |
634 | frame_time = gdk_frame_clock_get_frame_time (frame_clock); |
635 | gtk_progress_tracker_advance_frame (tracker: &pbar->tracker, frame_time); |
636 | |
637 | g_assert (pbar->pulse2 > pbar->pulse1); |
638 | |
639 | pulse_iterations = (pbar->pulse2 - pbar->pulse1) / (double) G_USEC_PER_SEC; |
640 | current_iterations = (frame_time - pbar->pulse1) / (double) G_USEC_PER_SEC; |
641 | |
642 | iteration = gtk_progress_tracker_get_iteration (tracker: &pbar->tracker); |
643 | /* Determine the fraction to move the block from one frame |
644 | * to the next when pulse_fraction is how far the block should |
645 | * move between two calls to gtk_progress_bar_pulse(). |
646 | */ |
647 | fraction = pbar->pulse_fraction * (iteration - pbar->last_iteration) / MAX (pulse_iterations, current_iterations); |
648 | pbar->last_iteration = iteration; |
649 | |
650 | if (current_iterations > 3 * pulse_iterations) |
651 | return G_SOURCE_CONTINUE; |
652 | |
653 | /* advance the block */ |
654 | if (pbar->activity_dir == 0) |
655 | { |
656 | pbar->activity_pos += fraction; |
657 | if (pbar->activity_pos > 1.0) |
658 | { |
659 | pbar->activity_pos = 1.0; |
660 | pbar->activity_dir = 1; |
661 | } |
662 | } |
663 | else |
664 | { |
665 | pbar->activity_pos -= fraction; |
666 | if (pbar->activity_pos <= 0) |
667 | { |
668 | pbar->activity_pos = 0; |
669 | pbar->activity_dir = 0; |
670 | } |
671 | } |
672 | |
673 | update_node_classes (pbar); |
674 | |
675 | gtk_widget_queue_allocate (widget: pbar->trough_widget); |
676 | |
677 | return G_SOURCE_CONTINUE; |
678 | } |
679 | |
680 | static void |
681 | gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar) |
682 | { |
683 | GtkWidget *widget = GTK_WIDGET (pbar); |
684 | gboolean inverted; |
685 | |
686 | gtk_widget_add_css_class (widget: pbar->progress_widget, css_class: "pulse" ); |
687 | gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: pbar), |
688 | first_state: GTK_ACCESSIBLE_STATE_BUSY, TRUE, |
689 | -1); |
690 | |
691 | inverted = pbar->inverted; |
692 | if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) |
693 | { |
694 | if (pbar->orientation == GTK_ORIENTATION_HORIZONTAL) |
695 | inverted = !inverted; |
696 | } |
697 | |
698 | /* calculate start pos */ |
699 | if (!inverted) |
700 | { |
701 | pbar->activity_pos = 0.0; |
702 | pbar->activity_dir = 0; |
703 | } |
704 | else |
705 | { |
706 | pbar->activity_pos = 1.0; |
707 | pbar->activity_dir = 1; |
708 | } |
709 | |
710 | update_node_classes (pbar); |
711 | /* No fixed schedule for pulses, will adapt after calls to update_pulse. Just |
712 | * start the tracker to repeat forever with iterations every second.*/ |
713 | gtk_progress_tracker_start (tracker: &pbar->tracker, G_USEC_PER_SEC, delay: 0, INFINITY); |
714 | pbar->tick_id = gtk_widget_add_tick_callback (widget, callback: tick_cb, NULL, NULL); |
715 | pbar->pulse2 = 0; |
716 | pbar->pulse1 = 0; |
717 | pbar->last_iteration = 0; |
718 | } |
719 | |
720 | static void |
721 | gtk_progress_bar_act_mode_leave (GtkProgressBar *pbar) |
722 | { |
723 | if (pbar->tick_id) |
724 | gtk_widget_remove_tick_callback (GTK_WIDGET (pbar), id: pbar->tick_id); |
725 | pbar->tick_id = 0; |
726 | |
727 | gtk_accessible_update_state (self: GTK_ACCESSIBLE (ptr: pbar), |
728 | first_state: GTK_ACCESSIBLE_STATE_BUSY, FALSE, |
729 | -1); |
730 | gtk_widget_remove_css_class (widget: pbar->progress_widget, css_class: "pulse" ); |
731 | update_node_classes (pbar); |
732 | } |
733 | |
734 | static void |
735 | gtk_progress_bar_set_activity_mode (GtkProgressBar *pbar, |
736 | gboolean activity_mode) |
737 | { |
738 | if (pbar->activity_mode == activity_mode) |
739 | return; |
740 | |
741 | pbar->activity_mode = activity_mode; |
742 | |
743 | if (pbar->activity_mode) |
744 | gtk_progress_bar_act_mode_enter (pbar); |
745 | else |
746 | gtk_progress_bar_act_mode_leave (pbar); |
747 | |
748 | gtk_widget_queue_resize (GTK_WIDGET (pbar)); |
749 | } |
750 | |
751 | /** |
752 | * gtk_progress_bar_set_fraction: (attributes org.gtk.Method.set_property=fraction) |
753 | * @pbar: a `GtkProgressBar` |
754 | * @fraction: fraction of the task that’s been completed |
755 | * |
756 | * Causes the progress bar to “fill in” the given fraction |
757 | * of the bar. |
758 | * |
759 | * The fraction should be between 0.0 and 1.0, inclusive. |
760 | */ |
761 | void |
762 | gtk_progress_bar_set_fraction (GtkProgressBar *pbar, |
763 | double fraction) |
764 | { |
765 | char *text = NULL; |
766 | |
767 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
768 | |
769 | pbar->fraction = CLAMP (fraction, 0.0, 1.0); |
770 | |
771 | if (pbar->label) |
772 | { |
773 | text = get_current_text (pbar); |
774 | gtk_label_set_label (GTK_LABEL (pbar->label), str: text); |
775 | } |
776 | |
777 | gtk_progress_bar_set_activity_mode (pbar, FALSE); |
778 | gtk_widget_queue_allocate (widget: pbar->trough_widget); |
779 | update_fraction_classes (pbar); |
780 | |
781 | gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: pbar), |
782 | first_property: GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, 1.0, |
783 | GTK_ACCESSIBLE_PROPERTY_VALUE_MIN, 0.0, |
784 | GTK_ACCESSIBLE_PROPERTY_VALUE_NOW, fraction, |
785 | -1); |
786 | |
787 | if (text != NULL) |
788 | { |
789 | gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: pbar), |
790 | first_property: GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT, text, |
791 | -1); |
792 | } |
793 | else |
794 | { |
795 | gtk_accessible_reset_property (self: GTK_ACCESSIBLE (ptr: pbar), property: GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT); |
796 | } |
797 | |
798 | g_free (mem: text); |
799 | |
800 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_FRACTION]); |
801 | } |
802 | |
803 | static void |
804 | gtk_progress_bar_update_pulse (GtkProgressBar *pbar) |
805 | { |
806 | gint64 pulse_time = g_get_monotonic_time (); |
807 | |
808 | if (pbar->pulse2 == pulse_time) |
809 | return; |
810 | |
811 | pbar->pulse1 = pbar->pulse2; |
812 | pbar->pulse2 = pulse_time; |
813 | } |
814 | |
815 | /** |
816 | * gtk_progress_bar_pulse: |
817 | * @pbar: a `GtkProgressBar` |
818 | * |
819 | * Indicates that some progress has been made, but you don’t know how much. |
820 | * |
821 | * Causes the progress bar to enter “activity mode,” where a block |
822 | * bounces back and forth. Each call to [method@Gtk.ProgressBar.pulse] |
823 | * causes the block to move by a little bit (the amount of movement |
824 | * per pulse is determined by [method@Gtk.ProgressBar.set_pulse_step]). |
825 | */ |
826 | void |
827 | gtk_progress_bar_pulse (GtkProgressBar *pbar) |
828 | { |
829 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
830 | |
831 | gtk_progress_bar_set_activity_mode (pbar, TRUE); |
832 | gtk_progress_bar_update_pulse (pbar); |
833 | } |
834 | |
835 | /** |
836 | * gtk_progress_bar_set_text: (attributes org.gtk.Method.set_property=text) |
837 | * @pbar: a `GtkProgressBar` |
838 | * @text: (nullable): a UTF-8 string |
839 | * |
840 | * Causes the given @text to appear next to the progress bar. |
841 | * |
842 | * If @text is %NULL and [property@Gtk.ProgressBar:show-text] is %TRUE, |
843 | * the current value of [property@Gtk.ProgressBar:fraction] will be displayed |
844 | * as a percentage. |
845 | * |
846 | * If @text is non-%NULL and [property@Gtk.ProgressBar:show-text] is %TRUE, |
847 | * the text will be displayed. In this case, it will not display the progress |
848 | * percentage. If @text is the empty string, the progress bar will still |
849 | * be styled and sized suitably for containing text, as long as |
850 | * [property@Gtk.ProgressBar:show-text] is %TRUE. |
851 | */ |
852 | void |
853 | gtk_progress_bar_set_text (GtkProgressBar *pbar, |
854 | const char *text) |
855 | { |
856 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
857 | |
858 | /* Don't notify again if nothing's changed. */ |
859 | if (g_strcmp0 (str1: pbar->text, str2: text) == 0) |
860 | return; |
861 | |
862 | g_free (mem: pbar->text); |
863 | pbar->text = g_strdup (str: text); |
864 | |
865 | if (pbar->label) |
866 | gtk_label_set_label (GTK_LABEL (pbar->label), str: text); |
867 | |
868 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_TEXT]); |
869 | } |
870 | |
871 | /** |
872 | * gtk_progress_bar_set_show_text: (attributes org.gtk.Method.set_property=show-text) |
873 | * @pbar: a `GtkProgressBar` |
874 | * @show_text: whether to show text |
875 | * |
876 | * Sets whether the progress bar will show text next to the bar. |
877 | * |
878 | * The shown text is either the value of the [property@Gtk.ProgressBar:text] |
879 | * property or, if that is %NULL, the [property@Gtk.ProgressBar:fraction] value, |
880 | * as a percentage. |
881 | * |
882 | * To make a progress bar that is styled and sized suitably for containing |
883 | * text (even if the actual text is blank), set [property@Gtk.ProgressBar:show-text] |
884 | * to %TRUE and [property@Gtk.ProgressBar:text] to the empty string (not %NULL). |
885 | */ |
886 | void |
887 | gtk_progress_bar_set_show_text (GtkProgressBar *pbar, |
888 | gboolean show_text) |
889 | { |
890 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
891 | |
892 | show_text = !!show_text; |
893 | |
894 | if (pbar->show_text == show_text) |
895 | return; |
896 | |
897 | pbar->show_text = show_text; |
898 | |
899 | if (show_text) |
900 | { |
901 | char *text = get_current_text (pbar); |
902 | |
903 | pbar->label = g_object_new (GTK_TYPE_LABEL, |
904 | first_property_name: "accessible-role" , GTK_ACCESSIBLE_ROLE_NONE, |
905 | "css-name" , "text" , |
906 | "label" , text, |
907 | "ellipsize" , pbar->ellipsize, |
908 | NULL); |
909 | gtk_widget_insert_after (widget: pbar->label, GTK_WIDGET (pbar), NULL); |
910 | |
911 | g_free (mem: text); |
912 | } |
913 | else |
914 | { |
915 | g_clear_pointer (&pbar->label, gtk_widget_unparent); |
916 | } |
917 | |
918 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_SHOW_TEXT]); |
919 | } |
920 | |
921 | /** |
922 | * gtk_progress_bar_get_show_text: (attributes org.gtk.Method.get_property=show-text) |
923 | * @pbar: a `GtkProgressBar` |
924 | * |
925 | * Returns whether the `GtkProgressBar` shows text. |
926 | * |
927 | * See [method@Gtk.ProgressBar.set_show_text]. |
928 | * |
929 | * Returns: %TRUE if text is shown in the progress bar |
930 | */ |
931 | gboolean |
932 | gtk_progress_bar_get_show_text (GtkProgressBar *pbar) |
933 | { |
934 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), FALSE); |
935 | |
936 | return pbar->show_text; |
937 | } |
938 | |
939 | /** |
940 | * gtk_progress_bar_set_pulse_step: (attributes org.gtk.Method.set_property=pulse-step) |
941 | * @pbar: a `GtkProgressBar` |
942 | * @fraction: fraction between 0.0 and 1.0 |
943 | * |
944 | * Sets the fraction of total progress bar length to move the |
945 | * bouncing block. |
946 | * |
947 | * The bouncing block is moved when [method@Gtk.ProgressBar.pulse] |
948 | * is called. |
949 | */ |
950 | void |
951 | gtk_progress_bar_set_pulse_step (GtkProgressBar *pbar, |
952 | double fraction) |
953 | { |
954 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
955 | |
956 | pbar->pulse_fraction = fraction; |
957 | |
958 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_PULSE_STEP]); |
959 | } |
960 | |
961 | static void |
962 | gtk_progress_bar_direction_changed (GtkWidget *widget, |
963 | GtkTextDirection previous_dir) |
964 | { |
965 | GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget); |
966 | |
967 | update_node_classes (pbar); |
968 | |
969 | GTK_WIDGET_CLASS (gtk_progress_bar_parent_class)->direction_changed (widget, previous_dir); |
970 | } |
971 | |
972 | static void |
973 | gtk_progress_bar_set_orientation (GtkProgressBar *pbar, |
974 | GtkOrientation orientation) |
975 | { |
976 | GtkBoxLayout *layout; |
977 | |
978 | if (pbar->orientation == orientation) |
979 | return; |
980 | |
981 | pbar->orientation = orientation; |
982 | |
983 | if (orientation == GTK_ORIENTATION_HORIZONTAL) |
984 | { |
985 | gtk_widget_set_vexpand (widget: pbar->trough_widget, FALSE); |
986 | gtk_widget_set_hexpand (widget: pbar->trough_widget, TRUE); |
987 | gtk_widget_set_halign (widget: pbar->trough_widget, align: GTK_ALIGN_FILL); |
988 | gtk_widget_set_valign (widget: pbar->trough_widget, align: GTK_ALIGN_CENTER); |
989 | } |
990 | else |
991 | { |
992 | gtk_widget_set_vexpand (widget: pbar->trough_widget, TRUE); |
993 | gtk_widget_set_hexpand (widget: pbar->trough_widget, FALSE); |
994 | gtk_widget_set_halign (widget: pbar->trough_widget, align: GTK_ALIGN_CENTER); |
995 | gtk_widget_set_valign (widget: pbar->trough_widget, align: GTK_ALIGN_FILL); |
996 | } |
997 | |
998 | gtk_widget_update_orientation (GTK_WIDGET (pbar), orientation: pbar->orientation); |
999 | update_node_classes (pbar); |
1000 | |
1001 | layout = GTK_BOX_LAYOUT (ptr: gtk_widget_get_layout_manager (GTK_WIDGET (pbar))); |
1002 | gtk_orientable_set_orientation (GTK_ORIENTABLE (layout), orientation: GTK_ORIENTATION_VERTICAL); |
1003 | |
1004 | g_object_notify (G_OBJECT (pbar), property_name: "orientation" ); |
1005 | } |
1006 | |
1007 | /** |
1008 | * gtk_progress_bar_set_inverted: (attributes org.gtk.Method.set_property=inverted) |
1009 | * @pbar: a `GtkProgressBar` |
1010 | * @inverted: %TRUE to invert the progress bar |
1011 | * |
1012 | * Sets whether the progress bar is inverted. |
1013 | * |
1014 | * Progress bars normally grow from top to bottom or left to right. |
1015 | * Inverted progress bars grow in the opposite direction. |
1016 | */ |
1017 | void |
1018 | gtk_progress_bar_set_inverted (GtkProgressBar *pbar, |
1019 | gboolean inverted) |
1020 | { |
1021 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
1022 | |
1023 | if (pbar->inverted == inverted) |
1024 | return; |
1025 | |
1026 | pbar->inverted = inverted; |
1027 | |
1028 | gtk_widget_queue_allocate (widget: pbar->trough_widget); |
1029 | update_node_classes (pbar); |
1030 | |
1031 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_INVERTED]); |
1032 | } |
1033 | |
1034 | /** |
1035 | * gtk_progress_bar_get_text: (attributes org.gtk.Method.get_property=text) |
1036 | * @pbar: a `GtkProgressBar` |
1037 | * |
1038 | * Retrieves the text that is displayed with the progress bar. |
1039 | * |
1040 | * The return value is a reference to the text, not a copy of it, |
1041 | * so will become invalid if you change the text in the progress bar. |
1042 | * |
1043 | * Returns: (nullable): the text |
1044 | */ |
1045 | const char * |
1046 | gtk_progress_bar_get_text (GtkProgressBar *pbar) |
1047 | { |
1048 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), NULL); |
1049 | |
1050 | return pbar->text; |
1051 | } |
1052 | |
1053 | /** |
1054 | * gtk_progress_bar_get_fraction: (attributes org.gtk.Method.get_property=fraction) |
1055 | * @pbar: a `GtkProgressBar` |
1056 | * |
1057 | * Returns the current fraction of the task that’s been completed. |
1058 | * |
1059 | * Returns: a fraction from 0.0 to 1.0 |
1060 | */ |
1061 | double |
1062 | gtk_progress_bar_get_fraction (GtkProgressBar *pbar) |
1063 | { |
1064 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0); |
1065 | |
1066 | return pbar->fraction; |
1067 | } |
1068 | |
1069 | /** |
1070 | * gtk_progress_bar_get_pulse_step: (attributes org.gtk.Method.get_property=pulse-step) |
1071 | * @pbar: a `GtkProgressBar` |
1072 | * |
1073 | * Retrieves the pulse step. |
1074 | * |
1075 | * See [method@Gtk.ProgressBar.set_pulse_step]. |
1076 | * |
1077 | * Returns: a fraction from 0.0 to 1.0 |
1078 | */ |
1079 | double |
1080 | gtk_progress_bar_get_pulse_step (GtkProgressBar *pbar) |
1081 | { |
1082 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0); |
1083 | |
1084 | return pbar->pulse_fraction; |
1085 | } |
1086 | |
1087 | /** |
1088 | * gtk_progress_bar_get_inverted: (attributes org.gtk.Method.get_property=inverted) |
1089 | * @pbar: a `GtkProgressBar` |
1090 | * |
1091 | * Returns whether the progress bar is inverted. |
1092 | * |
1093 | * Returns: %TRUE if the progress bar is inverted |
1094 | */ |
1095 | gboolean |
1096 | gtk_progress_bar_get_inverted (GtkProgressBar *pbar) |
1097 | { |
1098 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), FALSE); |
1099 | |
1100 | return pbar->inverted; |
1101 | } |
1102 | |
1103 | /** |
1104 | * gtk_progress_bar_set_ellipsize: (attributes org.gtk.Method.set_property=ellipsize) |
1105 | * @pbar: a `GtkProgressBar` |
1106 | * @mode: a `PangoEllipsizeMode` |
1107 | * |
1108 | * Sets the mode used to ellipsize the text. |
1109 | * |
1110 | * The text is ellipsized if there is not enough space |
1111 | * to render the entire string. |
1112 | */ |
1113 | void |
1114 | gtk_progress_bar_set_ellipsize (GtkProgressBar *pbar, |
1115 | PangoEllipsizeMode mode) |
1116 | { |
1117 | g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); |
1118 | g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && |
1119 | mode <= PANGO_ELLIPSIZE_END); |
1120 | |
1121 | if ((PangoEllipsizeMode)pbar->ellipsize == mode) |
1122 | return; |
1123 | |
1124 | pbar->ellipsize = mode; |
1125 | |
1126 | if (pbar->label) |
1127 | gtk_label_set_ellipsize (GTK_LABEL (pbar->label), mode); |
1128 | |
1129 | g_object_notify_by_pspec (G_OBJECT (pbar), pspec: progress_props[PROP_ELLIPSIZE]); |
1130 | } |
1131 | |
1132 | /** |
1133 | * gtk_progress_bar_get_ellipsize: (attributes org.gtk.Method.get_property=ellipsize) |
1134 | * @pbar: a `GtkProgressBar` |
1135 | * |
1136 | * Returns the ellipsizing position of the progress bar. |
1137 | * |
1138 | * See [method@Gtk.ProgressBar.set_ellipsize]. |
1139 | * |
1140 | * Returns: `PangoEllipsizeMode` |
1141 | */ |
1142 | PangoEllipsizeMode |
1143 | gtk_progress_bar_get_ellipsize (GtkProgressBar *pbar) |
1144 | { |
1145 | g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), PANGO_ELLIPSIZE_NONE); |
1146 | |
1147 | return pbar->ellipsize; |
1148 | } |
1149 | |