int nx_fill(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, nxgl_mxpixel_t color[CONFIG_NX_NPLANES]) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_fill_s outmsg; #ifdef CONFIG_DEBUG if (!wnd || !rect || !color) { set_errno(EINVAL); return ERROR; } #endif /* Format the fill command */ outmsg.msgid = NX_SVRMSG_FILL; outmsg.wnd = wnd; nxgl_rectcopy(&outmsg.rect, rect); nxgl_colorcopy(outmsg.color, color); /* Forward the fill command to the server */ return nxmu_sendwindow(wnd, &outmsg, sizeof(struct nxsvrmsg_fill_s)); }
static inline void nxbe_pushrectangle(FAR struct nxbe_clipstack_s *stack, FAR struct nxbe_window_s *wnd, FAR const struct nxgl_rect_s *rect) { /* Check if there is room on the stack to hold another rectangle */ if ((stack->npushed + 1) > stack->mxrects) { /* No then we will need to reallocate the stack to hole more */ int mxrects = stack->mxrects ? 2 * stack->mxrects : NX_INITIAL_STACKSIZE; struct nxbe_cliprect_s *newstack; newstack = realloc(stack->stack, sizeof(struct nxbe_cliprect_s) * mxrects); if (!newstack) { gdbg("Failed to reallocate stack\n"); return; } stack->stack = newstack; stack->mxrects = mxrects; } /* Then push the new rectangle onto the stack */ stack->stack[stack->npushed].wnd = wnd; nxgl_rectcopy(&stack->stack[stack->npushed].rect, rect); stack->npushed++; }
int nx_fill(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, nxgl_mxpixel_t color[CONFIG_NX_NPLANES]) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_fill_s outmsg; int ret; #ifdef CONFIG_DEBUG if (!wnd || !wnd->conn || !rect || !color) { errno = EINVAL; return ERROR; } #endif /* Format the fill command */ outmsg.msgid = NX_SVRMSG_FILL; outmsg.wnd = wnd; nxgl_rectcopy(&outmsg.rect, rect); nxgl_colorcopy(outmsg.color, color); /* Forward the fill command to the server */ ret = mq_send(wnd->conn->cwrmq, &outmsg, sizeof(struct nxsvrmsg_fill_s), NX_SVRMSG_PRIO); if (ret < 0) { gdbg("mq_send failed: %d\n", errno); } return ret; }
int nx_bitmap(NXWINDOW hwnd, FAR const struct nxgl_rect_s *dest, FAR const void *src[CONFIG_NX_NPLANES], FAR const struct nxgl_point_s *origin, unsigned int stride) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_bitmap_s outmsg; int i; #ifdef CONFIG_DEBUG if (!wnd || !dest || !src || !origin) { errno = EINVAL; return ERROR; } #endif /* Format the bitmap command */ outmsg.msgid = NX_SVRMSG_BITMAP; outmsg.wnd = wnd; outmsg.stride = stride; for (i = 0; i < CONFIG_NX_NPLANES; i++) { outmsg.src[i] = src[i]; } outmsg.origin.x = origin->x; outmsg.origin.y = origin->y; nxgl_rectcopy(&outmsg.dest, dest); /* Forward the fill command to the server */ return nxmu_sendwindow(wnd, &outmsg, sizeof(struct nxsvrmsg_bitmap_s)); }
int nx_move(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, FAR const struct nxgl_point_s *offset) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_move_s outmsg; #ifdef CONFIG_DEBUG if (!wnd) { set_errno(EINVAL); return ERROR; } #endif /* Format the fill command */ outmsg.msgid = NX_SVRMSG_MOVE; outmsg.wnd = wnd; outmsg.offset.x = offset->x; outmsg.offset.y = offset->y; nxgl_rectcopy(&outmsg.rect, rect); /* Forward the fill command to the server */ return nxmu_sendwindow(wnd, &outmsg, sizeof(struct nxsvrmsg_move_s)); }
static inline bool nxbe_poprectangle(struct nxbe_clipstack_s *stack, FAR struct nxbe_window_s **wnd, struct nxgl_rect_s *rect) { if(stack->npushed > 0) { stack->npushed--; *wnd = stack->stack[stack->npushed].wnd; nxgl_rectcopy(rect, &stack->stack[stack->npushed].rect); return true; } return false; }
int nx_filltrapezoid(NXWINDOW hwnd, FAR const struct nxgl_rect_s *clip, FAR const struct nxgl_trapezoid_s *trap, nxgl_mxpixel_t color[CONFIG_NX_NPLANES]) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_filltrapezoid_s outmsg; int ret; int i; #ifdef CONFIG_DEBUG if (!wnd || !wnd->conn || !trap || !color) { errno = EINVAL; return ERROR; } #endif /* Format the fill command */ outmsg.msgid = NX_SVRMSG_FILLTRAP; outmsg.wnd = wnd; if (clip) { nxgl_rectcopy(&outmsg.clip, clip); } else { memset(&outmsg.clip, 0, sizeof(struct nxgl_rect_s)); } nxgl_trapcopy(&outmsg.trap, trap); for (i = 0; i < CONFIG_NX_NPLANES; i++) { outmsg.color[i] = color[i]; } /* Forward the fill command to the server */ ret = mq_send(wnd->conn->cwrmq, &outmsg, sizeof(struct nxsvrmsg_filltrapezoid_s), NX_SVRMSG_PRIO); if (ret < 0) { gdbg("mq_send failed: %d\n", errno); } return ret; }
void nxbe_setsize(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_size_s *size) { struct nxgl_rect_s bounds; #ifdef CONFIG_DEBUG if (!wnd) { return; } #endif /* Save the before size of the window's bounding box */ nxgl_rectcopy(&bounds, &wnd->bounds); /* Add the window origin to the supplied size get the new window bounding box */ wnd->bounds.pt2.x = wnd->bounds.pt1.x + size->w - 1; wnd->bounds.pt2.y = wnd->bounds.pt1.y + size->h - 1; /* Clip the new bounding box so that lies within the background screen */ nxgl_rectintersect(&wnd->bounds, &wnd->bounds, &wnd->be->bkgd.bounds); /* We need to update the larger of the two rectangles. That will be the * union of the before and after sizes. */ nxgl_rectunion(&bounds, &bounds, &wnd->bounds); /* Report the new size/position */ nxfe_reportposition(wnd); /* Then redraw this window AND all windows below it. Having resized the * window, we may have exposed previoulsy obscured portions of windows * below this one. */ nxbe_redrawbelow(wnd->be, wnd, &bounds); }
void nx_redrawreq(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect) { FAR struct nxbe_window_s *wnd = (FAR struct nxbe_window_s *)hwnd; struct nxsvrmsg_redrawreq_s outmsg; int ret; DEBUGASSERT(wnd && rect); /* Inform the server of the changed position */ outmsg.msgid = NX_SVRMSG_REDRAWREQ; outmsg.wnd = wnd; nxgl_rectcopy(&outmsg.rect, rect); ret = nxmu_sendwindow(wnd, &outmsg, sizeof(struct nxsvrmsg_redrawreq_s)); if (ret < 0) { gdbg("ERROR: nxmu_sendwindow failed: %d\n", errno); } }
void nxbe_setposition(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_point_s *pos) { struct nxgl_rect_s before; struct nxgl_rect_s rect; #ifdef CONFIG_DEBUG if (!wnd) { return; } #endif /* Back out the old window origin position from the bounding box */ nxgl_rectoffset(&rect, &wnd->bounds, -wnd->bounds.pt1.x, -wnd->bounds.pt1.y); /* Add the new window origin into the bounding box */ nxgl_rectcopy(&before, &wnd->bounds); nxgl_rectoffset(&wnd->bounds, &rect, pos->x, pos->y); /* Get the union of the 'before' bounding box and the 'after' bounding * this union is the region of the display that must be updated. */ nxgl_rectunion(&rect, &before, &wnd->bounds); nxgl_rectintersect(&rect, &rect, &wnd->be->bkgd.bounds); /* Report the new size/position */ nxfe_reportposition(wnd); /* Then redraw this window AND all windows below it. Having moved the * window, we may have exposed previoulsy obscured portions of windows * below this one. */ nxbe_redrawbelow(wnd->be, wnd, &rect); }
void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, FAR struct nxtext_state_s *st, NXHANDLE hfont, FAR const struct nxtext_bitmap_s *bm) { FAR struct nxtext_glyph_s *glyph; struct nxgl_rect_s bounds; struct nxgl_rect_s intersection; struct nxgl_size_s fsize; int ret; /* Handle the special case of spaces which have no glyph bitmap */ if (BM_ISSPACE(bm)) { return; } /* Get the size of the font glyph (which may not have been created yet) */ ret = nxtext_fontsize(hfont, bm->code, &fsize); if (ret < 0) { /* This would mean that there is no bitmap for the character code and * that the font would be rendered as a space. But this case should * never happen here because the BM_ISSPACE() should have already * found all such cases. */ return; } /* Construct a bounding box for the glyph */ bounds.pt1.x = bm->pos.x; bounds.pt1.y = bm->pos.y; bounds.pt2.x = bm->pos.x + fsize.w - 1; bounds.pt2.y = bm->pos.y + fsize.h - 1; /* Should this also be clipped to a region in the window? */ if (rect) { /* Get the intersection of the redraw region and the character bitmap */ nxgl_rectintersect(&intersection, rect, &bounds); } else { /* The intersection is the whole glyph */ nxgl_rectcopy(&intersection, &bounds); } /* Check for empty intersections */ if (!nxgl_nullrect(&intersection)) { FAR const void *src; /* Find (or create) the glyph that goes with this font */ glyph = nxtext_getglyph(hfont, st, bm->code); if (!glyph) { /* Shouldn't happen */ return; } /* Blit the font bitmap into the window */ src = (FAR const void *)glyph->bitmap; ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src, &bm->pos, (unsigned int)glyph->stride); if (ret < 0) { printf("nxtext_fillchar: nx_bitmapwindow failed: %d\n", errno); } } }
void nxbe_clipper(FAR struct nxbe_window_s *wnd, FAR const struct nxgl_rect_s *dest, uint8_t order, FAR struct nxbe_clipops_s *cops, FAR struct nxbe_plane_s *plane) { struct nxbe_clipstack_s stack; FAR struct nxbe_window_s *currw; struct nxgl_rect_s rect; struct nxgl_rect_s obscuredrect; struct nxgl_rect_s currbounds; struct nxgl_rect_s nonoverlapped[4]; int i; /* Initialize the stack where we will keep deferred rectangle operations */ stack.npushed = 0; stack.mxrects = 0; stack.stack = NULL; /* Loop until there are no further pending operations */ nxgl_rectcopy(&rect, dest); /* Start with the whole dest rectangle */ do { /* Loop for every window from the current window and above. Only windows * above the current window can obscure the current window */ for (currw = wnd; currw; currw = currw->above) { /* Does the current window overlap the dest rectangle? */ currbounds = currw->bounds; if (nxgl_rectoverlap(&rect, &currbounds)) { /* Yes.. then it obscures all or part of the dest rectangle. * Divide the potentially visible, non-overlapping regions into 4 * smaller rectangles and push them onto the stack for processing * on the next time through the outer loop. */ nxgl_nonintersecting(nonoverlapped, &rect, &currbounds); for (i = 3; i >= 0; i--) { /* Push the rectangles in the order specific by the input * argument of that name. */ struct nxgl_rect_s *candidate = &nonoverlapped[g_nxcliporder[order][i]]; if (!nxgl_nullrect(candidate)) { nxbe_pushrectangle(&stack, currw->above, candidate); } } /* Now performed any required processing on the obscurred, * overlapped region. */ nxgl_rectintersect(&obscuredrect, &rect, &currbounds); cops->obscured(cops, plane, &obscuredrect); /* Break out of the loop to process the pushed rectangles */ break; } } /* If there are no other windows overlapping this rectangle, then this * rectangular region must be visible. */ if (!currw && !nxgl_nullrect(&rect)) { cops->visible(cops, plane, &rect); } } while (nxbe_poprectangle(&stack, &wnd, &rect)); /* Done! If any stack was allocated, then free it before exit-ting */ if (stack.stack) { free(stack.stack); } }
int vnc_update_rectangle(FAR struct vnc_session_s *session, FAR const struct nxgl_rect_s *rect, bool change) { FAR struct vnc_fbupdate_s *update; struct nxgl_rect_s intersection; bool whupd; /* Clip rectangle to the screen dimensions */ nxgl_rectintersect(&intersection, rect, &g_wholescreen); /* Make sure that the clipped rectangle has a area */ if (!nxgl_nullrect(&intersection)) { /* Check for a whole screen update. The RealVNC client sends a lot * of these (especially when it is confused) */ whupd = (memcmp(&intersection, &g_wholescreen, sizeof(struct nxgl_rect_s)) == 0); /* Ignore any client update requests if there have been no changes to * the framebuffer since the last whole screen update. */ sched_lock(); if (!change && !session->change) { /* No.. ignore the client update. We have nothing new to report. */ sched_unlock(); return OK; } /* Ignore all updates if there is a queued whole screen update */ if (session->nwhupd == 0) { /* No whole screen updates in the queue. Is this a new whole * screen update? */ if (whupd) { /* Yes.. Discard all of the previously queued updates */ FAR struct vnc_fbupdate_s *curr; FAR struct vnc_fbupdate_s *next; updvdbg("New whole screen update...\n"); curr = (FAR struct vnc_fbupdate_s *)session->updqueue.head; sq_init(&session->updqueue); sem_reset(&session->queuesem, 0); for (; curr != NULL; curr = next) { next = curr->flink; vnc_free_update(session, curr); } /* One whole screen update will be queued. There have been * no frame buffer data changes since this update was queued. */ session->nwhupd = 1; session->change = false; } else { /* We are not updating the whole screen. Remember if this * update (OR a preceding update) was due to a data change. */ session->change |= change; } /* Allocate an update structure... waiting if necessary */ update = vnc_alloc_update(session); DEBUGASSERT(update != NULL); /* Copy the clipped rectangle into the update structure */ update->whupd = whupd; nxgl_rectcopy(&update->rect, &intersection); /* Add the upate to the end of the update queue. */ vnc_add_queue(session, update); updvdbg("Queued {(%d, %d),(%d, %d)}\n", intersection.pt1.x, intersection.pt1.y, intersection.pt2.x, intersection.pt2.y); } sched_unlock(); } /* Since we ignore bad rectangles and wait for updata structures, there is * really no way a failure can occur. */ return OK; }