Changeset e79a025 in mainline for uspace/lib/gui/window.c


Ignore:
Timestamp:
2020-07-03T23:41:46Z (4 years ago)
Author:
GitHub <noreply@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
fd11144
Parents:
edb57bc6 (diff), ddb844e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
jxsvoboda <5887334+jxsvoboda@…> (2020-07-03 23:41:46)
git-committer:
GitHub <noreply@…> (2020-07-03 23:41:46)
Message:

Merge pull request #200 from jxsvoboda/gfx

Display server

File:
1 edited

Legend:

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

    redb57bc6 re79a025  
    4848#include <adt/list.h>
    4949
    50 #include <async.h>
    5150#include <loc.h>
    5251
     
    5655#include <draw/drawctx.h>
    5756#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;
     69static sysarg_t corner_size = 24;
     70static sysarg_t window_initial_size = 1;
    6971
    7072static pixel_t color_highlight = PIXEL(255, 255, 255, 255);
     
    8284static pixel_t color_caption_focus = PIXEL(255, 255, 255, 255);
    8385static pixel_t color_caption_unfocus = PIXEL(255, 207, 207, 207);
     86
     87static void window_close_event(void *);
     88static void window_focus_event(void *);
     89static void window_kbd_event(void *, kbd_event_t *);
     90static void window_pos_event(void *, pos_event_t *);
     91static void window_resize_event(void *, gfx_rect_t *);
     92static void window_unfocus_event(void *);
     93
     94static 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
     103static 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}
    84110
    85111static void paint_internal(widget_t *widget)
     
    258284static void root_handle_position_event(widget_t *widget, pos_event_t event)
    259285{
     286        gfx_coord2_t pos;
     287
    260288        if (widget->window->is_decorated) {
    261289                sysarg_t width = widget->width;
     
    263291
    264292                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;
    267293
    268294                bool left = (event.hpos < border_thickness);
     
    270296                bool top = (event.vpos < border_thickness);
    271297                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
    272305                bool header = (event.hpos >= border_thickness) &&
    273306                    (event.hpos < width - border_thickness) &&
     
    277310                    (event.hpos >= width - border_thickness - close_thickness);
    278311
    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);
     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);
    321348                } else if (close && btn_left) {
    322                         win_close_request(widget->window->osess);
     349                        window_close(widget->window);
    323350                } else if (header && btn_left) {
    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);
     351                        (void) display_window_move_req(widget->window->dwindow,
     352                            &pos);
    328353                } else {
    329354                        list_foreach(widget->children, link, widget_t, child) {
     
    370395    sysarg_t width, sysarg_t height, window_placement_flags_t placement_flags)
    371396{
    372         if (width < 2 * border_thickness + header_min_width) {
    373                 win_damage(win->osess, 0, 0, 0, 0);
    374                 return;
    375         }
    376 
    377         if (height < 2 * border_thickness + header_height) {
    378                 win_damage(win->osess, 0, 0, 0, 0);
    379                 return;
    380         }
    381 
    382         /* Allocate resources for new surface. */
    383         surface_t *new_surface = surface_create(width, height, NULL,
     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)
     408                return;
     409
     410        if (height < 2 * border_thickness + header_height)
     411                return;
     412
     413        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,
    384503            SURFACE_FLAG_SHARED);
    385         if (!new_surface)
    386                 return;
    387 
    388         /* Switch new and old surface. */
    389         fibril_mutex_lock(&win->guard);
    390         surface_t *old_surface = win->surface;
     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. */
    391511        win->surface = new_surface;
     512        win->bitmap = new_bitmap;
    392513        fibril_mutex_unlock(&win->guard);
    393514
     
    402523        fibril_mutex_unlock(&win->guard);
    403524
    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         }
     525        (void) gfx_bitmap_render(win->bitmap, NULL, NULL);
    435526}
    436527
     
    443534{
    444535        sysarg_t x, y, width, height;
     536        gfx_rect_t rect;
    445537        fibril_mutex_lock(&win->guard);
    446538        surface_get_damaged_region(win->surface, &x, &y, &width, &height);
     
    449541
    450542        if (width > 0 && height > 0) {
    451                 /* Notify compositor. */
    452                 win_damage(win->osess, x, y, width, height);
     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);
    453550        }
    454551}
     
    472569        win->focus = NULL;
    473570
    474         win_close(win->osess);
    475         async_hangup(win->isess);
    476         async_hangup(win->osess);
     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);
    477581
    478582        while (!list_empty(&win->events.list)) {
     
    506610                        break;
    507611                case ET_POSITION_EVENT:
    508                         if (!win->is_focused) {
    509                                 win->is_focused = true;
    510                                 handle_refresh(win);
    511                         }
    512612                        deliver_position_event(win, event->data.pos);
    513613                        break;
     
    559659}
    560660
    561 /* Input fetcher from compositor. Runs in own dedicated fibril. */
    562 static 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 
    593661window_t *window_open(const char *winreg, const void *data,
    594662    window_flags_t flags, const char *caption)
    595663{
    596         window_t *win = (window_t *) malloc(sizeof(window_t));
     664        display_wnd_params_t wparams;
     665
     666        window_t *win = (window_t *) calloc(1, sizeof(window_t));
    597667        if (!win)
    598668                return NULL;
     
    600670        win->is_main = flags & WINDOW_MAIN;
    601671        win->is_decorated = flags & WINDOW_DECORATED;
     672        win->is_resizable = flags & WINDOW_RESIZEABLE;
    602673        win->is_focused = true;
    603674        prodcons_initialize(&win->events);
     
    614685        win->grab = NULL;
    615686        win->focus = 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) {
     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) {
    621693                free(win);
    622694                return NULL;
    623695        }
    624696
    625         async_sess_t *reg_sess =
    626             loc_service_connect(reg_dsid, INTERFACE_COMPOSITOR, 0);
    627         if (reg_sess == NULL) {
     697        errno_t rc = display_open(winreg, &win->display);
     698        if (rc != EOK) {
     699                surface_destroy(win->surface);
    628700                free(win);
    629701                return NULL;
    630702        }
    631703
    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);
     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);
    636715        if (rc != EOK) {
     716                display_close(win->display);
     717                surface_destroy(win->surface);
    637718                free(win);
    638719                return NULL;
    639720        }
    640721
    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);
     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);
    650727                free(win);
    651728                return NULL;
     
    724801{
    725802        fid_t ev_fid = fibril_create(event_loop, win);
    726         fid_t fi_fid = fibril_create(fetch_input, win);
    727         if (!ev_fid || !fi_fid) {
     803        if (!ev_fid) {
    728804                return;
    729805        }
    730806        fibril_add_ready(ev_fid);
    731         fibril_add_ready(fi_fid);
    732807}
    733808
     
    745820void window_close(window_t *win)
    746821{
    747         /* Request compositor to init closing cascade. */
    748         win_close_request(win->osess);
     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
     833static void window_close_event(void *arg)
     834{
     835        window_t *win = (window_t *) arg;
     836
     837        window_close(win);
     838}
     839
     840static 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
     854static 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
     869static 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
     884static 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
     906static 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);
    749918}
    750919
Note: See TracChangeset for help on using the changeset viewer.