Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/gui/window.c

    rde19d4a r2bb6d04  
    4848#include <adt/list.h>
    4949
     50#include <async.h>
    5051#include <loc.h>
    5152
     
    5556#include <draw/drawctx.h>
    5657#include <draw/surface.h>
    57 #include <display.h>
    5858
    5959#include "common.h"
     
    6767static sysarg_t header_min_width = 40;
    6868static sysarg_t close_thickness = 20;
    69 static sysarg_t corner_size = 24;
    70 static sysarg_t window_initial_size = 1;
    7169
    7270static pixel_t color_highlight = PIXEL(255, 255, 255, 255);
     
    8482static pixel_t color_caption_focus = PIXEL(255, 255, 255, 255);
    8583static pixel_t color_caption_unfocus = PIXEL(255, 207, 207, 207);
    86 
    87 static void window_close_event(void *);
    88 static void window_focus_event(void *);
    89 static void window_kbd_event(void *, kbd_event_t *);
    90 static void window_pos_event(void *, pos_event_t *);
    91 static void window_resize_event(void *, gfx_rect_t *);
    92 static void window_unfocus_event(void *);
    93 
    94 static display_wnd_cb_t window_cb = {
    95         .close_event = window_close_event,
    96         .focus_event = window_focus_event,
    97         .kbd_event = window_kbd_event,
    98         .pos_event = window_pos_event,
    99         .resize_event = window_resize_event,
    100         .unfocus_event = window_unfocus_event
    101 };
    102 
    103 static void set_cursor(window_t *window, display_stock_cursor_t cursor)
    104 {
    105         if (cursor != window->cursor) {
    106                 (void) display_window_set_cursor(window->dwindow, cursor);
    107                 window->cursor = cursor;
    108         }
    109 }
    11084
    11185static void paint_internal(widget_t *widget)
     
    284258static void root_handle_position_event(widget_t *widget, pos_event_t event)
    285259{
    286         gfx_coord2_t pos;
    287 
    288260        if (widget->window->is_decorated) {
    289261                sysarg_t width = widget->width;
     
    291263
    292264                bool btn_left = (event.btn_num == 1) && (event.type == POS_PRESS);
     265                bool btn_right = (event.btn_num == 2) && (event.type == POS_PRESS);
     266                bool allowed_button = btn_left || btn_right;
    293267
    294268                bool left = (event.hpos < border_thickness);
     
    296270                bool top = (event.vpos < border_thickness);
    297271                bool bottom = (event.vpos >= height - border_thickness);
    298                 bool edge = left || right || top || bottom;
    299 
    300                 bool cleft = (event.hpos < corner_size);
    301                 bool cright = (event.hpos >= width - corner_size);
    302                 bool ctop = (event.vpos < corner_size);
    303                 bool cbottom = (event.vpos >= height - corner_size);
    304 
    305272                bool header = (event.hpos >= border_thickness) &&
    306273                    (event.hpos < width - border_thickness) &&
     
    310277                    (event.hpos >= width - border_thickness - close_thickness);
    311278
    312                 bool isresize = widget->window->is_resizable;
    313                 display_wnd_rsztype_t rsztype = 0;
    314 
    315                 if (edge && ctop && cleft) {
    316                         rsztype = display_wr_top_left;
    317                 } else if (edge && cbottom && cleft) {
    318                         rsztype = display_wr_bottom_left;
    319                 } else if (edge && cbottom && cright) {
    320                         rsztype = display_wr_bottom_right;
    321                 } else if (edge && ctop && cright) {
    322                         rsztype = display_wr_top_right;
    323                 } else if (top) {
    324                         rsztype = display_wr_top;
    325                 } else if (left) {
    326                         rsztype = display_wr_left;
    327                 } else if (bottom) {
    328                         rsztype = display_wr_bottom;
    329                 } else if (right) {
    330                         rsztype = display_wr_right;
    331                 } else {
    332                         isresize = false;
    333                 }
    334 
    335                 if (isresize) {
    336                         (void) set_cursor(widget->window,
    337                             display_cursor_from_wrsz(rsztype));
    338                 } else {
    339                         (void) set_cursor(widget->window, dcurs_arrow);
    340                 }
    341 
    342                 pos.x = event.hpos;
    343                 pos.y = event.vpos;
    344 
    345                 if (isresize && btn_left) {
    346                         (void) display_window_resize_req(
    347                             widget->window->dwindow, rsztype, &pos);
     279                if (top && left && allowed_button) {
     280                        window_grab_flags_t flags = GF_EMPTY;
     281                        flags |= GF_MOVE_X;
     282                        flags |= GF_MOVE_Y;
     283                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     284                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     285                        win_grab(widget->window->osess, event.pos_id, flags);
     286                } else if (bottom && left && allowed_button) {
     287                        window_grab_flags_t flags = GF_EMPTY;
     288                        flags |= GF_MOVE_X;
     289                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     290                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     291                        win_grab(widget->window->osess, event.pos_id, flags);
     292                } else if (bottom && right && allowed_button) {
     293                        window_grab_flags_t flags = GF_EMPTY;
     294                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     295                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     296                        win_grab(widget->window->osess, event.pos_id, flags);
     297                } else if (top && right && allowed_button) {
     298                        window_grab_flags_t flags = GF_EMPTY;
     299                        flags |= GF_MOVE_Y;
     300                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     301                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     302                        win_grab(widget->window->osess, event.pos_id, flags);
     303                } else if (top && allowed_button) {
     304                        window_grab_flags_t flags = GF_EMPTY;
     305                        flags |= GF_MOVE_Y;
     306                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     307                        win_grab(widget->window->osess, event.pos_id, flags);
     308                } else if (left && allowed_button) {
     309                        window_grab_flags_t flags = GF_EMPTY;
     310                        flags |= GF_MOVE_X;
     311                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     312                        win_grab(widget->window->osess, event.pos_id, flags);
     313                } else if (bottom && allowed_button) {
     314                        window_grab_flags_t flags = GF_EMPTY;
     315                        flags |= btn_left ? GF_RESIZE_Y : GF_SCALE_Y;
     316                        win_grab(widget->window->osess, event.pos_id, flags);
     317                } else if (right && allowed_button) {
     318                        window_grab_flags_t flags = GF_EMPTY;
     319                        flags |= btn_left ? GF_RESIZE_X : GF_SCALE_X;
     320                        win_grab(widget->window->osess, event.pos_id, flags);
    348321                } else if (close && btn_left) {
    349                         window_close(widget->window);
     322                        win_close_request(widget->window->osess);
    350323                } else if (header && btn_left) {
    351                         (void) display_window_move_req(widget->window->dwindow,
    352                             &pos);
     324                        window_grab_flags_t flags = GF_EMPTY;
     325                        flags |= GF_MOVE_X;
     326                        flags |= GF_MOVE_Y;
     327                        win_grab(widget->window->osess, event.pos_id, flags);
    353328                } else {
    354329                        list_foreach(widget->children, link, widget_t, child) {
     
    395370    sysarg_t width, sysarg_t height, window_placement_flags_t placement_flags)
    396371{
    397         gfx_bitmap_params_t params;
    398         gfx_bitmap_alloc_t alloc;
    399         gfx_bitmap_t *new_bitmap = NULL;
    400         gfx_coord2_t offs;
    401         gfx_coord2_t dpos;
    402         display_info_t dinfo;
    403         gfx_rect_t drect;
    404         gfx_rect_t nrect;
    405         errno_t rc;
    406 
    407         if (width < 2 * border_thickness + header_min_width)
     372        if (width < 2 * border_thickness + header_min_width) {
     373                win_damage(win->osess, 0, 0, 0, 0);
    408374                return;
    409 
    410         if (height < 2 * border_thickness + header_height)
     375        }
     376
     377        if (height < 2 * border_thickness + header_height) {
     378                win_damage(win->osess, 0, 0, 0, 0);
    411379                return;
    412 
     380        }
     381
     382        /* Allocate resources for new surface. */
     383        surface_t *new_surface = surface_create(width, height, NULL,
     384            SURFACE_FLAG_SHARED);
     385        if (!new_surface)
     386                return;
     387
     388        /* Switch new and old surface. */
    413389        fibril_mutex_lock(&win->guard);
    414 
    415         /* Deallocate old bitmap. */
    416         if (win->bitmap != NULL) {
    417                 gfx_bitmap_destroy(win->bitmap);
    418                 win->bitmap = NULL;
    419         }
    420 
    421         /* Deallocate old surface. */
    422         if (win->surface != NULL) {
    423                 surface_destroy(win->surface);
    424                 win->surface = NULL;
    425         }
    426 
    427         /* Place window, if appropriate */
    428         if (placement_flags != WINDOW_PLACEMENT_ANY) {
    429                 dpos.x = 0;
    430                 dpos.y = 0;
    431 
    432                 rc = display_get_info(win->display, &dinfo);
    433                 if (rc != EOK) {
    434                         fibril_mutex_unlock(&win->guard);
    435                         return;
    436                 }
    437 
    438                 drect = dinfo.rect;
    439 
    440                 if (placement_flags & WINDOW_PLACEMENT_LEFT)
    441                         dpos.x = drect.p0.x;
    442                 else if (placement_flags & WINDOW_PLACEMENT_CENTER_X)
    443                         dpos.x = (drect.p0.x + drect.p1.x - width) / 2;
    444                 else
    445                         dpos.x = drect.p1.x - width;
    446 
    447                 if (placement_flags & WINDOW_PLACEMENT_TOP)
    448                         dpos.y = drect.p0.y;
    449                 else if (placement_flags & WINDOW_PLACEMENT_CENTER_Y)
    450                         dpos.y = (drect.p0.y + drect.p1.y - height) / 2;
    451                 else
    452                         dpos.y = drect.p1.y - height;
    453 
    454                 (void) display_window_move(win->dwindow, &dpos);
    455         }
    456 
    457         /* Resize the display window. */
    458         offs.x = offset_x;
    459         offs.y = offset_y;
    460         nrect.p0.x = 0;
    461         nrect.p0.y = 0;
    462         nrect.p1.x = width;
    463         nrect.p1.y = height;
    464 
    465         rc = display_window_resize(win->dwindow, &offs, &nrect);
    466         if (rc != EOK) {
    467                 fibril_mutex_unlock(&win->guard);
    468                 return;
    469         }
    470 
    471         gfx_bitmap_params_init(&params);
    472 #ifndef CONFIG_WIN_DOUBLE_BUF
    473         params.flags = bmpf_direct_output;
    474 #else
    475         params.flags = 0;
    476 #endif
    477         params.rect.p0.x = 0;
    478         params.rect.p0.y = 0;
    479         params.rect.p1.x = width;
    480         params.rect.p1.y = height;
    481 
    482         rc = gfx_bitmap_create(win->gc, &params, NULL, &new_bitmap);
    483         if (rc != EOK) {
    484                 if (rc == ENOTSUP) {
    485                         /* Direct output is not supported */
    486                         params.flags &= ~bmpf_direct_output;
    487                         rc = gfx_bitmap_create(win->gc, &params, NULL, &new_bitmap);
    488                         if (rc != EOK) {
    489                                 fibril_mutex_unlock(&win->guard);
    490                                 return;
    491                         }
    492                 }
    493         }
    494 
    495         rc = gfx_bitmap_get_alloc(new_bitmap, &alloc);
    496         if (rc != EOK) {
    497                 fibril_mutex_unlock(&win->guard);
    498                 return;
    499         }
    500 
    501         /* Allocate new surface. */
    502         surface_t *new_surface = surface_create(width, height, alloc.pixels,
    503             SURFACE_FLAG_SHARED);
    504         if (!new_surface) {
    505                 gfx_bitmap_destroy(new_bitmap);
    506                 fibril_mutex_unlock(&win->guard);
    507                 return;
    508         }
    509 
    510         /* Switch in new surface and bitmap. */
     390        surface_t *old_surface = win->surface;
    511391        win->surface = new_surface;
    512         win->bitmap = new_bitmap;
    513392        fibril_mutex_unlock(&win->guard);
    514393
     
    523402        fibril_mutex_unlock(&win->guard);
    524403
    525         (void) gfx_bitmap_render(win->bitmap, NULL, NULL);
     404        /* Inform compositor about new surface. */
     405        errno_t rc = win_resize(win->osess, offset_x, offset_y, width, height,
     406            placement_flags, surface_direct_access(new_surface));
     407
     408        if (rc != EOK) {
     409                /* Rollback to old surface. Reverse all changes. */
     410
     411                sysarg_t old_width = 0;
     412                sysarg_t old_height = 0;
     413                if (old_surface)
     414                        surface_get_resolution(old_surface, &old_width, &old_height);
     415
     416                fibril_mutex_lock(&win->guard);
     417                new_surface = win->surface;
     418                win->surface = old_surface;
     419                fibril_mutex_unlock(&win->guard);
     420
     421                win->root.rearrange(&win->root, 0, 0, old_width, old_height);
     422
     423                if (win->surface) {
     424                        fibril_mutex_lock(&win->guard);
     425                        surface_reset_damaged_region(win->surface);
     426                        fibril_mutex_unlock(&win->guard);
     427                }
     428
     429                surface_destroy(new_surface);
     430        } else {
     431                /* Deallocate old surface. */
     432                if (old_surface)
     433                        surface_destroy(old_surface);
     434        }
    526435}
    527436
     
    534443{
    535444        sysarg_t x, y, width, height;
    536         gfx_rect_t rect;
    537445        fibril_mutex_lock(&win->guard);
    538446        surface_get_damaged_region(win->surface, &x, &y, &width, &height);
     
    541449
    542450        if (width > 0 && height > 0) {
    543                 rect.p0.x = x;
    544                 rect.p0.y = y;
    545                 rect.p1.x = x + width;
    546                 rect.p1.y = y + height;
    547 
    548                 if (win->bitmap != NULL)
    549                         (void) gfx_bitmap_render(win->bitmap, &rect, NULL);
     451                /* Notify compositor. */
     452                win_damage(win->osess, x, y, width, height);
    550453        }
    551454}
     
    569472        win->focus = NULL;
    570473
    571         gfx_bitmap_destroy(win->bitmap);
    572 
    573         /*
    574          * XXX Here we should properly destroy the IPC GC. We only have
    575          * the generic GC so either it would need to be cast back or
    576          * GC needs a virtual destructor.
    577          */
    578 
    579         display_window_destroy(win->dwindow);
    580         display_close(win->display);
     474        win_close(win->osess);
     475        async_hangup(win->isess);
     476        async_hangup(win->osess);
    581477
    582478        while (!list_empty(&win->events.list)) {
     
    610506                        break;
    611507                case ET_POSITION_EVENT:
     508                        if (!win->is_focused) {
     509                                win->is_focused = true;
     510                                handle_refresh(win);
     511                        }
    612512                        deliver_position_event(win, event->data.pos);
    613513                        break;
     
    659559}
    660560
     561/* Input fetcher from compositor. Runs in own dedicated fibril. */
     562static errno_t fetch_input(void *arg)
     563{
     564        errno_t rc;
     565        bool terminate = false;
     566        window_t *win = (window_t *) arg;
     567
     568        while (true) {
     569                window_event_t *event = (window_event_t *) malloc(sizeof(window_event_t));
     570
     571                if (event) {
     572                        rc = win_get_event(win->isess, event);
     573                        if (rc == EOK) {
     574                                terminate = (event->type == ET_WINDOW_CLOSE);
     575                                link_initialize(&event->link);
     576                                prodcons_produce(&win->events, &event->link);
     577                        } else {
     578                                free(event);
     579                                terminate = true;
     580                        }
     581                } else {
     582                        terminate = true;
     583                }
     584
     585                if (terminate) {
     586                        break;
     587                }
     588        }
     589
     590        return 0;
     591}
     592
    661593window_t *window_open(const char *winreg, const void *data,
    662594    window_flags_t flags, const char *caption)
    663595{
    664         display_wnd_params_t wparams;
    665 
    666         window_t *win = (window_t *) calloc(1, sizeof(window_t));
     596        window_t *win = (window_t *) malloc(sizeof(window_t));
    667597        if (!win)
    668598                return NULL;
     
    670600        win->is_main = flags & WINDOW_MAIN;
    671601        win->is_decorated = flags & WINDOW_DECORATED;
    672         win->is_resizable = flags & WINDOW_RESIZEABLE;
    673602        win->is_focused = true;
    674603        prodcons_initialize(&win->events);
     
    685614        win->grab = NULL;
    686615        win->focus = NULL;
    687         win->cursor = dcurs_arrow;
    688 
    689         /* Allocate resources for new surface. */
    690         win->surface = surface_create(window_initial_size,
    691             window_initial_size, NULL, SURFACE_FLAG_SHARED);
    692         if (win->surface == NULL) {
     616        win->surface = NULL;
     617
     618        service_id_t reg_dsid;
     619        errno_t rc = loc_service_get_id(winreg, &reg_dsid, 0);
     620        if (rc != EOK) {
    693621                free(win);
    694622                return NULL;
    695623        }
    696624
    697         errno_t rc = display_open(winreg, &win->display);
    698         if (rc != EOK) {
    699                 surface_destroy(win->surface);
     625        async_sess_t *reg_sess =
     626            loc_service_connect(reg_dsid, INTERFACE_COMPOSITOR, 0);
     627        if (reg_sess == NULL) {
    700628                free(win);
    701629                return NULL;
    702630        }
    703631
    704         /* Window dimensions are not know at this time */
    705         display_wnd_params_init(&wparams);
    706         wparams.rect.p0.x = 0;
    707         wparams.rect.p0.y = 0;
    708         wparams.rect.p1.x = window_initial_size;
    709         wparams.rect.p1.y = window_initial_size;
    710         wparams.min_size.x = 2 * border_thickness + header_min_width;
    711         wparams.min_size.y = 2 * border_thickness + header_height;
    712 
    713         rc = display_window_create(win->display, &wparams, &window_cb,
    714             (void *) win, &win->dwindow);
     632        service_id_t in_dsid;
     633        service_id_t out_dsid;
     634        rc = win_register(reg_sess, flags, &in_dsid, &out_dsid);
     635        async_hangup(reg_sess);
    715636        if (rc != EOK) {
    716                 display_close(win->display);
    717                 surface_destroy(win->surface);
    718637                free(win);
    719638                return NULL;
    720639        }
    721640
    722         rc = display_window_get_gc(win->dwindow, &win->gc);
    723         if (rc != EOK) {
    724                 display_window_destroy(win->dwindow);
    725                 display_close(win->display);
    726                 surface_destroy(win->surface);
     641        win->osess = loc_service_connect(out_dsid, INTERFACE_COMPOSITOR, 0);
     642        if (win->osess == NULL) {
     643                free(win);
     644                return NULL;
     645        }
     646
     647        win->isess = loc_service_connect(in_dsid, INTERFACE_COMPOSITOR, 0);
     648        if (win->isess == NULL) {
     649                async_hangup(win->osess);
    727650                free(win);
    728651                return NULL;
     
    801724{
    802725        fid_t ev_fid = fibril_create(event_loop, win);
    803         if (!ev_fid) {
     726        fid_t fi_fid = fibril_create(fetch_input, win);
     727        if (!ev_fid || !fi_fid) {
    804728                return;
    805729        }
    806730        fibril_add_ready(ev_fid);
     731        fibril_add_ready(fi_fid);
    807732}
    808733
     
    820745void window_close(window_t *win)
    821746{
    822         window_event_t *event;
    823 
    824         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    825         if (event == NULL)
    826                 return;
    827 
    828         link_initialize(&event->link);
    829         event->type = ET_WINDOW_CLOSE;
    830         prodcons_produce(&win->events, &event->link);
    831 }
    832 
    833 static void window_close_event(void *arg)
    834 {
    835         window_t *win = (window_t *) arg;
    836 
    837         window_close(win);
    838 }
    839 
    840 static void window_focus_event(void *arg)
    841 {
    842         window_t *win = (window_t *) arg;
    843         window_event_t *event;
    844 
    845         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    846         if (event == NULL)
    847                 return;
    848 
    849         link_initialize(&event->link);
    850         event->type = ET_WINDOW_FOCUS;
    851         prodcons_produce(&win->events, &event->link);
    852 }
    853 
    854 static void window_kbd_event(void *arg, kbd_event_t *kevent)
    855 {
    856         window_t *win = (window_t *) arg;
    857         window_event_t *event;
    858 
    859         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    860         if (event == NULL)
    861                 return;
    862 
    863         link_initialize(&event->link);
    864         event->type = ET_KEYBOARD_EVENT;
    865         event->data.kbd = *kevent;
    866         prodcons_produce(&win->events, &event->link);
    867 }
    868 
    869 static void window_pos_event(void *arg, pos_event_t *pevent)
    870 {
    871         window_t *win = (window_t *) arg;
    872         window_event_t *event;
    873 
    874         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    875         if (event == NULL)
    876                 return;
    877 
    878         link_initialize(&event->link);
    879         event->type = ET_POSITION_EVENT;
    880         event->data.pos = *pevent;
    881         prodcons_produce(&win->events, &event->link);
    882 }
    883 
    884 static void window_resize_event(void *arg, gfx_rect_t *nrect)
    885 {
    886         window_t *win = (window_t *) arg;
    887         window_event_t *event;
    888 
    889         if (!win->is_resizable)
    890                 return;
    891 
    892         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    893         if (event == NULL)
    894                 return;
    895 
    896         link_initialize(&event->link);
    897         event->type = ET_WINDOW_RESIZE;
    898         event->data.resize.offset_x = nrect->p0.x;
    899         event->data.resize.offset_y = nrect->p0.y;
    900         event->data.resize.width = nrect->p1.x - nrect->p0.x;
    901         event->data.resize.height = nrect->p1.y - nrect->p0.y;
    902         event->data.resize.placement_flags = WINDOW_PLACEMENT_ANY;
    903         prodcons_produce(&win->events, &event->link);
    904 }
    905 
    906 static void window_unfocus_event(void *arg)
    907 {
    908         window_t *win = (window_t *) arg;
    909         window_event_t *event;
    910 
    911         event = (window_event_t *) calloc(1, sizeof(window_event_t));
    912         if (event == NULL)
    913                 return;
    914 
    915         link_initialize(&event->link);
    916         event->type = ET_WINDOW_UNFOCUS;
    917         prodcons_produce(&win->events, &event->link);
     747        /* Request compositor to init closing cascade. */
     748        win_close_request(win->osess);
    918749}
    919750
Note: See TracChangeset for help on using the changeset viewer.