From cc3754a2bdd6801179751d45f1df3b5816e189fc Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Thu, 17 May 2012 18:48:28 -0700 Subject: xorg: work on offscreen bitmaps --- common/xrdp_constants.h | 1 + libxrdp/libxrdp.c | 17 +++++ libxrdp/libxrdpinc.h | 5 ++ libxrdp/xrdp_orders.c | 4 +- xorg/X11R7.6/rdp/rdp.h | 8 ++ xorg/X11R7.6/rdp/rdpdraw.c | 173 +++++++++++++++++++++++++++++++++--------- xorg/X11R7.6/rdp/rdpmain.c | 3 + xorg/X11R7.6/rdp/rdpup.c | 105 ++++++++++++++++--------- xrdp/xrdp.h | 15 +++- xrdp/xrdp_cache.c | 4 +- xrdp/xrdp_mm.c | 138 +++++++++++++++++++++++++++++++-- xrdp/xrdp_painter.c | 185 ++++++++++++++++++++++++++++++++++++--------- xrdp/xrdp_types.h | 13 +++- xrdp/xrdp_wm.c | 2 + xup/xup.c | 33 ++++++++ xup/xup.h | 10 ++- 16 files changed, 598 insertions(+), 118 deletions(-) diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 1faeea33..035ba663 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -429,6 +429,7 @@ #define WND_TYPE_COMBO 7 #define WND_TYPE_SPECIAL 8 #define WND_TYPE_LISTBOX 9 +#define WND_TYPE_OFFSCREEN 10 /* button states */ #define BUTTON_STATE_UP 0 diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 05e67eb7..9e206c2c 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -754,3 +754,20 @@ libxrdp_orders_send_brush(struct xrdp_session* session, width, height, bpp, type, size, data, cache_id); } + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_create_os_surface(struct xrdp_session* session, int id, + int width, int height) +{ + return xrdp_orders_send_create_os_surface + ((struct xrdp_orders*)(session->orders), id, width, height); +} + +/*****************************************************************************/ +int EXPORT_CC +libxrdp_orders_send_switch_os_surface(struct xrdp_session* session, int id) +{ + return xrdp_orders_send_switch_os_surface + ((struct xrdp_orders*)(session->orders), id); +} diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 82ac9ad0..b7974b35 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -176,5 +176,10 @@ int DEFAULT_CC libxrdp_orders_send_brush(struct xrdp_session* session, int width, int height, int bpp, int type, int size, char* data, int cache_id); +int EXPORT_CC +libxrdp_orders_send_create_os_surface(struct xrdp_session* session, int id, + int width, int height); +int EXPORT_CC +libxrdp_orders_send_switch_os_surface(struct xrdp_session* session, int id); #endif diff --git a/libxrdp/xrdp_orders.c b/libxrdp/xrdp_orders.c index 925c52aa..5acd42b0 100644 --- a/libxrdp/xrdp_orders.c +++ b/libxrdp/xrdp_orders.c @@ -1976,7 +1976,7 @@ xrdp_orders_send_create_os_surface(struct xrdp_orders* self, int id, int order_flags; int cache_id; - g_writeln("xrdp_orders_send_create_os_surface:"); + //g_writeln("xrdp_orders_send_create_os_surface:"); xrdp_orders_check(self, 7); self->order_count++; order_flags = RDP_ORDER_SECONDARY; @@ -1997,7 +1997,7 @@ xrdp_orders_send_switch_os_surface(struct xrdp_orders* self, int id) int order_flags; int cache_id; - g_writeln("xrdp_orders_send_switch_os_surface:"); + //g_writeln("xrdp_orders_send_switch_os_surface:"); xrdp_orders_check(self, 3); self->order_count++; order_flags = RDP_ORDER_SECONDARY; diff --git a/xorg/X11R7.6/rdp/rdp.h b/xorg/X11R7.6/rdp/rdp.h index 3927e29d..7df24c48 100644 --- a/xorg/X11R7.6/rdp/rdp.h +++ b/xorg/X11R7.6/rdp/rdp.h @@ -136,6 +136,7 @@ struct _rdpScreenInfoRec ClearToBackgroundProcPtr ClearToBackground; ScreenWakeupHandlerProcPtr WakeupHandler; CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; /* Backing store procedures */ RestoreAreasProcPtr RestoreAreas; @@ -292,6 +293,11 @@ void rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +void +rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, + GlyphPtr* glyphs); /* rdpinput.c */ @@ -378,6 +384,8 @@ rdpup_delete_os_surface(int rdpid); void rdpup_paint_rect_os(int x, int y, int cx, int cy, int rdpid, int srcx, int srcy); +void +rdpup_set_hints(int hints, int mask); #if defined(X_BYTE_ORDER) # if X_BYTE_ORDER == X_LITTLE_ENDIAN diff --git a/xorg/X11R7.6/rdp/rdpdraw.c b/xorg/X11R7.6/rdp/rdpdraw.c index e393e88c..6e2846ed 100644 --- a/xorg/X11R7.6/rdp/rdpdraw.c +++ b/xorg/X11R7.6/rdp/rdpdraw.c @@ -68,8 +68,15 @@ extern int g_Bpp; /* from rdpmain.c */ extern ScreenPtr g_pScreen; /* from rdpmain.c */ extern Bool g_wrapPixmap; /* from rdpmain.c */ +extern int g_con_number; /* in rdpup.c */ +extern int g_connected; /* in rdpup.c */ + ColormapPtr g_rdpInstalledColormap; +static int g_pixmap_rdpid = 1; +int g_pixmap_byte_total = 0; +int g_pixmap_num_used = 0; + GCFuncs g_rdpGCFuncs = { rdpValidateGC, rdpChangeGC, rdpCopyGC, rdpDestroyGC, rdpChangeClip, @@ -395,14 +402,29 @@ rdpCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, int org_width; org_width = width; + /* width must be a multiple of 4 in rdp */ width = (width + 3) & ~3; LLOGLN(10, ("rdpCreatePixmap: width %d org_width %d", width, org_width)); pScreen->CreatePixmap = g_rdpScreen.CreatePixmap; rv = pScreen->CreatePixmap(pScreen, width, height, depth, usage_hint); priv = GETPIXPRIV(rv); - priv->status = 1; - pScreen->CreatePixmap = rdpCreatePixmap; + if ((g_rdpScreen.client_info.offscreen_support_level > 0) && + (rv->drawable.depth == g_rdpScreen.depth) && + (org_width > 1) && (height > 1) && g_connected) + { + priv->allocBytes = width * height * 4; + g_pixmap_byte_total += priv->allocBytes; + g_pixmap_num_used++; + priv->status = 1; + priv->rdpid = g_pixmap_rdpid; + g_pixmap_rdpid++; + priv->con_number = g_con_number; + rdpup_create_os_surface(priv->rdpid, width, height); + LLOGLN(0, ("rdpCreatePixmap: g_pixmap_byte_total %d g_pixmap_num_used %d", + g_pixmap_byte_total, g_pixmap_num_used)); + } pScreen->ModifyPixmapHeader(rv, org_width, 0, 0, 0, 0, 0); + pScreen->CreatePixmap = rdpCreatePixmap; return rv; } @@ -414,9 +436,22 @@ rdpDestroyPixmap(PixmapPtr pPixmap) ScreenPtr pScreen; rdpPixmapRec* priv; - //ErrorF("rdpDestroyPixmap:\n"); + LLOGLN(10, ("rdpDestroyPixmap:")); priv = GETPIXPRIV(pPixmap); - //ErrorF(" refcnt %d\n", pPixmap->refcnt); + LLOGLN(10, ("status %d refcnt %d", priv->status, pPixmap->refcnt)); + if (pPixmap->refcnt < 2) + { + if (XRDP_IS_OS(priv) && g_connected) + { + g_pixmap_byte_total -= priv->allocBytes; + g_pixmap_num_used--; + LLOGLN(0, ("rdpDestroyPixmap: id 0x%x " + "rdpid 0x%x g_pixmap_byte_total %d g_pixmap_num_used %d", + pPixmap->drawable.id, priv->rdpid, + g_pixmap_byte_total, g_pixmap_num_used)); + rdpup_delete_os_surface(priv->rdpid); + } + } pScreen = pPixmap->drawable.pScreen; pScreen->DestroyPixmap = g_rdpScreen.DestroyPixmap; rv = pScreen->DestroyPixmap(pPixmap); @@ -691,51 +726,119 @@ rdpComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, DrawablePtr p; int j; int num_clips; + int got_id; + WindowPtr pDstWnd; + PixmapPtr pDstPixmap; + rdpPixmapRec* pDstPriv; + struct image_data id; - DEBUG_OUT_OPS(("in rdpComposite\n")); + LLOGLN(10, ("rdpComposite:")); ps = GetPictureScreen(g_pScreen); ps->Composite = g_rdpScreen.Composite; ps->Composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); + ps->Composite = rdpComposite; + p = pDst->pDrawable; - if (p->type == DRAWABLE_WINDOW) + + got_id = 0; + if (p->type == DRAWABLE_PIXMAP) { - if (pDst->clientClipType == CT_REGION) + pDstPixmap = (PixmapPtr)p; + pDstPriv = GETPIXPRIV(pDstPixmap); + if (XRDP_IS_OS(pDstPriv)) { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; - RegionInit(®1, &box, 0); - RegionInit(®2, NullBox, 0); - RegionCopy(®2, pDst->clientClip); - RegionTranslate(®2, p->x + pDst->clipOrigin.x, - p->y + pDst->clipOrigin.y); - RegionIntersect(®1, ®1, ®2); - num_clips = REGION_NUM_RECTS(®1); - if (num_clips > 0) + rdpup_switch_os_surface(pDstPriv->rdpid); + rdpup_get_pixmap_image_rect(pDstPixmap, &id); + got_id = 1; + } + } + else + { + if (p->type == DRAWABLE_WINDOW) + { + pDstWnd = (WindowPtr)p; + if (pDstWnd->viewable) { - rdpup_begin_update(); - for (j = num_clips - 1; j >= 0; j--) - { - box = REGION_RECTS(®1)[j]; - rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); - } - rdpup_end_update(); + rdpup_get_screen_image_rect(&id); + got_id = 1; } - RegionUninit(®1); - RegionUninit(®2); } - else + } + if (!got_id) + { + return; + } + + if (pDst->clientClipType == CT_REGION) + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + RegionInit(®1, &box, 0); + RegionInit(®2, NullBox, 0); + RegionCopy(®2, pDst->clientClip); + RegionTranslate(®2, p->x + pDst->clipOrigin.x, + p->y + pDst->clipOrigin.y); + RegionIntersect(®1, ®1, ®2); + num_clips = REGION_NUM_RECTS(®1); + if (num_clips > 0) { - box.x1 = p->x + xDst; - box.y1 = p->y + yDst; - box.x2 = box.x1 + width; - box.y2 = box.y1 + height; rdpup_begin_update(); - rdpup_send_area(0, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + for (j = num_clips - 1; j >= 0; j--) + { + box = REGION_RECTS(®1)[j]; + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + } rdpup_end_update(); } + RegionUninit(®1); + RegionUninit(®2); } - ps->Composite = rdpComposite; + else + { + box.x1 = p->x + xDst; + box.y1 = p->y + yDst; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + rdpup_begin_update(); + rdpup_send_area(&id, box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); + rdpup_end_update(); + } + rdpup_switch_os_surface(-1); +} + +/******************************************************************************/ +void +rdpGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, int nlists, GlyphListPtr lists, + GlyphPtr* glyphs) +{ + PictureScreenPtr ps; + int index; + + LLOGLN(10, ("rdpGlyphs:")); + LLOGLN(10, ("rdpGlyphs: nlists %d len %d", nlists, lists->len)); + if (g_rdpScreen.client_info.jpeg) + { + rdpup_set_hints(1, 1); + } + for (index = 0; index < lists->len; index++) + { + LLOGLN(10, (" index %d size %d refcnt %d width %d height %d", + index, glyphs[index]->size, glyphs[index]->refcnt, + glyphs[index]->info.width, glyphs[index]->info.height)); + } + ps = GetPictureScreen(g_pScreen); + ps->Glyphs = g_rdpScreen.Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlists, lists, glyphs); + ps->Glyphs = rdpGlyphs; + if (g_rdpScreen.client_info.jpeg) + { + rdpup_set_hints(0, 1); + } + LLOGLN(10, ("rdpGlyphs: out")); } diff --git a/xorg/X11R7.6/rdp/rdpmain.c b/xorg/X11R7.6/rdp/rdpmain.c index f95a718a..b8b3840f 100644 --- a/xorg/X11R7.6/rdp/rdpmain.c +++ b/xorg/X11R7.6/rdp/rdpmain.c @@ -361,6 +361,8 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char** argv) if (ps) { g_rdpScreen.Composite = ps->Composite; + g_rdpScreen.Glyphs = ps->Glyphs; + } pScreen->blackPixel = g_rdpScreen.blackPixel; pScreen->whitePixel = g_rdpScreen.whitePixel; @@ -370,6 +372,7 @@ rdpScreenInit(int index, ScreenPtr pScreen, int argc, char** argv) if (ps) { ps->Composite = rdpComposite; + ps->Glyphs = rdpGlyphs; } pScreen->SaveScreen = rdpSaveScreen; /* GC procedures */ diff --git a/xorg/X11R7.6/rdp/rdpup.c b/xorg/X11R7.6/rdp/rdpup.c index 5d0049d3..4a8bf9f8 100644 --- a/xorg/X11R7.6/rdp/rdpup.c +++ b/xorg/X11R7.6/rdp/rdpup.c @@ -38,7 +38,8 @@ int g_con_number = 0; /* increments for each connection */ static int g_listen_sck = 0; static int g_sck = 0; static int g_sck_closed = 0; -static int g_connected = 0; + +int g_connected = 0; static int g_dis_listen_sck = 0; //static int g_dis_sck = 0; @@ -65,6 +66,9 @@ extern rdpScreenInfoRec g_rdpScreen; /* from rdpmain.c */ extern int g_use_uds; /* in rdpmain.c */ extern char g_uds_data[]; /* in rdpmain.c */ +extern int g_pixmap_byte_total; /* in rdpdraw.c */ +extern int g_pixmap_num_used; /* in rdpdraw.c */ + /* 0 GXclear, 0 1 GXnor, DPon @@ -189,6 +193,7 @@ rdpup_send_pending(void) { DEBUG_OUT_UP(("end %d\n", g_count)); out_uint16_le(g_out_s, 2); + out_uint16_le(g_out_s, 4); g_count++; s_mark_end(g_out_s); rdpup_send_msg(g_out_s); @@ -202,16 +207,7 @@ rdpup_send_pending(void) static CARD32 rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) { - if (g_connected && g_begin) - { - DEBUG_OUT_UP(("end %d\n", g_count)); - out_uint16_le(g_out_s, 2); - g_count++; - s_mark_end(g_out_s); - rdpup_send_msg(g_out_s); - } - g_count = 0; - g_begin = 0; + rdpup_send_pending(); g_scheduled = 0; return 0; } @@ -254,6 +250,8 @@ rdpup_recv(char* data, int len) g_tcp_close(g_sck); g_sck = 0; g_sck_closed = 1; + g_pixmap_byte_total = 0; + g_pixmap_num_used = 0; return 1; } } @@ -264,6 +262,8 @@ rdpup_recv(char* data, int len) g_tcp_close(g_sck); g_sck = 0; g_sck_closed = 1; + g_pixmap_byte_total = 0; + g_pixmap_num_used = 0; return 1; } else @@ -568,7 +568,7 @@ rdpup_get_pixmap_image_rect(PixmapPtr pPixmap, struct image_data* id) id->height = pPixmap->drawable.height; id->bpp = g_rdpScreen.rdp_bpp; id->Bpp = g_rdpScreen.rdp_Bpp; - id->lineBytes = id->width * id->Bpp; + id->lineBytes = pPixmap->devKind; id->pixels = (char*)(pPixmap->devPrivate.ptr); } @@ -1087,11 +1087,13 @@ rdpup_set_cursor(short x, short y, char* cur_data, char* cur_mask) int rdpup_create_os_surface(int rdpid, int width, int height) { + LLOGLN(10, ("rdpup_create_os_surface:")); if (g_connected) { DEBUG_OUT_UP((" rdpup_create_os_surface\n")); - rdpup_pre_check(10); + rdpup_pre_check(12); out_uint16_le(g_out_s, 20); + out_uint16_le(g_out_s, 12); g_count++; out_uint32_le(g_out_s, rdpid); out_uint16_le(g_out_s, width); @@ -1112,15 +1114,19 @@ rdpup_switch_os_surface(int rdpid) return 0; } g_rdpid = rdpid; - rdpup_send_pending(); - LLOGLN(0, ("rdpup_switch_os_surface: rdpid %d", rdpid)); + rdpup_send_pending(); // TODO: do we need this ? + // the protocol allows switch the surface anytime + + LLOGLN(10, ("rdpup_switch_os_surface: rdpid %d", rdpid)); /* switch surface */ out_uint16_le(g_out_s, 21); + out_uint16_le(g_out_s, 8); out_uint32_le(g_out_s, rdpid); /* begin update */ out_uint16_le(g_out_s, 1); + out_uint16_le(g_out_s, 4); g_begin = 1; g_count = 2; @@ -1132,15 +1138,17 @@ rdpup_switch_os_surface(int rdpid) int rdpup_delete_os_surface(int rdpid) { + LLOGLN(10, ("rdpup_delete_os_surface: rdpid %d", rdpid)); if (g_connected) { - DEBUG_OUT_UP((" rdpup_delete_os_surface\n")); + LLOGLN(10, ("rdpup_delete_os_surface: rdpid %d", rdpid)); //if (g_current_surface == rdpid) //{ // g_current_surface = -1; //} - rdpup_pre_check(6); + rdpup_pre_check(8); out_uint16_le(g_out_s, 22); + out_uint16_le(g_out_s, 8); g_count++; out_uint32_le(g_out_s, rdpid); } @@ -1149,7 +1157,7 @@ rdpup_delete_os_surface(int rdpid) /******************************************************************************/ static int -get_single_color(int x, int y, int w, int h) +get_single_color(struct image_data* id, int x, int y, int w, int h) { int rv; int i; @@ -1165,8 +1173,8 @@ get_single_color(int x, int y, int w, int h) { for (i = 0; i < h; i++) { - i8 = (unsigned char*)(g_rdpScreen.pfbMemory + - ((y + i) * g_rdpScreen.paddedWidthInBytes) + (x * g_Bpp)); + i8 = (unsigned char*)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); if (i == 0) { p = *i8; @@ -1185,8 +1193,8 @@ get_single_color(int x, int y, int w, int h) { for (i = 0; i < h; i++) { - i16 = (unsigned short*)(g_rdpScreen.pfbMemory + - ((y + i) * g_rdpScreen.paddedWidthInBytes) + (x * g_Bpp)); + i16 = (unsigned short*)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); if (i == 0) { p = *i16; @@ -1205,8 +1213,8 @@ get_single_color(int x, int y, int w, int h) { for (i = 0; i < h; i++) { - i32 = (unsigned int*)(g_rdpScreen.pfbMemory + - ((y + i) * g_rdpScreen.paddedWidthInBytes) + (x * g_Bpp)); + i32 = (unsigned int*)(id->pixels + + ((y + i) * id->lineBytes) + (x * g_Bpp)); if (i == 0) { p = *i32; @@ -1237,12 +1245,20 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h) int lh; int lw; int size; + struct image_data lid; + + LLOGLN(10, ("rdpup_send_area: id %p x %d y %d w %d h %d", id, x, y, w, h)); + if (id == 0) + { + rdpup_get_screen_image_rect(&lid); + id = &lid; + } - if (x >= g_rdpScreen.width) + if (x >= id->width) { return; } - if (y >= g_rdpScreen.height) + if (y >= id->height) { return; } @@ -1264,13 +1280,13 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h) { return; } - if (x + w > g_rdpScreen.width) + if (x + w > id->width) { - w = g_rdpScreen.width - x; + w = id->width - x; } - if (y + h > g_rdpScreen.height) + if (y + h > id->height) { - h = g_rdpScreen.height - y; + h = id->height - y; } DEBUG_OUT_UP(("%d\n", w * h)); if (g_connected && g_begin) @@ -1284,7 +1300,7 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h) { lw = MIN(64, (x + w) - lx); lh = MIN(64, (y + h) - ly); - single_color = get_single_color(lx, ly, lw, lh); + single_color = get_single_color(id, lx, ly, lw, lh); if (single_color != -1) { DEBUG_OUT_UP(("%d sending single color\n", g_count)); @@ -1293,7 +1309,7 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h) } else { - size = lw * lh * g_rdpScreen.rdp_Bpp + 24; + size = lw * lh * id->Bpp + 24; rdpup_pre_check(size); out_uint16_le(g_out_s, 5); out_uint16_le(g_out_s, size); @@ -1302,13 +1318,13 @@ rdpup_send_area(struct image_data* id, int x, int y, int w, int h) out_uint16_le(g_out_s, ly); out_uint16_le(g_out_s, lw); out_uint16_le(g_out_s, lh); - out_uint32_le(g_out_s, lw * lh * g_rdpScreen.rdp_Bpp); + out_uint32_le(g_out_s, lw * lh * id->Bpp); for (i = 0; i < lh; i++) { - s = (g_rdpScreen.pfbMemory + - ((ly + i) * g_rdpScreen.paddedWidthInBytes) + (lx * g_Bpp)); + s = (id->pixels + + ((ly + i) * id->lineBytes) + (lx * g_Bpp)); convert_pixels(s, g_out_s->p, lw); - g_out_s->p += lw * g_rdpScreen.rdp_Bpp; + g_out_s->p += lw * id->Bpp; } out_uint16_le(g_out_s, lw); out_uint16_le(g_out_s, lh); @@ -1329,8 +1345,9 @@ rdpup_paint_rect_os(int x, int y, int cx, int cy, { if (g_connected) { - rdpup_pre_check(18); + rdpup_pre_check(20); out_uint16_le(g_out_s, 23); + out_uint16_le(g_out_s, 20); g_count++; out_uint16_le(g_out_s, x); out_uint16_le(g_out_s, y); @@ -1341,3 +1358,17 @@ rdpup_paint_rect_os(int x, int y, int cx, int cy, out_uint16_le(g_out_s, srcy); } } + +/******************************************************************************/ +void +rdpup_set_hints(int hints, int mask) +{ + if (g_connected) + { + rdpup_pre_check(6); + out_uint16_le(g_out_s, 24); + g_count++; + out_uint32_le(g_out_s, hints); + out_uint32_le(g_out_s, mask); + } +} diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 14be3767..e295408c 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -64,7 +64,8 @@ int APP_CC xrdp_cache_reset(struct xrdp_cache* self, struct xrdp_client_info* client_info); int APP_CC -xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap); +xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap, + int hints); int APP_CC xrdp_cache_add_palette(struct xrdp_cache* self, int* palette); int APP_CC @@ -422,3 +423,15 @@ int DEFAULT_CC server_send_to_channel(struct xrdp_mod* mod, int channel_id, char* data, int data_len, int total_data_len, int flags); +int DEFAULT_CC +server_create_os_surface(struct xrdp_mod* mod, int id, + int width, int height); +int DEFAULT_CC +server_switch_os_surface(struct xrdp_mod* mod, int id); +int DEFAULT_CC +server_delete_os_surface(struct xrdp_mod* mod, int id); +int DEFAULT_CC +server_paint_rect_os(struct xrdp_mod* mod, int x, int y, int cx, int cy, + int id, int srcx, int srcy); +int DEFAULT_CC +server_set_hints(struct xrdp_mod* mod, int hints, int mask); diff --git a/xrdp/xrdp_cache.c b/xrdp/xrdp_cache.c index 88180491..a63a8210 100644 --- a/xrdp/xrdp_cache.c +++ b/xrdp/xrdp_cache.c @@ -73,6 +73,7 @@ xrdp_cache_delete(struct xrdp_cache* self) g_free(self->char_items[i][j].font_item.data); } } + /* free all the off screen bitmaps */ for (i = 0; i < 2000; i++) { xrdp_bitmap_delete(self->os_bitmap_items[i].bitmap); @@ -131,7 +132,8 @@ xrdp_cache_reset(struct xrdp_cache* self, /*****************************************************************************/ /* returns cache id */ int APP_CC -xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap) +xrdp_cache_add_bitmap(struct xrdp_cache* self, struct xrdp_bitmap* bitmap, + int hints) { int i = 0; int j = 0; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index a41208eb..f0ecc249 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -351,6 +351,11 @@ xrdp_mm_setup_mod1(struct xrdp_mm* self) self->mod->server_query_channel = server_query_channel; self->mod->server_get_channel_id = server_get_channel_id; self->mod->server_send_to_channel = server_send_to_channel; + self->mod->server_create_os_surface = server_create_os_surface; + self->mod->server_switch_os_surface = server_switch_os_surface; + self->mod->server_delete_os_surface = server_delete_os_surface; + self->mod->server_paint_rect_os = server_paint_rect_os; + self->mod->server_set_hints = server_set_hints; } } /* id self->mod is null, there must be a problem */ @@ -1223,7 +1228,7 @@ server_fill_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy) return 0; } wm = (struct xrdp_wm*)(mod->wm); - xrdp_painter_fill_rect(p, wm->screen, x, y, cx, cy); + xrdp_painter_fill_rect(p, wm->target_surface, x, y, cx, cy); return 0; } @@ -1242,7 +1247,7 @@ server_screen_blt(struct xrdp_mod* mod, int x, int y, int cx, int cy, } wm = (struct xrdp_wm*)(mod->wm); p->rop = 0xcc; - xrdp_painter_copy(p, wm->screen, wm->screen, x, y, cx, cy, srcx, srcy); + xrdp_painter_copy(p, wm->screen, wm->target_surface, x, y, cx, cy, srcx, srcy); return 0; } @@ -1262,7 +1267,7 @@ server_paint_rect(struct xrdp_mod* mod, int x, int y, int cx, int cy, } wm = (struct xrdp_wm*)(mod->wm); b = xrdp_bitmap_create_with_data(width, height, wm->screen->bpp, data, wm); - xrdp_painter_copy(p, b, wm->screen, x, y, cx, cy, srcx, srcy); + xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); xrdp_bitmap_delete(b); return 0; } @@ -1453,7 +1458,7 @@ server_draw_line(struct xrdp_mod* mod, int x1, int y1, int x2, int y2) return 0; } wm = (struct xrdp_wm*)(mod->wm); - return xrdp_painter_line(p, wm->screen, x1, y1, x2, y2); + return xrdp_painter_line(p, wm->target_surface, x1, y1, x2, y2); } /*****************************************************************************/ @@ -1492,7 +1497,7 @@ server_draw_text(struct xrdp_mod* mod, int font, return 0; } wm = (struct xrdp_wm*)(mod->wm); - return xrdp_painter_draw_text2(p, wm->screen, font, flags, + return xrdp_painter_draw_text2(p, wm->target_surface, font, flags, mixmode, clip_left, clip_top, clip_right, clip_bottom, box_left, box_top, @@ -1586,3 +1591,126 @@ server_send_to_channel(struct xrdp_mod* mod, int channel_id, return libxrdp_send_to_channel(wm->session, channel_id, data, data_len, total_data_len, flags); } + +/*****************************************************************************/ +int DEFAULT_CC +server_create_os_surface(struct xrdp_mod* mod, int id, + int width, int height) +{ + struct xrdp_wm* wm; + struct xrdp_bitmap* bitmap; + int index; + + //g_writeln("server_create_os_surface: id 0x%x, width %d height %d", + // id, width, height); + wm = (struct xrdp_wm*)(mod->wm); + bitmap = xrdp_bitmap_create(width, height, wm->screen->bpp, + WND_TYPE_OFFSCREEN, wm); + bitmap->id = id; + index = xrdp_cache_add_os_bitmap(wm->cache, bitmap, id); + if (index < 0) + { + g_writeln("server_create_os_surface: xrdp_cache_add_os_bitmap failed"); + return 1; + } + bitmap->item_index = index; + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_switch_os_surface(struct xrdp_mod* mod, int id) +{ + struct xrdp_wm* wm; + struct xrdp_os_bitmap_item* bi; + + //g_writeln("server_switch_os_surface: id 0x%x", id); + wm = (struct xrdp_wm*)(mod->wm); + if (id == -1) + { + //g_writeln("server_switch_os_surface: setting target_surface to screen"); + wm->target_surface = wm->screen; + return 0; + } + bi = xrdp_cache_get_os_bitmap(wm->cache, id); + if (bi != 0) + { + //g_writeln("server_switch_os_surface: setting target_surface to rdpid %d", id); + wm->target_surface = bi->bitmap; + } + else + { + g_writeln("server_switch_os_surface: error finding id 0x%x", id); + } + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_delete_os_surface(struct xrdp_mod* mod, int id) +{ + struct xrdp_wm* wm; + + //g_writeln("server_delete_os_surface: id 0x%x", id); + wm = (struct xrdp_wm*)(mod->wm); + if (wm->target_surface->type == WND_TYPE_OFFSCREEN) + { + if (wm->target_surface->id == id) + { + g_writeln("server_delete_os_surface: setting target_surface to screen"); + wm->target_surface = wm->screen; + } + } + xrdp_cache_remove_os_bitmap(wm->cache, id); + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_paint_rect_os(struct xrdp_mod* mod, int x, int y, int cx, int cy, + int id, int srcx, int srcy) +{ + struct xrdp_wm* wm; + struct xrdp_bitmap* b; + struct xrdp_painter* p; + struct xrdp_os_bitmap_item* bi; + + p = (struct xrdp_painter*)(mod->painter); + if (p == 0) + { + return 0; + } + wm = (struct xrdp_wm*)(mod->wm); + bi = xrdp_cache_get_os_bitmap(wm->cache, id); + if (bi != 0) + { + b = bi->bitmap; + xrdp_painter_copy(p, b, wm->target_surface, x, y, cx, cy, srcx, srcy); + } + else + { + g_writeln("server_paint_rect_os: error finding id 0x%x", id); + } + return 0; +} + +/*****************************************************************************/ +int DEFAULT_CC +server_set_hints(struct xrdp_mod* mod, int hints, int mask) +{ + struct xrdp_wm* wm; + + wm = (struct xrdp_wm*)(mod->wm); + if (mask & 1) + { + if (hints & 1) + { + wm->hints |= 1; + } + else + { + wm->hints &= ~1; + } + } + return 0; +} diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 38644ae1..117d68a4 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -14,7 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. xrdp: A Remote Desktop Protocol server. - Copyright (C) Jay Sorg 2004-2010 + Copyright (C) Jay Sorg 2004-2012 painter, gc @@ -51,11 +51,42 @@ xrdp_painter_delete(struct xrdp_painter* self) int APP_CC xrdp_painter_begin_update(struct xrdp_painter* self) { + int surface_index; + if (self == 0) { return 0; } libxrdp_orders_init(self->session); + + if (self->wm->target_surface->type == WND_TYPE_SCREEN) + { + if (self->wm->current_surface_index != 0xffff) + { + libxrdp_orders_send_switch_os_surface(self->session, 0xffff); + self->wm->current_surface_index = 0xffff; + } + } + else if (self->wm->target_surface->type == WND_TYPE_OFFSCREEN) + { + surface_index = self->wm->target_surface->item_index; + if (surface_index != self->wm->current_surface_index) + { + if (self->wm->target_surface->tab_stop == 0) /* tab_stop is hack */ + { + libxrdp_orders_send_create_os_surface(self->session, surface_index, + self->wm->target_surface->width, + self->wm->target_surface->height); + self->wm->target_surface->tab_stop = 1; + } + libxrdp_orders_send_switch_os_surface(self->session, surface_index); + self->wm->current_surface_index = surface_index; + } + } + else + { + g_writeln("xrdp_painter_begin_update: bad target_surface"); + } return 0; } @@ -271,7 +302,7 @@ xrdp_painter_setup_brush(struct xrdp_painter* self, /* fill in an area of the screen with one color */ int APP_CC xrdp_painter_fill_rect(struct xrdp_painter* self, - struct xrdp_bitmap* bitmap, + struct xrdp_bitmap* dst, int x, int y, int cx, int cy) { struct xrdp_rect clip_rect; @@ -291,14 +322,21 @@ xrdp_painter_fill_rect(struct xrdp_painter* self, /* todo data */ - if (bitmap->type == WND_TYPE_BITMAP) /* 0 */ + if (dst->type == WND_TYPE_BITMAP) /* 0 */ { return 0; } - xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - xrdp_wm_get_vis_region(self->wm, bitmap, x, y, cx, cy, region, - self->clip_children); + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, + self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } x += dx; y += dy; if (self->mix_mode == 0 && self->rop == 0xcc) @@ -372,7 +410,7 @@ xrdp_painter_fill_rect(struct xrdp_painter* self, /*****************************************************************************/ int APP_CC xrdp_painter_draw_text(struct xrdp_painter* self, - struct xrdp_bitmap* bitmap, + struct xrdp_bitmap* dst, int x, int y, const char* text) { int i; @@ -409,7 +447,7 @@ xrdp_painter_draw_text(struct xrdp_painter* self, /* todo data */ - if (bitmap->type == 0) + if (dst->type == 0) { return 0; } @@ -439,10 +477,17 @@ xrdp_painter_draw_text(struct xrdp_painter* self, total_width += k; total_height = MAX(total_height, font_item->height); } - xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - xrdp_wm_get_vis_region(self->wm, bitmap, x, y, total_width, total_height, - region, self->clip_children); + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, total_width, total_height, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } x += dx; y += dy; k = 0; @@ -470,7 +515,7 @@ xrdp_painter_draw_text(struct xrdp_painter* self, /*****************************************************************************/ int APP_CC xrdp_painter_draw_text2(struct xrdp_painter* self, - struct xrdp_bitmap* bitmap, + struct xrdp_bitmap* dst, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, @@ -493,24 +538,32 @@ xrdp_painter_draw_text2(struct xrdp_painter* self, /* todo data */ - if (bitmap->type == WND_TYPE_BITMAP) + if (dst->type == WND_TYPE_BITMAP) { return 0; } - xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - if (box_right - box_left > 1) + if (dst->type != WND_TYPE_OFFSCREEN) { - xrdp_wm_get_vis_region(self->wm, bitmap, box_left, box_top, - box_right - box_left, box_bottom - box_top, - region, self->clip_children); + if (box_right - box_left > 1) + { + xrdp_wm_get_vis_region(self->wm, dst, box_left, box_top, + box_right - box_left, box_bottom - box_top, + region, self->clip_children); + } + else + { + xrdp_wm_get_vis_region(self->wm, dst, clip_left, clip_top, + clip_right - clip_left, clip_bottom - clip_top, + region, self->clip_children); + } } else { - xrdp_wm_get_vis_region(self->wm, bitmap, clip_left, clip_top, - clip_right - clip_left, clip_bottom - clip_top, - region, self->clip_children); + xrdp_region_add_rect(region, &clip_rect); } + clip_left += dx; clip_top += dy; clip_right += dx; @@ -577,12 +630,19 @@ xrdp_painter_copy(struct xrdp_painter* self, { return 0; } - if (src == dst && src->wm->screen == src) + if (src->type == WND_TYPE_SCREEN) { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, - region, self->clip_children); + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } x += dx; y += dy; srcx += dx; @@ -599,13 +659,61 @@ xrdp_painter_copy(struct xrdp_painter* self, } xrdp_region_delete(region); } + else if (src->type == WND_TYPE_OFFSCREEN) + { + //g_writeln("xrdp_painter_copy: todo"); + + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); + region = xrdp_region_create(self->wm); + if (dst->type != WND_TYPE_OFFSCREEN) + { + g_writeln("off screen to screen"); + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); + } + else + { + g_writeln("off screen to off screen"); + xrdp_region_add_rect(region, &clip_rect); + } + x += dx; + y += dy; + + palette_id = 0; + cache_id = 255; // todo + cache_idx = src->item_index; // todo + + k = 0; + while (xrdp_region_get_rect(region, k, &rect1) == 0) + { + if (rect_intersect(&rect1, &clip_rect, &rect2)) + { + MAKERECT(rect1, x, y, cx, cy); + if (rect_intersect(&rect2, &rect1, &draw_rect)) + { + libxrdp_orders_mem_blt(self->session, cache_id, palette_id, + x, y, cx, cy, self->rop, srcx, srcy, + cache_idx, &draw_rect); + } + } + k++; + } + xrdp_region_delete(region); + } else if (src->data != 0) /* todo, the non bitmap cache part is gone, it should be put back */ { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, - region, self->clip_children); + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } x += dx; y += dy; palette_id = 0; @@ -615,11 +723,11 @@ xrdp_painter_copy(struct xrdp_painter* self, i = srcx; while (i < (srcx + cx)) { - w = MIN(64, (srcx + cx) - i); - h = MIN(64, (srcy + cy) - j); + w = MIN(64, ((srcx + cx) - i)); + h = MIN(64, ((srcy + cy) - j)); b = xrdp_bitmap_create(w, h, self->wm->screen->bpp, 0, self->wm); xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h); - bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b); + bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b, self->wm->hints); cache_id = HIWORD(bitmap_id); cache_idx = LOWORD(bitmap_id); dstx = (x + i) - srcx; @@ -651,7 +759,7 @@ xrdp_painter_copy(struct xrdp_painter* self, /*****************************************************************************/ int APP_CC xrdp_painter_line(struct xrdp_painter* self, - struct xrdp_bitmap* bitmap, + struct xrdp_bitmap* dst, int x1, int y1, int x2, int y2) { struct xrdp_rect clip_rect; @@ -670,15 +778,22 @@ xrdp_painter_line(struct xrdp_painter* self, /* todo data */ - if (bitmap->type == WND_TYPE_BITMAP) + if (dst->type == WND_TYPE_BITMAP) { return 0; } - xrdp_bitmap_get_screen_clip(bitmap, self, &clip_rect, &dx, &dy); + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); - xrdp_wm_get_vis_region(self->wm, bitmap, MIN(x1, x2), MIN(y1, y2), - g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, - region, self->clip_children); + if (dst->type != WND_TYPE_OFFSCREEN) + { + xrdp_wm_get_vis_region(self->wm, dst, MIN(x1, x2), MIN(y1, y2), + g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, + region, self->clip_children); + } + else + { + xrdp_region_add_rect(region, &clip_rect); + } x1 += dx; y1 += dy; x2 += dx; diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 3c5decf6..73bb066c 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -80,7 +80,15 @@ struct xrdp_mod char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct xrdp_mod* v); - long server_dumby[100 - 25]; /* align, 100 minus the number of server + int (*server_create_os_surface)(struct xrdp_mod* v, int id, + int width, int height); + int (*server_switch_os_surface)(struct xrdp_mod* v, int id); + int (*server_delete_os_surface)(struct xrdp_mod* v, int id); + int (*server_paint_rect_os)(struct xrdp_mod* mod, int x, int y, + int cx, int cy, + int id, int srcx, int srcy); + int (*server_set_hints)(struct xrdp_mod* mod, int hints, int mask); + long server_dumby[100 - 30]; /* align, 100 minus the number of server functions above */ /* common */ long handle; /* pointer to self as int */ @@ -274,6 +282,9 @@ struct xrdp_wm struct xrdp_font* default_font; struct xrdp_keymap keymap; int hide_log_window; + struct xrdp_bitmap* target_surface; /* either screen or os surface */ + int current_surface_index; + int hints; }; /* rdp process */ diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 7d15c3d0..3f9d3c6e 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -56,6 +56,8 @@ xrdp_wm_create(struct xrdp_process* owner, /* this will use built in keymap or load from file */ get_keymaps(self->session->client_info->keylayout, &(self->keymap)); xrdp_wm_set_login_mode(self, 0); + self->target_surface = self->screen; + self->current_surface_index = 0xffff; /* screen */ return self; } diff --git a/xup/xup.c b/xup/xup.c index 28c1b50c..5d729c6b 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -377,6 +377,9 @@ lib_mod_process_orders(struct mod* mod, int type, struct stream* s) int y1; int x2; int y2; + int rdpid; + int hints; + int mask; int width; int height; int fgcolor; @@ -462,6 +465,36 @@ lib_mod_process_orders(struct mod* mod, int type, struct stream* s) in_uint8a(s, cur_mask, 32 * (32 / 8)); rv = mod->server_set_cursor(mod, x, y, cur_data, cur_mask); break; + case 20: + in_uint32_le(s, rdpid); + in_uint16_le(s, width); + in_uint16_le(s, height); + rv = mod->server_create_os_surface(mod, rdpid, width, height); + break; + case 21: + in_uint32_le(s, rdpid); + rv = mod->server_switch_os_surface(mod, rdpid); + break; + case 22: + in_uint32_le(s, rdpid); + rv = mod->server_delete_os_surface(mod, rdpid); + break; + case 23: /* server_paint_rect_os */ + in_sint16_le(s, x); + in_sint16_le(s, y); + in_uint16_le(s, cx); + in_uint16_le(s, cy); + in_uint32_le(s, rdpid); + in_sint16_le(s, srcx); + in_sint16_le(s, srcy); + rv = mod->server_paint_rect_os(mod, x, y, cx, cy, + rdpid, srcx, srcy); + break; + case 24: /* server_set_hints */ + in_uint32_le(s, hints); + in_uint32_le(s, mask); + rv = mod->server_set_hints(mod, hints, mask); + break; default: g_writeln("lib_mod_process_orders: unknown order type %d", type); rv = 0; diff --git a/xup/xup.h b/xup/xup.h index 26d893af..9e0a4489 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -88,7 +88,15 @@ struct mod char* data, int data_len, int total_data_len, int flags); int (*server_bell_trigger)(struct mod* v); - tbus server_dumby[100 - 25]; /* align, 100 minus the number of server + int (*server_create_os_surface)(struct mod* v, int id, + int width, int height); + int (*server_switch_os_surface)(struct mod* v, int id); + int (*server_delete_os_surface)(struct mod* v, int id); + int (*server_paint_rect_os)(struct mod* v, int x, int y, + int cx, int cy, + int id, int srcx, int srcy); + int (*server_set_hints)(struct mod* v, int hints, int mask); + tbus server_dumby[100 - 30]; /* align, 100 minus the number of server functions above */ /* common */ tbus handle; /* pointer to self as long */ -- cgit v1.2.1