00001
00044 #include <stdint.h>
00045 #include <stdlib.h>
00046 #include "assert.h"
00047 #include "gfx/win.h"
00048 #include <membag.h>
00049 #include <ring.h>
00050 #include <workqueue.h>
00051
00052 #ifdef CONFIG_GFX_WIN_USE_TOUCH
00053 # include <touch/touch.h>
00054 #endif
00055
00064 struct win_window {
00066 struct win_attributes attributes;
00067
00069 struct win_window *parent;
00071 struct win_window *prev_sibling;
00073 struct win_window *next_sibling;
00075 struct win_window *top_child;
00076
00078 bool is_mapped;
00079 };
00080
00081
00082
00091 struct win_event_queue {
00092 struct ring_head ring;
00094 struct workqueue_task task;
00095 struct win_event buffer[WIN_EVENT_QUEUE_SIZE];
00096 };
00097
00098
00099
00100
00101
00102
00103
00105 static bool win_is_visible(const struct win_window *win);
00106
00108 static void win_draw(
00109 const struct win_window *win,
00110 const struct win_area *dirty_area);
00111
00113 static void win_draw_parent(
00114 const struct win_window *child,
00115 const struct win_area *dirty_area);
00116
00118 static void win_draw_contents(
00119 const struct win_window *win,
00120 const struct win_clip_region *clip);
00121
00123 static void win_draw_child(
00124 const struct win_window *child,
00125 const struct win_clip_region *parentClip);
00126
00128 static bool win_translate_area_to_parent(
00129 struct win_area *area,
00130 const struct win_window *parent);
00131
00133 static void win_destroy_children(struct win_window *win);
00134
00136 static void win_unlink(struct win_window *win);
00137
00139 static void win_add_top_child(
00140 struct win_window *parent,
00141 struct win_window *child);
00142
00144 static void win_process_pointer_event(struct win_pointer_event *event);
00145
00147 static bool win_handle_pointer_event(
00148 struct win_window *win,
00149 const struct win_pointer_event *event,
00150 const struct win_point *pos);
00151
00153 static bool win_handle_event(
00154 struct win_window *win,
00155 enum win_event_type type,
00156 const void *data);
00157
00158 #ifdef CONFIG_GFX_WIN_USE_TOUCH
00159
00160 static void win_queue_touch_event(const struct touch_event *event);
00161 #endif
00162
00164 static void win_queue_event(const struct win_event *event);
00165
00167 static void win_event_worker(struct workqueue_task *task);
00168
00169
00170
00171
00173 static struct win_window win_root;
00174
00176 static struct win_event_queue win_event_queue;
00177
00179 static uint32_t win_num_dropped_events;
00180
00182 static struct win_window *win_pointer_grabber;
00184 static struct win_window *win_keyboard_focus;
00185
00187 static struct win_point win_last_pointer_pos;
00188
00190 static struct gfx_bitmap win_root_background = {
00191 .type = BITMAP_SOLID,
00192 .data.color = GFX_COLOR(0, 0, 0),
00193 };
00194
00195
00201 void win_init(void)
00202 {
00203
00204 win_root.attributes.area.size.x = gfx_get_width();
00205 win_root.attributes.area.size.y = gfx_get_height();
00206 win_root.attributes.background = &win_root_background;
00207
00208
00209 build_assert(!(WIN_EVENT_QUEUE_SIZE & (WIN_EVENT_QUEUE_SIZE - 1)));
00210 workqueue_task_init(&win_event_queue.task, win_event_worker);
00211
00212
00213 win_keyboard_focus = &win_root;
00214 win_last_pointer_pos.x = gfx_get_width() / 2;
00215 win_last_pointer_pos.y = gfx_get_height() / 2;
00216
00217 #ifdef CONFIG_GFX_WIN_USE_TOUCH
00218
00219 touch_set_event_handler(win_queue_touch_event);
00220 #endif
00221 }
00222
00223
00230 struct win_window *win_get_root(void)
00231 {
00232 return &win_root;
00233 }
00234
00235
00243 struct win_window *win_get_parent(const struct win_window *win)
00244 {
00245 return win->parent;
00246 }
00247
00248
00254 void win_reset_root_geometry(void)
00255 {
00256
00257 win_root.attributes.area.size.x = gfx_get_width();
00258 win_root.attributes.area.size.y = gfx_get_height();
00259
00260
00261 win_attribute_mask_t mask = WIN_ATTR_SIZE;
00262 win_handle_event(&win_root, WIN_EVENT_ATTRIBUTES, &mask);
00263
00264
00265 win_redraw(&win_root);
00266 }
00267
00268
00278 void win_set_attributes(struct win_window *win,
00279 const struct win_attributes *new_attributes,
00280 win_attribute_mask_t attribute_mask)
00281 {
00282
00283 bool needs_redraw = false;
00284 struct win_area dirty_area;
00285
00286
00287 assert(win != NULL);
00288 assert(new_attributes != NULL);
00289
00290
00291
00292 dirty_area = win->attributes.area;
00293
00294
00295 if (attribute_mask & WIN_ATTR_BACKGROUND) {
00296 win->attributes.background = new_attributes->background;
00297
00298 needs_redraw = true;
00299 }
00300
00301
00302 if (attribute_mask & WIN_ATTR_EVENTHANDLER)
00303 win->attributes.event_handler = new_attributes->event_handler;
00304
00305
00306 if (attribute_mask & WIN_ATTR_BEHAVIOR)
00307 win->attributes.behavior = new_attributes->behavior;
00308
00309
00310 if (attribute_mask & WIN_ATTR_CUSTOM)
00311 win->attributes.custom = new_attributes->custom;
00312
00313
00314
00315
00316
00317
00318 if (attribute_mask & (WIN_ATTR_POSITION | WIN_ATTR_SIZE)) {
00319 win_set_area(win, &(new_attributes->area), attribute_mask);
00320 } else {
00321 win_handle_event(win, WIN_EVENT_ATTRIBUTES, &attribute_mask);
00322
00323
00324
00325
00326
00327 if (needs_redraw && win_is_visible(win))
00328 win_draw(win, &dirty_area);
00329 }
00330 }
00331
00332
00343 void win_set_area(struct win_window *win,
00344 const struct win_area *new_area,
00345 win_attribute_mask_t attribute_mask)
00346 {
00347
00348 bool exposed_areas = false;
00349 struct win_area dirty_area;
00350
00351
00352 assert(win != NULL);
00353 assert(win != &win_root);
00354 assert(new_area != NULL);
00355
00356
00357
00358
00359
00360
00361 dirty_area = win->attributes.area;
00362
00363
00364 if (attribute_mask & WIN_ATTR_POSITION) {
00365 win->attributes.area.pos = new_area->pos;
00366 win_compute_union(&dirty_area, new_area);
00367 exposed_areas = true;
00368 }
00369
00370
00371 if (attribute_mask & WIN_ATTR_SIZE) {
00372
00373 if ((new_area->size.x < win->attributes.area.size.x) ||
00374 (new_area->size.y < win->attributes.area.size.y)) {
00375 exposed_areas = true;
00376 }
00377
00378 win->attributes.area.size = new_area->size;
00379 win_compute_union(&dirty_area, new_area);
00380 }
00381
00382
00383 win_handle_event(win, WIN_EVENT_ATTRIBUTES, &attribute_mask);
00384
00385 if (win_is_visible(win)) {
00386
00387
00388
00389
00390
00391 if (exposed_areas)
00392 win_draw_parent(win, &dirty_area);
00393 else
00394 win_draw(win, &dirty_area);
00395 }
00396 }
00397
00398
00407 const struct win_attributes *win_get_attributes(const struct win_window *win)
00408 {
00409
00410 assert(win != NULL);
00411
00412
00413 return &win->attributes;
00414 }
00415
00416
00425 const struct win_area *win_get_area(const struct win_window *win)
00426 {
00427
00428 assert(win != NULL);
00429
00430
00431 return &win->attributes.area;
00432 }
00433
00434
00443 void *win_get_custom_data(const struct win_window *win)
00444 {
00445 return win->attributes.custom;
00446 }
00447
00448
00463 struct win_window *win_create(struct win_window *parent,
00464 const struct win_attributes *attributes)
00465 {
00466 struct win_window *win;
00467
00468
00469 assert(parent != NULL);
00470 assert(attributes != NULL);
00471
00472 win = membag_alloc(sizeof(struct win_window));
00473 if (!win)
00474 return NULL;
00475
00476
00477 win->attributes = *attributes;
00478 win->is_mapped = false;
00479
00480
00481
00482
00483
00484 win->top_child = NULL;
00485
00486 win_add_top_child(parent, win);
00487
00488 return win;
00489 }
00490
00491
00503 void win_destroy(struct win_window *win)
00504 {
00505
00506 assert(win != NULL);
00507 assert(win != &win_root);
00508
00509
00510 if (win->is_mapped)
00511 win_hide(win);
00512
00513
00514
00515
00516
00517 win_unlink(win);
00518 win_destroy_children(win);
00519 win_handle_event(win, WIN_EVENT_DESTROY, NULL);
00520 membag_free(win);
00521 }
00522
00523
00533 void win_reparent(struct win_window *child, struct win_window *new_parent)
00534 {
00535 bool was_mapped;
00536
00537
00538 assert(child != NULL);
00539 assert(child != &win_root);
00540 assert(new_parent != NULL);
00541
00542
00543 was_mapped = child->is_mapped;
00544 if (was_mapped)
00545 win_hide(child);
00546
00547 win_unlink(child);
00548 win_add_top_child(new_parent, child);
00549
00550 if (was_mapped)
00551 win_show(child);
00552 }
00553
00554
00562 void win_show(struct win_window *win)
00563 {
00564
00565 assert(win != NULL);
00566
00567
00568 if (win->is_mapped)
00569 return;
00570
00571
00572 win->is_mapped = true;
00573 win_redraw(win);
00574 }
00575
00576
00583 void win_redraw(const struct win_window *win)
00584 {
00585 if (win_is_visible(win)) {
00586 const struct win_area *dirty_area = &win->attributes.area;
00587 win_draw(win, dirty_area);
00588 }
00589 }
00590
00591
00599 void win_hide(struct win_window *win)
00600 {
00601
00602 assert(win != NULL);
00603
00604
00605 if (!win->is_mapped)
00606 return;
00607
00608
00609 if (win == &win_root) {
00610 win->is_mapped = false;
00611 gfx_set_clipping(0, 0, gfx_get_width(), gfx_get_height());
00612 gfx_draw_filled_rect(0, 0, gfx_get_width(), gfx_get_height(),
00613 WIN_SCREEN_COLOR);
00614 } else {
00615
00616 if (win_is_visible(win)) {
00617 win->is_mapped = false;
00618 win_draw_parent(win, &win->attributes.area);
00619 } else {
00620 win->is_mapped = false;
00621 }
00622 }
00623 }
00624
00625
00635 void win_raise(struct win_window *win)
00636 {
00637 struct win_window *parent;
00638
00639
00640 assert(win != NULL);
00641 assert(win != &win_root);
00642
00643
00644 if (win->parent->top_child == win)
00645 return;
00646
00647
00648 win_handle_event(win->top_child, WIN_EVENT_UNRAISE, NULL);
00649
00650 parent = win->parent;
00651 win_unlink(win);
00652 win_add_top_child(parent, win);
00653
00654 win_handle_event(win, WIN_EVENT_RAISE, NULL);
00655
00656 if (win_is_visible(win)) {
00657 const struct win_area *dirty_area = &win->attributes.area;
00658 win_draw(win, dirty_area);
00659 }
00660 }
00661
00662
00672 void win_lower(struct win_window *win)
00673 {
00674 struct win_window *parent;
00675
00676
00677 assert(win != NULL);
00678 assert(win != &win_root);
00679
00680
00681 if (win->parent->top_child->prev_sibling == win)
00682 return;
00683
00684
00685
00686
00687
00688
00689 win_handle_event(win->top_child, WIN_EVENT_UNRAISE, NULL);
00690
00691 parent = win->parent;
00692 win_unlink(win);
00693 win_add_top_child(parent, win);
00694 parent->top_child = win->next_sibling;
00695
00696 win_handle_event(win->top_child, WIN_EVENT_RAISE, NULL);
00697
00698 if (win_is_visible(win)) {
00699 const struct win_area *dirty_area = &win->attributes.area;
00700 win_draw(win, dirty_area);
00701 }
00702 }
00703
00704
00713 void win_queue_pointer_event(const struct win_pointer_event *event)
00714 {
00715 struct win_event w_event;
00716
00717 w_event.type = WIN_EVENT_POINTER;
00718 w_event.pointer = *event;
00719 win_queue_event(&w_event);
00720 }
00721
00722
00731 void win_queue_keyboard_event(const struct win_keyboard_event *event)
00732 {
00733 struct win_event w_event;
00734
00735 w_event.type = WIN_EVENT_KEYBOARD;
00736 w_event.keyboard = *event;
00737 win_queue_event(&w_event);
00738 }
00739
00740
00749 void win_queue_command_event(const struct win_command_event *event)
00750 {
00751 struct win_event w_event;
00752
00753 w_event.type = WIN_EVENT_COMMAND;
00754 w_event.command = *event;
00755 win_queue_event(&w_event);
00756 }
00757
00764 static void win_process_keyboard_event(struct win_keyboard_event *kevent)
00765 {
00766
00767
00768
00769
00770
00771 if (win_keyboard_focus) {
00772 struct win_window *win = win_keyboard_focus;
00773
00774 do {
00775 bool accepted = win_handle_event(win,
00776 WIN_EVENT_KEYBOARD, kevent);
00777
00778 if (accepted)
00779 break;
00780
00781 win = win->parent;
00782 } while (win != NULL);
00783 }
00784 }
00785
00792 static void win_process_command_event(struct win_command_event *cevent)
00793 {
00794 struct win_window *win = cevent->recipient;
00795
00796 assert(win != NULL);
00797
00798 do {
00799 bool accepted = win_handle_event(win, WIN_EVENT_COMMAND,
00800 (win_command_t)cevent->data);
00801
00802 if (accepted)
00803 break;
00804
00805 win = win->parent;
00806 } while (win != NULL);
00807 }
00808
00809 static bool win_event_queue_is_empty(void)
00810 {
00811 return ring_is_empty(&win_event_queue.ring);
00812 }
00813
00814 static bool win_event_queue_is_full(void)
00815 {
00816 return ring_is_full(&win_event_queue.ring, WIN_EVENT_QUEUE_SIZE);
00817 }
00818
00819 static struct win_event *win_event_queue_get_tail(void)
00820 {
00821 unsigned int tail;
00822
00823 tail = ring_get_tail(&win_event_queue.ring, WIN_EVENT_QUEUE_SIZE);
00824 return &win_event_queue.buffer[tail];
00825 }
00826
00827 static void win_event_queue_push(const struct win_event *event,
00828 clock_jiffy_t timestamp)
00829 {
00830 unsigned int index;
00831 struct win_event *head;
00832
00833 index = ring_get_head(&win_event_queue.ring, WIN_EVENT_QUEUE_SIZE);
00834 head = &win_event_queue.buffer[index];
00835 *head = *event;
00836 head->timestamp = timestamp;
00837 ring_insert_entries(&win_event_queue.ring, 1);
00838 }
00839
00840 static void win_event_queue_pop(void)
00841 {
00842 ring_extract_entries(&win_event_queue.ring, 1);
00843 }
00844
00857 void win_process_events(void)
00858 {
00859
00860 while (!win_event_queue_is_empty()) {
00861
00862 struct win_event *event = win_event_queue_get_tail();
00863
00864 switch (event->type) {
00865 case WIN_EVENT_POINTER:
00866 win_process_pointer_event(&event->pointer);
00867 break;
00868
00869 case WIN_EVENT_KEYBOARD:
00870 win_process_keyboard_event(&event->keyboard);
00871 break;
00872
00873 case WIN_EVENT_COMMAND:
00874 win_process_command_event(&event->command);
00875 break;
00876
00877 default:
00878
00879 unhandled_case(event->type);
00880 break;
00881 }
00882
00883
00884 win_event_queue_pop();
00885 }
00886 }
00887
00888
00897 void win_set_keyboard_focus(struct win_window *win)
00898 {
00899 if (win_keyboard_focus != NULL)
00900 win_handle_event(win_keyboard_focus, WIN_EVENT_LOSEFOCUS, NULL);
00901
00902 win_keyboard_focus = win;
00903 win_handle_event(win, WIN_EVENT_GETFOCUS, NULL);
00904 }
00905
00906
00916 void win_grab_pointer(struct win_window *win)
00917 {
00918 win_pointer_grabber = win;
00919 }
00920
00921
00932 bool win_is_inside_clip(const struct win_clip_region *clip,
00933 const struct win_point *point)
00934 {
00935 return (clip->NW.x <= point->x)
00936 && (clip->NW.y <= point->y)
00937 && (point->x <= clip->SE.x)
00938 && (point->y <= clip->SE.y);
00939 }
00940
00941
00950 bool win_is_inside_area(const struct win_area *area,
00951 const struct win_point *point)
00952 {
00953 return (area->pos.x <= point->x)
00954 && (area->pos.y <= point->y)
00955 && (point->x < (area->pos.x + area->size.x))
00956 && (point->y < (area->pos.y + area->size.y));
00957 }
00958
00959
00970 bool win_is_inside_window(
00971 const struct win_window *win,
00972 const struct win_point *point)
00973 {
00974 struct win_clip_region clip;
00975
00976 win_compute_clipping(win, &win->attributes.area, &clip);
00977
00978 return win_is_inside_clip(&clip, point);
00979 }
00980
00981
00989 void win_compute_union(struct win_area *area, const struct win_area *merge)
00990 {
00991 gfx_coord_t expand_left;
00992 gfx_coord_t expand_top;
00993 gfx_coord_t expand_width;
00994 gfx_coord_t expand_height;
00995
00996
00997 expand_left = area->pos.x - merge->pos.x;
00998
00999 if (expand_left > 0) {
01000 area->pos.x -= expand_left;
01001 area->size.x += expand_left;
01002 }
01003
01004
01005 expand_top = area->pos.y - merge->pos.y;
01006 if (expand_top > 0) {
01007 area->pos.y -= expand_top;
01008 area->size.y += expand_top;
01009 }
01010
01011
01012 expand_width = (merge->pos.x + merge->size.x)
01013 - (area->pos.x + area->size.x);
01014 if (expand_width > 0)
01015 area->size.x += expand_width;
01016
01017
01018 expand_height = (merge->pos.y + merge->size.y)
01019 - (area->pos.y + area->size.y);
01020 if (expand_height > 0)
01021 area->size.y += expand_height;
01022 }
01023
01024
01038 bool win_compute_intersection(struct win_clip_region *clip,
01039 const struct win_area *area)
01040 {
01041
01042 const gfx_coord_t right_x = area->pos.x + area->size.x - 1;
01043 const gfx_coord_t bottom_y = area->pos.y + area->size.y - 1;
01044
01045
01046
01047
01048
01049 if (clip->SE.x < area->pos.x)
01050 return false;
01051 if (clip->SE.y < area->pos.y)
01052 return false;
01053
01054
01055
01056
01057
01058 if (clip->NW.x > right_x)
01059 return false;
01060 if (clip->NW.y > bottom_y)
01061 return false;
01062
01063
01064 if (clip->NW.x < area->pos.x)
01065 clip->NW.x = area->pos.x;
01066 if (clip->NW.y < area->pos.y)
01067 clip->NW.y = area->pos.y;
01068
01069
01070 if (clip->SE.x > right_x)
01071 clip->SE.x = right_x;
01072 if (clip->SE.y > bottom_y)
01073 clip->SE.y = bottom_y;
01074
01075
01076 return true;
01077 }
01078
01079
01101 bool win_compute_clipping(const struct win_window *win,
01102 const struct win_area *dirty_area,
01103 struct win_clip_region *clip)
01104 {
01105
01106
01107
01108
01109
01110 clip->origin = win->attributes.area.pos;
01111 clip->NW = win->attributes.area.pos;
01112 clip->SE.x = win->attributes.area.pos.x
01113 + win->attributes.area.size.x - 1;
01114 clip->SE.y = win->attributes.area.pos.y
01115 + win->attributes.area.size.y - 1;
01116
01117
01118 if (!win_compute_intersection(clip, dirty_area))
01119 return false;
01120
01121
01122
01123
01124
01125 while (win != &win_root) {
01126
01127 win = win->parent;
01128
01129
01130 if (clip->NW.x < 0)
01131 clip->NW.x = 0;
01132 if (clip->NW.y < 0)
01133 clip->NW.y = 0;
01134 if (clip->SE.x >= win->attributes.area.size.x)
01135 clip->SE.x = win->attributes.area.size.x - 1;
01136 if (clip->SE.y >= win->attributes.area.size.y)
01137 clip->SE.y = win->attributes.area.size.y - 1;
01138
01139
01140
01141
01142
01143 if ((clip->NW.x > clip->SE.x) || (clip->NW.y > clip->SE.y))
01144 return false;
01145
01146
01147
01148
01149
01150
01151 clip->origin.x += win->attributes.area.pos.x;
01152 clip->NW.x += win->attributes.area.pos.x;
01153 clip->SE.x += win->attributes.area.pos.x;
01154
01155 clip->origin.y += win->attributes.area.pos.y;
01156 clip->NW.y += win->attributes.area.pos.y;
01157 clip->SE.y += win->attributes.area.pos.y;
01158 }
01159
01160
01161
01162
01163
01164
01165 return true;
01166 }
01167
01168
01182 static bool win_is_visible(const struct win_window *win)
01183 {
01184
01185 do {
01186
01187 if (!win->is_mapped)
01188 return false;
01189
01190 win = win->parent;
01191 } while (win != NULL);
01192
01193
01194
01195
01196
01197 return true;
01198 }
01199
01200
01223 static void win_draw(const struct win_window *win,
01224 const struct win_area *dirty_area)
01225 {
01226 struct win_clip_region clip;
01227
01228
01229
01230
01231
01232
01233 if (!win_compute_clipping(win, dirty_area, &clip))
01234 return;
01235
01236
01237
01238
01239
01240 if (win->parent && (win->attributes.behavior
01241 & WIN_BEHAVIOR_REDRAW_PARENT)) {
01242 win_draw_parent(win, dirty_area);
01243 return;
01244 }
01245
01246
01247 win_draw_contents(win, &clip);
01248
01249
01250
01251
01252
01253 while (win != &win_root) {
01254
01255
01256
01257
01258 clip.origin.x -= win->attributes.area.pos.x;
01259 clip.origin.y -= win->attributes.area.pos.y;
01260
01261
01262 while (win != win->parent->top_child) {
01263 win = win->prev_sibling;
01264 if (win->is_mapped)
01265 win_draw_child(win, &clip);
01266 }
01267
01268
01269 win = win->parent;
01270 }
01271 }
01272
01273
01284 static void win_draw_parent(const struct win_window *child,
01285 const struct win_area *dirty_area)
01286 {
01287 struct win_area area = *dirty_area;
01288
01289 if (win_translate_area_to_parent(&area, child->parent))
01290 win_draw(child->parent, &area);
01291 }
01292
01293
01312 static void win_draw_contents(const struct win_window *win,
01313 const struct win_clip_region *clip)
01314 {
01315 const struct win_window *child;
01316
01317
01318 gfx_set_clipping(clip->NW.x, clip->NW.y, clip->SE.x, clip->SE.y);
01319
01320 if (win->attributes.background) {
01321 gfx_draw_bitmap_tiled(win->attributes.background, clip->NW.x,
01322 clip->NW.y, clip->SE.x, clip->SE.y, clip->origin.x,
01323 clip->origin.y);
01324 }
01325
01326 win_handle_event((struct win_window *)win, WIN_EVENT_DRAW, clip);
01327
01328
01329 child = win->top_child;
01330 if (child != NULL) {
01331 do {
01332
01333
01334
01335
01336
01337 child = child->prev_sibling;
01338
01339 if (child->is_mapped)
01340 win_draw_child(child, clip);
01341 } while (child != win->top_child);
01342 }
01343 }
01344
01353 static void win_draw_child(const struct win_window *child,
01354 const struct win_clip_region *parent_clip)
01355 {
01356 struct win_clip_region clip;
01357
01358
01359
01360
01361
01362
01363 clip.origin = child->attributes.area.pos;
01364 clip.NW = child->attributes.area.pos;
01365 clip.SE.x = child->attributes.area.pos.x
01366 + child->attributes.area.size.x - 1;
01367 clip.SE.y = child->attributes.area.pos.y
01368 + child->attributes.area.size.y - 1;
01369
01370
01371
01372
01373
01374
01375 clip.origin.x += parent_clip->origin.x;
01376 clip.NW.x += parent_clip->origin.x;
01377 clip.SE.x += parent_clip->origin.x;
01378
01379 clip.origin.y += parent_clip->origin.y;
01380 clip.NW.y += parent_clip->origin.y;
01381 clip.SE.y += parent_clip->origin.y;
01382
01383
01384 if (clip.NW.x < parent_clip->NW.x)
01385 clip.NW.x = parent_clip->NW.x;
01386 if (clip.NW.y < parent_clip->NW.y)
01387 clip.NW.y = parent_clip->NW.y;
01388 if (clip.SE.x > parent_clip->SE.x)
01389 clip.SE.x = parent_clip->SE.x;
01390 if (clip.SE.y > parent_clip->SE.y)
01391 clip.SE.y = parent_clip->SE.y;
01392
01393
01394
01395
01396
01397 if ((clip.NW.x > clip.SE.x) || (clip.NW.y > clip.SE.y))
01398 return;
01399
01400
01401 win_draw_contents(child, &clip);
01402 }
01403
01404
01413 void win_translate_win_to_root(struct win_window const *start_win,
01414 struct win_point *return_pos)
01415 {
01416 struct win_window *win;
01417
01418 assert(start_win);
01419 assert(return_pos);
01420
01421 return_pos->x = start_win->attributes.area.pos.x;
01422 return_pos->y = start_win->attributes.area.pos.y;
01423
01424 win = start_win->parent;
01425 while (win) {
01426 return_pos->x += win->attributes.area.pos.x;
01427 return_pos->y += win->attributes.area.pos.y;
01428 win = win->parent;
01429 }
01430 }
01431
01445 static bool win_translate_area_to_parent(struct win_area *area,
01446 const struct win_window *parent)
01447 {
01448 const struct win_area *parent_area = &parent->attributes.area;
01449
01450
01451 if (area->pos.x < 0) {
01452
01453 area->size.x += area->pos.x;
01454 area->pos.x = 0;
01455 }
01456 if (area->pos.y < 0) {
01457
01458 area->size.y += area->pos.y;
01459 area->pos.y = 0;
01460 }
01461
01462 if ((area->pos.x + area->size.x) > parent_area->size.x)
01463 area->size.x = parent_area->size.x - area->pos.x;
01464 if ((area->pos.y + area->size.y) > parent_area->size.y)
01465 area->size.y = parent_area->size.y - area->pos.y;
01466
01467
01468 if ((area->size.x <= 0) || (area->size.y <= 0))
01469 return false;
01470
01471
01472 area->pos.x += parent_area->pos.x;
01473 area->pos.y += parent_area->pos.y;
01474
01475 return true;
01476 }
01477
01478
01491 static void win_destroy_children(struct win_window *win)
01492 {
01493 struct win_window *next_sibling;
01494 struct win_window *child = win->top_child;
01495
01496 if (child != NULL) {
01497 do {
01498 win_destroy_children(child);
01499 win_handle_event(child, WIN_EVENT_DESTROY, NULL);
01500 next_sibling = child->next_sibling;
01501 membag_free(child);
01502
01503 child = next_sibling;
01504 } while (child != win->top_child);
01505
01506 win->top_child = NULL;
01507 }
01508 }
01509
01510
01517 static void win_unlink(struct win_window *win)
01518 {
01519
01520 if (win->next_sibling == win) {
01521 win->parent->top_child = NULL;
01522 } else {
01523
01524 if (win->parent->top_child == win)
01525 win->parent->top_child = win->next_sibling;
01526
01527
01528 win->next_sibling->prev_sibling = win->prev_sibling;
01529 win->prev_sibling->next_sibling = win->next_sibling;
01530 }
01531
01532
01533 win->parent = NULL;
01534 win->next_sibling = NULL;
01535 win->prev_sibling = NULL;
01536 }
01537
01538
01545 static void win_add_top_child(struct win_window *parent,
01546 struct win_window *child)
01547 {
01548
01549 if (parent->top_child == NULL) {
01550
01551 child->next_sibling = child;
01552 child->prev_sibling = child;
01553 } else {
01554
01555 child->next_sibling = parent->top_child;
01556 child->prev_sibling = parent->top_child->prev_sibling;
01557
01558 child->next_sibling->prev_sibling = child;
01559 child->prev_sibling->next_sibling = child;
01560 }
01561
01562
01563 parent->top_child = child;
01564 child->parent = parent;
01565 }
01566
01567
01577 static void win_process_pointer_event(struct win_pointer_event *event)
01578 {
01579
01580 event->last_pos = win_last_pointer_pos;
01581
01582
01583 if (event->is_relative) {
01584 event->pos.x += win_last_pointer_pos.x;
01585 event->pos.y += win_last_pointer_pos.y;
01586
01587 event->is_relative = false;
01588 }
01589
01590
01591 win_last_pointer_pos = event->pos;
01592
01593
01594
01595
01596
01597
01598
01599 if (win_pointer_grabber != NULL) {
01600 win_handle_event(win_pointer_grabber,
01601 WIN_EVENT_POINTER, event);
01602 } else {
01603 win_handle_pointer_event(&win_root,
01604 event, &win_last_pointer_pos);
01605 }
01606 }
01607
01608
01629 static bool win_handle_pointer_event(struct win_window *win,
01630 const struct win_pointer_event *event,
01631 const struct win_point *pos)
01632 {
01633
01634 struct win_window *child = win->top_child;
01635
01636 if (child != NULL) {
01637
01638 struct win_point local_pos = *pos;
01639
01640 local_pos.x -= win->attributes.area.pos.x;
01641 local_pos.y -= win->attributes.area.pos.y;
01642
01643 do {
01644 struct win_area *area;
01645
01646
01647
01648
01649
01650
01651
01652 area = &child->attributes.area;
01653 if (child->is_mapped && win_is_inside_area(area, &local_pos)) {
01654 bool accepted;
01655
01656
01657
01658
01659
01660
01661
01662
01663 if ((event->type == WIN_POINTER_PRESS)
01664 && (child->attributes.behavior
01665 & WIN_BEHAVIOR_RAISE_ON_PRESS)) {
01666 win_raise(child);
01667 }
01668
01669
01670 accepted = win_handle_pointer_event(child,
01671 event, &local_pos);
01672
01673 if (accepted)
01674 return true;
01675 else
01676 break;
01677 }
01678
01679
01680
01681
01682
01683 child = child->next_sibling;
01684 } while (child != win->top_child);
01685 }
01686
01687
01688 return win_handle_event(win, WIN_EVENT_POINTER, event);
01689 }
01690
01691
01707 static bool win_handle_event(struct win_window *win,
01708 enum win_event_type type, const void *data)
01709 {
01710 win_event_handler_t handler = win->attributes.event_handler;
01711
01712 if (handler)
01713 return handler(win, type, data);
01714 else
01715 return false;
01716 }
01717
01718
01719 #ifdef CONFIG_GFX_WIN_USE_TOUCH
01720
01728 static void win_queue_touch_event(const struct touch_event *event)
01729 {
01730 struct win_pointer_event pointer_event;
01731
01732
01733
01734
01735
01736
01737 pointer_event.buttons = WIN_TOUCH_BUTTON;
01738 pointer_event.pos.x = event->point.panel_x;
01739 pointer_event.pos.y = event->point.panel_y;
01740 pointer_event.is_relative = false;
01741
01742 switch (event->type) {
01743 case TOUCH_PRESS:
01744 pointer_event.type = WIN_POINTER_PRESS;
01745 break;
01746
01747 case TOUCH_MOVE:
01748 pointer_event.type = WIN_POINTER_MOVE;
01749 break;
01750
01751 case TOUCH_RELEASE:
01752 pointer_event.type = WIN_POINTER_RELEASE;
01753 break;
01754
01755 case TOUCH_NO_EVENT:
01756
01757 break;
01758 }
01759
01760
01761 win_queue_pointer_event(&pointer_event);
01762 }
01763 #endif
01764
01765
01780 static void win_queue_event(const struct win_event *event)
01781 {
01782 irqflags_t iflags;
01783
01784 workqueue_add_task(&main_workqueue, &win_event_queue.task);
01785
01786
01787
01788
01789
01790 iflags = cpu_irq_save();
01791
01792
01793 if (win_event_queue_is_full()) {
01794 ++win_num_dropped_events;
01795 } else {
01796
01797 win_event_queue_push(event, 0);
01798 }
01799
01800 cpu_irq_restore(iflags);
01801 }
01802
01803
01810 static void win_event_worker(struct workqueue_task *task)
01811 {
01812 win_process_events();
01813 }
01814