X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=8d27c94b6b1e6956a52d3dcca34cf94ee9536540;hb=1b2751f5c24ca06afbb68e41e73fc9fce6c6b521;hp=23a43c18169c1124b6568d1c45bb078daf261164;hpb=5dc48af29e9972527767977be3bbc9c072cf1c13;p=st.git diff --git a/st.c b/st.c index 23a43c1..8d27c94 100644 --- a/st.c +++ b/st.c @@ -36,6 +36,7 @@ char *argv0; #define Draw XftDraw * #define Colour XftColor #define Colourmap Colormap +#define Rectangle XRectangle #if defined(__linux) #include @@ -85,6 +86,7 @@ enum glyph_attribute { ATTR_GFX = 8, ATTR_ITALIC = 16, ATTR_BLINK = 32, + ATTR_WRAP = 64, }; enum cursor_movement { @@ -98,11 +100,6 @@ enum cursor_state { CURSOR_ORIGIN = 2 }; -enum glyph_state { - GLYPH_SET = 1, - GLYPH_DIRTY = 2 -}; - enum term_mode { MODE_WRAP = 1, MODE_INSERT = 2, @@ -118,6 +115,7 @@ enum term_mode { MODE_ECHO = 1024, MODE_APPCURSOR = 2048, MODE_MOUSESGR = 4096, + MODE_8BIT = 8192, }; enum escape_state { @@ -140,6 +138,11 @@ enum selection_type { SEL_RECTANGULAR = 2 }; +enum selection_snap { + SNAP_WORD = 1, + SNAP_LINE = 2 +}; + /* bit macro */ #undef B0 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; @@ -154,7 +157,6 @@ typedef struct { uchar mode; /* attribute flags */ ushort fg; /* foreground */ ushort bg; /* background */ - uchar state; /* state flags */ } Glyph; typedef Glyph *Line; @@ -238,6 +240,7 @@ typedef struct { typedef struct { int mode; int type; + int snap; int bx, by; int ex, ey; struct { @@ -310,7 +313,7 @@ static void strhandle(void); static void strparse(void); static void strreset(void); -static void tclearregion(int, int, int, int, int); +static void tclearregion(int, int, int, int); static void tcursor(int); static void tdeletechar(int); static void tdeleteline(int); @@ -378,6 +381,7 @@ static void selinit(void); static inline bool selected(int, int); static void selcopy(void); static void selscroll(int, int); +static void selsnap(int, int *, int *, int); static int utf8decode(char *, long *); static int utf8encode(long *, char *); @@ -664,6 +668,23 @@ selected(int x, int y) { } void +selsnap(int mode, int *x, int *y, int direction) { + switch(mode) { + case SNAP_WORD: + while(*x > 0 && *x < term.col-1 + && term.line[*y][*x + direction].c[0] != ' ') { + *x += direction; + } + break; + case SNAP_LINE: + *x = (direction < 0) ? 0 : term.col - 1; + break; + default: + break; + } +} + +void getbuttoninfo(XEvent *e) { int type; uint state = e->xbutton.state &~Button1Mask; @@ -673,6 +694,15 @@ getbuttoninfo(XEvent *e) { sel.ex = x2col(e->xbutton.x); sel.ey = y2row(e->xbutton.y); + if (sel.by < sel.ey + || (sel.by == sel.ey && sel.bx < sel.ex)) { + selsnap(sel.snap, &sel.bx, &sel.by, -1); + selsnap(sel.snap, &sel.ex, &sel.ey, +1); + } else { + selsnap(sel.snap, &sel.ex, &sel.ey, -1); + selsnap(sel.snap, &sel.bx, &sel.by, +1); + } + sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; sel.b.y = MIN(sel.by, sel.ey); sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; @@ -736,9 +766,14 @@ mousereport(XEvent *e) { void bpress(XEvent *e) { + struct timeval now; + if(IS_SET(MODE_MOUSE)) { mousereport(e); } else if(e->xbutton.button == Button1) { + gettimeofday(&now, NULL); + + /* Clear previous selection, logically and visually. */ if(sel.bx != -1) { sel.bx = -1; tsetdirt(sel.b.y, sel.e.y); @@ -748,6 +783,36 @@ bpress(XEvent *e) { sel.type = SEL_REGULAR; sel.ex = sel.bx = x2col(e->xbutton.x); sel.ey = sel.by = y2row(e->xbutton.y); + + /* + * If the user clicks below predefined timeouts specific + * snapping behaviour is exposed. + */ + if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { + sel.snap = SNAP_LINE; + } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { + sel.snap = SNAP_WORD; + } else { + sel.snap = 0; + } + selsnap(sel.snap, &sel.bx, &sel.by, -1); + selsnap(sel.snap, &sel.ex, &sel.ey, 1); + sel.b.x = sel.bx; + sel.b.y = sel.by; + sel.e.x = sel.ex; + sel.e.y = sel.ey; + + /* + * Draw selection, unless it's regular and we don't want to + * make clicks visible + */ + if(sel.snap != 0) { + sel.mode++; + tsetdirt(sel.b.y, sel.e.y); + draw(); + } + sel.tclick2 = sel.tclick1; + sel.tclick1 = now; } else if(e->xbutton.button == Button4) { ttywrite("\031", 1); } else if(e->xbutton.button == Button5) { @@ -757,8 +822,8 @@ bpress(XEvent *e) { void selcopy(void) { - char *str, *ptr, *p; - int x, y, bufsize, isselected = 0, size; + char *str, *ptr; + int x, y, bufsize, size; Glyph *gp, *last; if(sel.bx == -1) { @@ -769,23 +834,19 @@ selcopy(void) { /* append every set & selected glyph to the selection */ for(y = sel.b.y; y < sel.e.y + 1; y++) { - isselected = 0; gp = &term.line[y][0]; last = gp + term.col; - while(--last >= gp && !(last->state & GLYPH_SET)) + while(--last >= gp && !(selected(last - gp, y) && \ + strcmp(last->c, " ") != 0)) /* nothing */; for(x = 0; gp <= last; x++, ++gp) { - if(!selected(x, y)) { + if(!selected(x, y)) continue; - } else { - isselected = 1; - } - p = (gp->state & GLYPH_SET) ? gp->c : " "; - size = utf8size(p); - memcpy(ptr, p, size); + size = utf8size(gp->c); + memcpy(ptr, gp->c, size); ptr += size; } @@ -798,7 +859,7 @@ selcopy(void) { * st. * FIXME: Fix the computer world. */ - if(isselected && y < sel.e.y) + if(y < sel.e.y && !((gp-1)->mode & ATTR_WRAP)) *ptr++ = '\n'; } *ptr = 0; @@ -916,8 +977,6 @@ xsetsel(char *str) { void brelease(XEvent *e) { - struct timeval now; - if(IS_SET(MODE_MOUSE)) { mousereport(e); return; @@ -926,42 +985,15 @@ brelease(XEvent *e) { if(e->xbutton.button == Button2) { selpaste(NULL); } else if(e->xbutton.button == Button1) { - sel.mode = 0; - getbuttoninfo(e); - term.dirty[sel.ey] = 1; - if(sel.bx == sel.ex && sel.by == sel.ey) { + if(sel.mode < 2) { sel.bx = -1; - gettimeofday(&now, NULL); - - if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { - /* triple click on the line */ - sel.b.x = sel.bx = 0; - sel.e.x = sel.ex = term.col; - sel.b.y = sel.e.y = sel.ey; - selcopy(); - } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { - /* double click to select word */ - sel.bx = sel.ex; - while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET && - term.line[sel.ey][sel.bx-1].c[0] != ' ') { - sel.bx--; - } - sel.b.x = sel.bx; - while(sel.ex < term.col-1 && term.line[sel.ey][sel.ex+1].state & GLYPH_SET && - term.line[sel.ey][sel.ex+1].c[0] != ' ') { - sel.ex++; - } - sel.e.x = sel.ex; - sel.b.y = sel.e.y = sel.ey; - selcopy(); - } } else { + getbuttoninfo(e); selcopy(); } + sel.mode = 0; + term.dirty[sel.ey] = 1; } - - memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval)); - gettimeofday(&sel.tclick1, NULL); } void @@ -976,6 +1008,7 @@ bmotion(XEvent *e) { if(!sel.mode) return; + sel.mode++; oldey = sel.ey; oldex = sel.ex; oldsby = sel.b.y; @@ -1187,30 +1220,17 @@ treset(void) { term.bot = term.row - 1; term.mode = MODE_WRAP; - tclearregion(0, 0, term.col-1, term.row-1, 0); + tclearregion(0, 0, term.col-1, term.row-1); tmoveto(0, 0); tcursor(CURSOR_SAVE); } void tnew(int col, int row) { - /* set screen size */ - term.row = row; - term.col = col; - term.line = xmalloc(term.row * sizeof(Line)); - term.alt = xmalloc(term.row * sizeof(Line)); - term.dirty = xmalloc(term.row * sizeof(*term.dirty)); - term.tabs = xmalloc(term.col * sizeof(*term.tabs)); - - for(row = 0; row < term.row; row++) { - term.line[row] = xmalloc(term.col * sizeof(Glyph)); - term.alt [row] = xmalloc(term.col * sizeof(Glyph)); - term.dirty[row] = 0; - } - + memset(&term, 0, sizeof(Term)); + tresize(col, row); term.numlock = 1; - memset(term.tabs, 0, term.col * sizeof(*term.tabs)); - /* setup screen */ + treset(); } @@ -1231,7 +1251,7 @@ tscrolldown(int orig, int n) { LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, term.bot-n+1, term.col-1, term.bot, 0); + tclearregion(0, term.bot-n+1, term.col-1, term.bot); for(i = term.bot; i >= orig+n; i--) { temp = term.line[i]; @@ -1251,7 +1271,7 @@ tscrollup(int orig, int n) { Line temp; LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, orig, term.col-1, orig+n-1, 0); + tclearregion(0, orig, term.col-1, orig+n-1); for(i = orig; i <= term.bot-n; i++) { temp = term.line[i]; @@ -1385,11 +1405,10 @@ tsetchar(char *c, Glyph *attr, int x, int y) { term.dirty[y] = 1; term.line[y][x] = *attr; memcpy(term.line[y][x].c, c, UTF_SIZ); - term.line[y][x].state |= GLYPH_SET; } void -tclearregion(int x1, int y1, int x2, int y2, int bce) { +tclearregion(int x1, int y1, int x2, int y2) { int x, y, temp; if(x1 > x2) @@ -1405,13 +1424,10 @@ tclearregion(int x1, int y1, int x2, int y2, int bce) { for(y = y1; y <= y2; y++) { term.dirty[y] = 1; for(x = x1; x <= x2; x++) { - if(bce) { - term.line[y][x] = term.c.attr; - memcpy(term.line[y][x].c, " ", 2); - term.line[y][x].state |= GLYPH_SET; - } else { - term.line[y][x].state = 0; - } + if(selected(x, y)) + selclear(NULL); + term.line[y][x] = term.c.attr; + memcpy(term.line[y][x].c, " ", 2); } } } @@ -1425,13 +1441,13 @@ tdeletechar(int n) { term.dirty[term.c.y] = 1; if(src >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(term.col-n, term.c.y, term.col-1, term.c.y, 0); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); } void @@ -1443,13 +1459,13 @@ tinsertblank(int n) { term.dirty[term.c.y] = 1; if(dst >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst - 1, term.c.y, 0); + tclearregion(src, term.c.y, dst - 1, term.c.y); } void @@ -1475,8 +1491,9 @@ tsetattr(int *attr, int l) { for(i = 0; i < l; i++) { switch(attr[i]) { case 0: - term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \ - | ATTR_ITALIC | ATTR_BLINK); + term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE \ + | ATTR_BOLD | ATTR_ITALIC \ + | ATTR_BLINK); term.c.attr.fg = defaultfg; term.c.attr.bg = defaultbg; break; @@ -1636,6 +1653,9 @@ tsetmode(bool priv, bool set, int *args, int narg) { case 1006: MODBIT(term.mode, set, MODE_MOUSESGR); break; + case 1034: + MODBIT(term.mode, set, MODE_8BIT); + break; case 1049: /* = 1047 and 1048 */ case 47: case 1047: @@ -1645,7 +1665,7 @@ tsetmode(bool priv, bool set, int *args, int narg) { alt = IS_SET(MODE_ALTSCREEN); if(alt) { tclearregion(0, 0, term.col-1, - term.row-1, 0); + term.row-1); } if(set ^ alt) /* set is always 1 or 0 */ tswapscreen(); @@ -1764,19 +1784,19 @@ csihandle(void) { sel.bx = -1; switch(csiescseq.arg[0]) { case 0: /* below */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); if(term.c.y < term.row-1) { tclearregion(0, term.c.y+1, term.col-1, - term.row-1, 1); + term.row-1); } break; case 1: /* above */ if(term.c.y > 1) - tclearregion(0, 0, term.col-1, term.c.y-1, 1); - tclearregion(0, term.c.y, term.c.x, term.c.y, 1); + tclearregion(0, 0, term.col-1, term.c.y-1); + tclearregion(0, term.c.y, term.c.x, term.c.y); break; case 2: /* all */ - tclearregion(0, 0, term.col-1, term.row-1, 1); + tclearregion(0, 0, term.col-1, term.row-1); break; default: goto unknown; @@ -1786,13 +1806,13 @@ csihandle(void) { switch(csiescseq.arg[0]) { case 0: /* right */ tclearregion(term.c.x, term.c.y, term.col-1, - term.c.y, 1); + term.c.y); break; case 1: /* left */ - tclearregion(0, term.c.y, term.c.x, term.c.y, 1); + tclearregion(0, term.c.y, term.c.x, term.c.y); break; case 2: /* all */ - tclearregion(0, term.c.y, term.col-1, term.c.y, 1); + tclearregion(0, term.c.y, term.col-1, term.c.y); break; } break; @@ -1818,7 +1838,7 @@ csihandle(void) { case 'X': /* ECH -- Erase char */ DEFAULT(csiescseq.arg[0], 1); tclearregion(term.c.x, term.c.y, - term.c.x + csiescseq.arg[0] - 1, term.c.y, 1); + term.c.x + csiescseq.arg[0] - 1, term.c.y); break; case 'P': /* DCH -- Delete char */ DEFAULT(csiescseq.arg[0], 1); @@ -2259,8 +2279,10 @@ tputc(char *c, int len) { return; if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) sel.bx = -1; - if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) - tnewline(1); /* always go to first col */ + if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) { + term.line[term.c.y][term.c.x].mode |= ATTR_WRAP; + tnewline(1); + } if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) { memmove(&term.line[term.c.y][term.c.x+1], @@ -2278,11 +2300,12 @@ tputc(char *c, int len) { int tresize(int col, int row) { - int i, x; + int i; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); int slide = term.c.y - row + 1; bool *bp; + Line *orig; if(col < 1 || row < 1) return 0; @@ -2318,10 +2341,6 @@ tresize(int col, int row) { term.dirty[i] = 1; term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); - for(x = mincol; x < col; x++) { - term.line[i][x].state = 0; - term.alt[i][x].state = 0; - } } /* allocate any new rows */ @@ -2346,6 +2365,17 @@ tresize(int col, int row) { tsetscroll(0, row-1); /* make use of the LIMIT in tmoveto */ tmoveto(term.c.x, term.c.y); + /* Clearing both screens */ + orig = term.line; + do { + if(mincol < col && 0 < minrow) { + tclearregion(mincol, 0, col - 1, minrow - 1); + } + if(0 < col && minrow < row) { + tclearregion(0, minrow, col - 1, row - 1); + } + tswapscreen(); + } while(orig != term.line); return (slide > 0); } @@ -2358,10 +2388,8 @@ xresize(int col, int row) { XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); - XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, xw.w, xw.h); } static inline ushort @@ -2738,6 +2766,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcCharSet *fccharset; Colour *fg, *bg, *temp, revfg, revbg; XRenderColor colfg, colbg; + Rectangle r; frcflags = FRC_NORMAL; @@ -2826,6 +2855,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { /* Clean up the region we want to draw to. */ XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch); + /* Set the clip region because Xft is sometimes dirty. */ + r.x = 0; + r.y = 0; + r.height = xw.ch; + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + fcsets[0] = font->set; for(xp = winx; bytelen > 0;) { /* @@ -2859,6 +2895,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { (FcChar8 *)u8fs, u8fblen); xp += font->width * u8fl; + } break; } @@ -2943,39 +2980,56 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1, width, 1); } + + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); } void xdrawcursor(void) { static int oldx = 0, oldy = 0; int sl; - Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs, 0}; + Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); - if(term.line[term.c.y][term.c.x].state & GLYPH_SET) - memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); + memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); /* remove the old cursor */ - if(term.line[oldy][oldx].state & GLYPH_SET) { - sl = utf8size(term.line[oldy][oldx].c); - xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, - oldy, 1, sl); - } else { - xtermclear(oldx, oldy, oldx, oldy); - } + sl = utf8size(term.line[oldy][oldx].c); + xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, + oldy, 1, sl); /* draw the new one */ if(!(IS_SET(MODE_HIDE))) { - if(!(xw.state & WIN_FOCUSED)) - g.bg = defaultucs; - - if(IS_SET(MODE_REVERSE)) - g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg = defaultfg; + if(xw.state & WIN_FOCUSED) { + if(IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.fg = defaultcs; + g.bg = defaultfg; + } - sl = utf8size(g.c); - xdraws(g.c, g, term.c.x, term.c.y, 1, sl); + sl = utf8size(g.c); + xdraws(g.c, g, term.c.x, term.c.y, 1, sl); + } else { + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + term.c.x * xw.cw, + borderpx + term.c.y * xw.ch, + xw.cw - 1, 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + term.c.x * xw.cw, + borderpx + term.c.y * xw.ch, + 1, xw.ch - 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + (term.c.x + 1) * xw.cw - 1, + borderpx + term.c.y * xw.ch, + 1, xw.ch - 1); + XftDrawRect(xw.draw, &dc.col[defaultcs], + borderpx + term.c.x * xw.cw, + borderpx + (term.c.y + 1) * xw.ch - 1, + xw.cw, 1); + } oldx = term.c.x, oldy = term.c.y; } } @@ -3041,25 +3095,22 @@ drawregion(int x1, int y1, int x2, int y2) { ic = ib = ox = 0; for(x = x1; x < x2; x++) { new = term.line[y][x]; - if(ena_sel && *(new.c) && selected(x, y)) + if(ena_sel && selected(x, y)) new.mode ^= ATTR_REVERSE; - if(ib > 0 && (!(new.state & GLYPH_SET) - || ATTRCMP(base, new) + if(ib > 0 && (ATTRCMP(base, new) || ib >= DRAW_BUF_SIZ-UTF_SIZ)) { xdraws(buf, base, ox, y, ic, ib); ic = ib = 0; } - if(new.state & GLYPH_SET) { - if(ib == 0) { - ox = x; - base = new; - } - - sl = utf8size(new.c); - memcpy(buf+ib, new.c, sl); - ib += sl; - ++ic; + if(ib == 0) { + ox = x; + base = new; } + + sl = utf8size(new.c); + memcpy(buf+ib, new.c, sl); + ib += sl; + ++ic; } if(ib > 0) xdraws(buf, base, ox, y, ic, ib); @@ -3195,7 +3246,8 @@ kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; char xstr[31], buf[32], *customkey, *cp = buf; - int len; + int len, ret; + long c; Status status; Shortcut *bp; @@ -3216,13 +3268,23 @@ kpress(XEvent *ev) { if((customkey = kmap(ksym, e->state))) { len = strlen(customkey); memcpy(buf, customkey, len); - /* 2. hardcoded (overrides X lookup) */ + /* 3. hardcoded (overrides X lookup) */ } else { if(len == 0) return; - if(len == 1 && e->state & Mod1Mask) - *cp++ = '\033'; + if(len == 1 && e->state & Mod1Mask) { + if(IS_SET(MODE_8BIT)) { + if(*xstr < 0177) { + c = *xstr | B7; + ret = utf8encode(&c, cp); + cp += ret; + len = 0; + } + } else { + *cp++ = '\033'; + } + } memcpy(cp, xstr, len); len = cp - buf + len; @@ -3400,6 +3462,8 @@ run: xinit(); ttynew(); selinit(); + if(xw.isfixed) + cresize(xw.h, xw.w); run(); return 0;