Merge lp:~macslow/notify-osd/two-slots into lp:notify-osd/trunk

Proposed by Mirco Müller
Status: Merged
Merged at revision: not available
Proposed branch: lp:~macslow/notify-osd/two-slots
Merge into: lp:notify-osd/trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~macslow/notify-osd/two-slots
Reviewer Review Type Date Requested Status
David Barth (community) Approve
Review via email: mp+11168@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Mirco Müller (macslow) wrote :

This branch introduces the "two slots"-concept for holding the two possible notification-bubbles (one for async./feedback notifications, one for sync./normal notifications). It extends the API of class Stack a bit (with unit-tests for the newly introduced calls) and works for both gravity cases (here still called Placement). It also fixes LP: #371422. A major culprit that still needs some fixing/clean up love is display.c, but it better now with this branch already.

Revision history for this message
David Barth (dbarth) wrote :

The code is sane. The unit tests give some extra safety in case of further refactoring.

On the approach, we've discussed the merits of distinguishing between:
- placement options, knowing that we not support all gravity options, but maybe different placement strategies for the same "gravity"
- slot allocations optimizations, like avoid "gaps" between bubbles at all costs, vs, accepting gaps but having a strict mapping between notification types (sync/async) and slot positioning

The code can go in as is. You can optionally refine these 2 last bits later, time permitting before the UIF.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/bubble.c'
2--- src/bubble.c 2009-08-26 11:17:55 +0000
3+++ src/bubble.c 2009-08-27 09:52:34 +0000
4@@ -83,7 +83,6 @@
5 gboolean icon_only;
6 gint future_height;
7 gboolean prevent_fade;
8- BubblePlacement placement;
9
10 // these will be replaced by notification_t* later on
11 GString* title;
12@@ -2251,7 +2250,6 @@
13 this->priv->tile_body = NULL;
14 this->priv->tile_indicator = NULL;
15 this->priv->prevent_fade = FALSE;
16- this->priv->placement = PLACEMENT_NEW;
17
18 update_input_shape (window, 1, 1);
19
20@@ -3649,12 +3647,3 @@
21 bubble_start_timer (self);
22 bubble_start_timer (other);
23 }
24-
25-BubblePlacement
26-bubble_get_placement (Bubble* self)
27-{
28- if (!self || !IS_BUBBLE (self))
29- return PLACEMENT_NONE;
30-
31- return GET_PRIVATE (self)->placement;
32-}
33
34=== modified file 'src/bubble.h'
35--- src/bubble.h 2009-08-26 09:35:02 +0000
36+++ src/bubble.h 2009-08-27 09:52:34 +0000
37@@ -48,13 +48,6 @@
38 LAYOUT_TITLE_ONLY
39 } BubbleLayout;
40
41-typedef enum
42-{
43- PLACEMENT_NONE = 0,
44- PLACEMENT_OLD, // top-right of screen
45- PLACEMENT_NEW // vertically centered at right of screen
46-} BubblePlacement;
47-
48 G_BEGIN_DECLS
49
50 #define BUBBLE_TYPE (bubble_get_type ())
51@@ -267,9 +260,6 @@
52 const char *process_name,
53 gchar **actions);
54
55-BubblePlacement
56-bubble_get_placement (Bubble* self);
57-
58 G_END_DECLS
59
60 #endif // __BUBBLE_H
61
62=== modified file 'src/display.c'
63--- src/display.c 2009-08-26 09:35:02 +0000
64+++ src/display.c 2009-09-03 08:39:04 +0000
65@@ -71,42 +71,122 @@
66 return y1 == y2;
67 }
68
69-
70 static void
71 stack_display_position_sync_bubble (Stack *self, Bubble *bubble)
72 {
73 Defaults* d = self->defaults;
74 gint y = 0;
75 gint x = 0;
76- Bubble* async;
77
78 defaults_get_top_corner (d, &x, &y);
79
80 // TODO: with multi-head, in focus follow mode, there may be enough
81 // space left on the top monitor
82
83- switch (bubble_get_placement (bubble))
84+ switch (stack_get_placement (self))
85 {
86 case PLACEMENT_OLD:
87- async = stack_find_bubble_on_display (self);
88- if (async != NULL)
89- {
90- d = self->defaults;
91- y += bubble_get_future_height (async);
92- y += EM2PIXELS (defaults_get_bubble_vert_gap (d), d) -
93- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
94+ // see if we're call at the wrong moment, when both
95+ // slots are occupied by bubbles
96+ if (!stack_is_slot_vacant (self, SLOT_TOP) &&
97+ !stack_is_slot_vacant (self, SLOT_BOTTOM))
98+ {
99+ g_warning ("%s(): Both slots taken!\n",
100+ G_STRFUNC);
101+ }
102+ else
103+ {
104+ // first check if we can place the sync. bubble
105+ // in the top slot and the bottom slot is still
106+ // vacant, this is to avoid the "gap" between
107+ // bottom slot and panel
108+ if (stack_is_slot_vacant (self, SLOT_TOP) &&
109+ stack_is_slot_vacant (self, SLOT_BOTTOM))
110+ {
111+ stack_get_slot_position (self,
112+ SLOT_TOP,
113+ bubble_get_height (bubble),
114+ &x,
115+ &y);
116+ if (x == -1 || y == -1)
117+ g_warning ("%s(): No coords!\n",
118+ G_STRFUNC);
119+ else
120+ stack_allocate_slot (self,
121+ bubble,
122+ SLOT_TOP);
123+ }
124+ // next check if top is occupied and bottom is
125+ // still vacant, then place sync. bubble in
126+ // bottom slot
127+ else if (!stack_is_slot_vacant (self,
128+ SLOT_TOP) &&
129+ stack_is_slot_vacant (self,
130+ SLOT_BOTTOM))
131+ {
132+ stack_get_slot_position (self,
133+ SLOT_BOTTOM,
134+ bubble_get_height (bubble),
135+ &x,
136+ &y);
137+ if (x == -1 || y == -1)
138+ g_warning ("%s(): No coords!\n",
139+ G_STRFUNC);
140+ else
141+ {
142+ stack_allocate_slot (
143+ self,
144+ bubble,
145+ SLOT_BOTTOM);
146+
147+ bubble_sync_with (
148+ bubble,
149+ self->slots[SLOT_TOP]);
150+ }
151+ }
152+ // this case, top vacant, bottom occupied,
153+ // should never happen for the old placement,
154+ // we want to avoid the "gap" between the bottom
155+ // bubble and the panel
156+ else if (stack_is_slot_vacant (self,
157+ SLOT_TOP) &&
158+ !stack_is_slot_vacant (self,
159+ SLOT_BOTTOM))
160+ {
161+ g_warning ("%s(): Gap, gap, gap!!!\n",
162+ G_STRFUNC);
163+ }
164 }
165 break;
166
167 case PLACEMENT_NEW:
168- y += defaults_get_desktop_height (d) / 2 -
169- EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
170- bubble_get_height (bubble) +
171- EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
172+ // see if reserved top slot for sync. bubble is really
173+ // vacant
174+ if (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED)
175+ {
176+ g_warning ("%s(): Top slot taken!\n",
177+ G_STRFUNC);
178+ }
179+ // if not just put sync. bubble in top slot
180+ else
181+ {
182+ stack_get_slot_position (self,
183+ SLOT_TOP,
184+ bubble_get_height (bubble),
185+ &x,
186+ &y);
187+ if (x == -1 || y == -1)
188+ g_warning ("%s(): No slot-coords!\n",
189+ G_STRFUNC);
190+ else
191+ stack_allocate_slot (self,
192+ bubble,
193+ SLOT_TOP);
194+ }
195 break;
196
197 default:
198- g_warning ("Unhandled bubble placement!\n");
199+ g_warning ("Unhandled placement!\n");
200 break;
201 }
202
203@@ -114,6 +194,7 @@
204 }
205
206 static void
207+
208 stack_display_sync_bubble (Stack *self, Bubble *bubble)
209 {
210 g_return_if_fail (IS_STACK (self));
211@@ -241,41 +322,124 @@
212
213 d = self->defaults;
214
215- switch (bubble_get_placement (bubble))
216+ switch (stack_get_placement (self))
217 {
218 case PLACEMENT_OLD:
219- if (sync_bubble != NULL && bubble_is_visible (sync_bubble))
220- {
221- d = self->defaults;
222- y += bubble_get_height (sync_bubble);
223- y += EM2PIXELS (defaults_get_bubble_vert_gap (d), d)
224- - 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
225+ if (!stack_is_slot_vacant (self, SLOT_TOP) &&
226+ !stack_is_slot_vacant (self, SLOT_BOTTOM))
227+ {
228+ g_warning ("%s(): Both slots taken!\n",
229+ G_STRFUNC);
230+ }
231+ else
232+ {
233+ if (stack_is_slot_vacant (self, SLOT_TOP))
234+ {
235+ stack_get_slot_position (self,
236+ SLOT_TOP,
237+ bubble_get_height (bubble),
238+ &x,
239+ &y);
240+ if (x == -1 || y == -1)
241+ g_warning ("%s(): No coords!\n",
242+ G_STRFUNC);
243+ else
244+ stack_allocate_slot (self,
245+ bubble,
246+ SLOT_TOP);
247+ }
248+ else if (stack_is_slot_vacant (self,
249+ SLOT_BOTTOM))
250+ {
251+ stack_get_slot_position (self,
252+ SLOT_BOTTOM,
253+ bubble_get_height (bubble),
254+ &x,
255+ &y);
256+ if (x == -1 || y == -1)
257+ g_warning ("%s(): No coords!\n",
258+ G_STRFUNC);
259+ else
260+ stack_allocate_slot (self,
261+ bubble,
262+ SLOT_BOTTOM);
263+ }
264+ }
265
266- // synchronize the sync bubble with the timeout of the bubble at
267- // the bottom
268- if (stack_is_at_top_corner (self, sync_bubble))
269- bubble_sync_with (sync_bubble, bubble);
270+ if (sync_bubble != NULL &&
271+ bubble_is_visible (sync_bubble) &&
272+ sync_bubble == self->slots[SLOT_TOP])
273+ {
274+ // synchronize the sync bubble with the timeout
275+ // of the bubble at the bottom
276+ bubble_sync_with (sync_bubble, bubble);
277 }
278 break;
279
280 case PLACEMENT_NEW:
281- if (sync_bubble != NULL && bubble_is_visible (sync_bubble))
282+ // with the new placement sync. bubbles are always to be
283+ // placed in the top slot (above the "half-line")
284+ if (bubble_is_synchronous (bubble))
285 {
286- y += defaults_get_desktop_height (d) / 2 -
287- EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
288- bubble_get_height (sync_bubble) +
289- EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
290+ // verify that the top slot is really vacant
291+ if (stack_is_slot_vacant (self, SLOT_TOP))
292+ {
293+ stack_get_slot_position (self,
294+ SLOT_TOP,
295+ bubble_get_height (bubble),
296+ &x,
297+ &y);
298+ if (x == -1 || y == -1)
299+ g_warning ("%s(): No coords!\n",
300+ G_STRFUNC);
301+ else
302+ stack_allocate_slot (self,
303+ bubble,
304+ SLOT_TOP);
305+ }
306+ // otherwise there's still an error in the
307+ // layout- and queue-logic
308+ else
309+ {
310+ g_warning ("%s(): Can't put sync. "
311+ "bubble in top slot!\n",
312+ G_STRFUNC);
313+ }
314 }
315+ // an async. bubble is always meant to be put in the
316+ // bottom slot (below the "half-line")
317 else
318 {
319- y += defaults_get_desktop_height (d) / 2 +
320- EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
321- EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
322+ // verify that the bottom slot is really vacant
323+ if (stack_is_slot_vacant (self, SLOT_BOTTOM))
324+ {
325+ stack_get_slot_position (self,
326+ SLOT_BOTTOM,
327+ bubble_get_height (bubble),
328+ &x,
329+ &y);
330+ if (x == -1 || y == -1)
331+ g_warning ("%s(): No coords!\n",
332+ G_STRFUNC);
333+ else
334+ stack_allocate_slot (
335+ self,
336+ bubble,
337+ SLOT_BOTTOM);
338+ }
339+ // otherwise there's still an error in the
340+ // layout- and queue-logic
341+ else
342+ {
343+ g_warning ("%s(): Can't put async. "
344+ "bubble in bottom slot!\n",
345+ G_STRFUNC);
346+ }
347 }
348 break;
349
350 default:
351- g_warning ("Unhandled bubble placement!\n");
352+ g_warning ("Unhandled placement!\n");
353 break;
354 }
355
356
357=== modified file 'src/stack.c'
358--- src/stack.c 2009-08-26 11:17:55 +0000
359+++ src/stack.c 2009-09-03 08:39:04 +0000
360@@ -319,10 +319,13 @@
361 if (!this)
362 return NULL;
363
364- this->defaults = defaults;
365- this->observer = observer;
366- this->list = NULL;
367- this->next_id = 1;
368+ this->defaults = defaults;
369+ this->observer = observer;
370+ this->list = NULL;
371+ this->next_id = 1;
372+ this->placement = PLACEMENT_OLD;
373+ this->slots[SLOT_TOP] = NULL;
374+ this->slots[SLOT_BOTTOM] = NULL;
375
376 /* hook up handler to act on changes of defaults/settings */
377 g_signal_connect (G_OBJECT (defaults),
378@@ -354,6 +357,9 @@
379
380 if (n != NULL)
381 {
382+ if (IS_BUBBLE (n))
383+ stack_free_slot (stack, BUBBLE (n))
384+
385 if (IS_BUBBLE (n)
386 && bubble_is_synchronous (BUBBLE (n)))
387 {
388@@ -736,7 +742,6 @@
389 if (bubble_is_synchronous (bubble))
390 {
391 stack_display_sync_bubble (self, bubble);
392-
393 } else {
394 stack_push_bubble (self, bubble);
395
396@@ -750,9 +755,10 @@
397 /* make sure the sync. bubble is positioned correctly
398 even for the append case
399 */
400- if (sync_bubble != NULL
401- && bubble_is_visible (sync_bubble))
402- stack_display_position_sync_bubble (self, sync_bubble);
403+ // no longer needed since we have the two-slots mechanism now
404+ //if (sync_bubble != NULL
405+ // && bubble_is_visible (sync_bubble))
406+ // stack_display_position_sync_bubble (self, sync_bubble);
407
408 /* update the layout of the stack;
409 * this will also open the new bubble */
410@@ -829,3 +835,155 @@
411
412 return TRUE;
413 }
414+
415+Placement
416+stack_get_placement (Stack* self)
417+{
418+ if (!self || !IS_STACK (self))
419+ return PLACEMENT_NONE;
420+
421+ return self->placement;
422+}
423+
424+gboolean
425+stack_is_slot_vacant (Stack* self,
426+ Slot slot)
427+{
428+ // sanity checks
429+ if (!self || !IS_STACK (self))
430+ return FALSE;
431+
432+ if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
433+ return FALSE;
434+
435+ return self->slots[slot] == NULL ? VACANT : OCCUPIED;
436+}
437+
438+// return values of -1 for x and y indicate an error by the caller
439+void
440+stack_get_slot_position (Stack* self,
441+ Slot slot,
442+ gint bubble_height,
443+ gint* x,
444+ gint* y)
445+{
446+ // sanity checks
447+ if (!x && !y)
448+ return;
449+
450+ if (!self || !IS_STACK (self))
451+ {
452+ *x = -1;
453+ *y = -1;
454+ return;
455+ }
456+
457+ if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
458+ {
459+ *x = -1;
460+ *y = -1;
461+ return;
462+ }
463+
464+ // initialize x and y
465+ defaults_get_top_corner (self->defaults, x, y);
466+
467+ // differentiate returned top-left corner for top and bottom slot
468+ // depending on the placement
469+ switch (stack_get_placement (self))
470+ {
471+ Defaults* d;
472+
473+ case PLACEMENT_NEW:
474+ d = self->defaults;
475+
476+ // the position for the sync./feedback bubble
477+ if (slot == SLOT_TOP)
478+ *y += defaults_get_desktop_height (d) / 2 -
479+ EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
480+ bubble_height +
481+ EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
482+ // the position for the async. bubble
483+ else if (slot == SLOT_BOTTOM)
484+ *y += defaults_get_desktop_height (d) / 2 +
485+ EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) -
486+ EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
487+ break;
488+
489+ case PLACEMENT_OLD:
490+ d = self->defaults;
491+
492+ // there's nothing to do for slot == SLOT_TOP as we
493+ // already have correct x and y from the call to
494+ // defaults_get_top_corner() earlier
495+
496+ // this needs to look at the height of the bubble in the
497+ // top slot
498+ if (slot == SLOT_BOTTOM)
499+ {
500+ g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED);
501+ *y += bubble_get_height (self->slots[SLOT_TOP]) +
502+ EM2PIXELS (defaults_get_bubble_vert_gap (d), d) -
503+ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d);
504+
505+ }
506+ break;
507+
508+ default:
509+ g_warning ("Unhandled placement!\n");
510+ break;
511+ }
512+}
513+
514+// call this _before_ the fade-in animation of the bubble starts
515+gboolean
516+stack_allocate_slot (Stack* self,
517+ Bubble* bubble,
518+ Slot slot)
519+{
520+ // sanity checks
521+ if (!self || !IS_STACK (self))
522+ return FALSE;
523+
524+ if (!bubble || !IS_BUBBLE (bubble))
525+ return FALSE;
526+
527+ if (slot != SLOT_TOP && slot != SLOT_BOTTOM)
528+ return FALSE;
529+
530+ if (stack_is_slot_vacant (self, slot))
531+ self->slots[slot] = BUBBLE (g_object_ref ((gpointer) bubble));
532+ else
533+ return FALSE;
534+
535+ return TRUE;
536+}
537+
538+// call this _after_ the fade-out animation of the bubble is finished
539+gboolean
540+stack_free_slot (Stack* self,
541+ Bubble* bubble)
542+{
543+ // sanity checks
544+ if (!self || !IS_STACK (self))
545+ return FALSE;
546+
547+ if (!bubble || !IS_BUBBLE (bubble))
548+ return FALSE;
549+
550+ // check top and bottom slots for bubble pointer equality
551+ if (bubble == self->slots[SLOT_TOP])
552+ {
553+ g_object_unref (self->slots[SLOT_TOP]);
554+ self->slots[SLOT_TOP] = NULL;
555+ }
556+ else if (bubble == self->slots[SLOT_BOTTOM])
557+ {
558+ g_object_unref (self->slots[SLOT_BOTTOM]);
559+ self->slots[SLOT_BOTTOM] = NULL;
560+ }
561+ else
562+ return FALSE;
563+
564+ return TRUE;
565+}
566
567=== modified file 'src/stack.h'
568--- src/stack.h 2009-08-21 10:43:50 +0000
569+++ src/stack.h 2009-09-03 08:39:04 +0000
570@@ -48,9 +48,25 @@
571
572 #define MAX_STACK_SIZE 50
573
574+#define VACANT TRUE
575+#define OCCUPIED FALSE
576+
577 typedef struct _Stack Stack;
578 typedef struct _StackClass StackClass;
579
580+typedef enum
581+{
582+ SLOT_TOP = 0,
583+ SLOT_BOTTOM
584+} Slot;
585+
586+typedef enum
587+{
588+ PLACEMENT_NONE = 0,
589+ PLACEMENT_OLD, // top-right of screen
590+ PLACEMENT_NEW // vertically centered at right of screen
591+} Placement;
592+
593 /* instance structure */
594 struct _Stack
595 {
596@@ -61,7 +77,8 @@
597 Observer* observer;
598 GList* list;
599 guint next_id;
600-
601+ Bubble* slots[2]; // NULL: vacant, non-NULL: occupied
602+ Placement placement;
603 };
604
605 /* class structure */
606@@ -115,6 +132,29 @@
607 gchar** out_version,
608 gchar** out_spec_ver);
609
610+Placement
611+stack_get_placement (Stack* self);
612+
613+gboolean
614+stack_is_slot_vacant (Stack* self,
615+ Slot slot);
616+
617+void
618+stack_get_slot_position (Stack* self,
619+ Slot slot,
620+ gint bubble_height,
621+ gint* x,
622+ gint* y);
623+
624+gboolean
625+stack_allocate_slot (Stack* self,
626+ Bubble* bubble,
627+ Slot slot);
628+
629+gboolean
630+stack_free_slot (Stack* self,
631+ Bubble* bubble);
632+
633 G_END_DECLS
634
635 #endif /* __STACK_H */
636
637=== modified file 'tests/test-stack.c'
638--- tests/test-stack.c 2009-08-04 17:34:48 +0000
639+++ tests/test-stack.c 2009-09-03 08:39:04 +0000
640@@ -79,6 +79,132 @@
641 g_object_unref (G_OBJECT (stack));
642 }
643
644+static void
645+test_stack_placement ()
646+{
647+ Stack* stack = NULL;
648+ Defaults* defaults = defaults_new ();
649+ Observer* observer = observer_new ();
650+
651+ stack = stack_new (defaults, observer);
652+
653+ // upon creation the placement method should not be unset
654+ g_assert_cmpint (stack_get_placement (stack), !=, PLACEMENT_NONE);
655+
656+ // currently the default value should be the new placement method
657+ g_assert_cmpint (stack_get_placement (stack), ==, PLACEMENT_OLD);
658+
659+ // check if we can pass "crap" to the call without causing a crash
660+ g_assert_cmpint (stack_get_placement (NULL), ==, PLACEMENT_NONE);
661+
662+ g_object_unref (G_OBJECT (stack));
663+}
664+
665+static void
666+test_stack_slots ()
667+{
668+ Stack* stack = NULL;
669+ Defaults* defaults = defaults_new ();
670+ Observer* observer = observer_new ();
671+ gint x;
672+ gint y;
673+ Bubble* one;
674+ Bubble* two;
675+
676+ stack = stack_new (defaults, observer);
677+
678+ // check if stack_is_slot_vacant() can take "crap" without crashing
679+ g_assert_cmpint (stack_is_slot_vacant (NULL, SLOT_TOP), ==, FALSE);
680+ g_assert_cmpint (stack_is_slot_vacant (stack, 832), ==, FALSE);
681+ g_assert_cmpint (stack_is_slot_vacant (NULL, 4321), ==, FALSE);
682+
683+ // check if stack_get_slot_position can take "crap" without crashing
684+ stack_get_slot_position (NULL, SLOT_TOP, 0, &x, &y);
685+ g_assert_cmpint (x, ==, -1);
686+ g_assert_cmpint (y, ==, -1);
687+ stack_get_slot_position (stack, 4711, 0, &x, &y);
688+ g_assert_cmpint (x, ==, -1);
689+ g_assert_cmpint (y, ==, -1);
690+ stack_get_slot_position (NULL, 42, 0, NULL, NULL);
691+
692+ // check if stack_allocate_slot() can take "crap" without crashing
693+ one = bubble_new (defaults);
694+ two = bubble_new (defaults);
695+ g_assert_cmpint (stack_allocate_slot (NULL, one, SLOT_TOP), ==, FALSE);
696+ g_assert_cmpint (stack_allocate_slot (stack, NULL, SLOT_TOP), ==, FALSE);
697+ g_assert_cmpint (stack_allocate_slot (stack, one, 4711), ==, FALSE);
698+
699+ // check if stack_free_slot() can take "crap" without crashing
700+ g_assert_cmpint (stack_free_slot (NULL, two), ==, FALSE);
701+ g_assert_cmpint (stack_free_slot (stack, NULL), ==, FALSE);
702+
703+ // initially both slots should be empty
704+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
705+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
706+ g_object_unref (one);
707+ g_object_unref (two);
708+
709+ // fill top slot, verify it's occupied, free it, verify again
710+ one = bubble_new (defaults);
711+ g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_TOP), ==, TRUE);
712+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, OCCUPIED);
713+ g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
714+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
715+ g_object_unref (one);
716+
717+ // fill bottom slot, verify it's occupied, free it, verify again
718+ two = bubble_new (defaults);
719+ g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_BOTTOM), ==, TRUE);
720+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, OCCUPIED);
721+ g_assert_cmpint (stack_free_slot (stack, two), ==, TRUE);
722+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
723+ g_object_unref (two);
724+
725+ // try to free vacant slots
726+ one = bubble_new (defaults);
727+ two = bubble_new (defaults);
728+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
729+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
730+ g_assert_cmpint (stack_free_slot (stack, one), ==, FALSE);
731+ g_assert_cmpint (stack_free_slot (stack, two), ==, FALSE);
732+ g_object_unref (one);
733+ g_object_unref (two);
734+
735+ // allocate top slot, verify, try to allocate top slot again
736+ one = bubble_new (defaults);
737+ two = bubble_new (defaults);
738+ g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_TOP), ==, TRUE);
739+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, OCCUPIED);
740+ g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_TOP), ==, FALSE);
741+ g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
742+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_TOP), ==, VACANT);
743+ g_object_unref (one);
744+ g_object_unref (two);
745+
746+ // allocate bottom slot, verify, try to allocate bottom slot again
747+ one = bubble_new (defaults);
748+ two = bubble_new (defaults);
749+ g_assert_cmpint (stack_allocate_slot (stack, one, SLOT_BOTTOM), ==, TRUE);
750+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, OCCUPIED);
751+ g_assert_cmpint (stack_allocate_slot (stack, two, SLOT_BOTTOM), ==, FALSE);
752+ g_assert_cmpint (stack_free_slot (stack, one), ==, TRUE);
753+ g_assert_cmpint (stack_is_slot_vacant (stack, SLOT_BOTTOM), ==, VACANT);
754+ g_object_unref (one);
755+ g_object_unref (two);
756+
757+ // check if we can get reasonable values from stack_get_slot_position()
758+ // FIXME: disabled this test for the moment, hopefully it works within
759+ // a real environment
760+ /*stack_get_slot_position (stack, SLOT_TOP, &x, &y);
761+ g_assert_cmpint (x, >, -1);
762+ g_assert_cmpint (y, >, -1);
763+ stack_get_slot_position (stack, SLOT_BOTTOM, &x, &y);
764+ g_assert_cmpint (x, >, -1);
765+ g_assert_cmpint (y, >, -1);*/
766+
767+ g_object_unref (G_OBJECT (stack));
768+}
769+
770 GTestSuite *
771 test_stack_create_test_suite (void)
772 {
773@@ -91,6 +217,8 @@
774 g_test_suite_add(ts, TC(test_stack_new));
775 g_test_suite_add(ts, TC(test_stack_del));
776 g_test_suite_add(ts, TC(test_stack_push));
777+ g_test_suite_add(ts, TC(test_stack_placement));
778+ g_test_suite_add(ts, TC(test_stack_slots));
779
780 return ts;
781 }

Subscribers

People subscribed via source and target branches