Merge lp:~macslow/notify-osd/two-slots into lp:notify-osd/trunk
- two-slots
- Merge into main
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
David Barth (community) | Approve | ||
Review via email: mp+11168@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Mirco Müller (macslow) wrote : | # |
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 | } |
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.