fix(popup): fit the current X11 monitor
This commit is contained in:
5
Makefile
5
Makefile
@@ -6,6 +6,8 @@ XIM_CFLAGS = $(shell pkg-config --cflags xcb-imdkit xkbcommon-x11)
|
|||||||
XIM_LIBS = $(shell pkg-config --libs xcb-imdkit xkbcommon-x11)
|
XIM_LIBS = $(shell pkg-config --libs xcb-imdkit xkbcommon-x11)
|
||||||
TEXT_CFLAGS = $(shell pkg-config --cflags pangocairo cairo)
|
TEXT_CFLAGS = $(shell pkg-config --cflags pangocairo cairo)
|
||||||
TEXT_LIBS = $(shell pkg-config --libs pangocairo cairo)
|
TEXT_LIBS = $(shell pkg-config --libs pangocairo cairo)
|
||||||
|
POPUP_CFLAGS = $(shell pkg-config --cflags xcb-randr)
|
||||||
|
POPUP_LIBS = $(shell pkg-config --libs xcb-randr)
|
||||||
CFLAGS = -Wall -Wextra -O2 -g $(PKG_CFLAGS)
|
CFLAGS = -Wall -Wextra -O2 -g $(PKG_CFLAGS)
|
||||||
PROG = strans
|
PROG = strans
|
||||||
DOCKER_IMAGE = strans-build
|
DOCKER_IMAGE = strans-build
|
||||||
@@ -22,10 +24,11 @@ all: $(PROG) gtk
|
|||||||
|
|
||||||
$(PROG): $(OBJS)
|
$(PROG): $(OBJS)
|
||||||
$(LD) -o $@ $(OBJS) -lthread -lbio -lxcb $(PKG_LIBS) $(TEXT_LIBS) \
|
$(LD) -o $@ $(OBJS) -lthread -lbio -lxcb $(PKG_LIBS) $(TEXT_LIBS) \
|
||||||
$(XIM_LIBS)
|
$(XIM_LIBS) $(POPUP_LIBS)
|
||||||
|
|
||||||
$(OBJS): dat.h fn.h ipc.h
|
$(OBJS): dat.h fn.h ipc.h
|
||||||
font.o: CFLAGS += $(TEXT_CFLAGS)
|
font.o: CFLAGS += $(TEXT_CFLAGS)
|
||||||
|
win.o: CFLAGS += $(POPUP_CFLAGS)
|
||||||
$(XIMOBJS): CFLAGS += -I. $(XIM_CFLAGS)
|
$(XIMOBJS): CFLAGS += -I. $(XIM_CFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
12
dat.h
12
dat.h
@@ -22,6 +22,7 @@ enum
|
|||||||
PopupSep = 1,
|
PopupSep = 1,
|
||||||
PopupNumw = Fontsz,
|
PopupNumw = Fontsz,
|
||||||
PopupTextw = 12*Fontsz,
|
PopupTextw = 12*Fontsz,
|
||||||
|
PopupBasew = 2*PopupPad + PopupNumw + PopupTextw,
|
||||||
Maxrunes = 64,
|
Maxrunes = 64,
|
||||||
Maxutf = Maxrunes * UTFmax + 1,
|
Maxutf = Maxrunes * UTFmax + 1,
|
||||||
};
|
};
|
||||||
@@ -31,7 +32,6 @@ enum
|
|||||||
Maxclients = 64,
|
Maxclients = 64,
|
||||||
Maxkouho = 32,
|
Maxkouho = 32,
|
||||||
Maxdisp = 9,
|
Maxdisp = 9,
|
||||||
Imgw = 2*PopupPad + PopupNumw + PopupTextw,
|
|
||||||
Imgh = 2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep,
|
Imgh = 2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep,
|
||||||
|
|
||||||
Colfg = 0x000000,
|
Colfg = 0x000000,
|
||||||
@@ -124,6 +124,15 @@ struct Im
|
|||||||
|
|
||||||
typedef struct Drawcmd Drawcmd;
|
typedef struct Drawcmd Drawcmd;
|
||||||
typedef struct Caret Caret;
|
typedef struct Caret Caret;
|
||||||
|
typedef struct Area Area;
|
||||||
|
struct Area
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int w;
|
||||||
|
int h;
|
||||||
|
};
|
||||||
|
|
||||||
struct Caret
|
struct Caret
|
||||||
{
|
{
|
||||||
int valid;
|
int valid;
|
||||||
@@ -149,6 +158,7 @@ struct Popup
|
|||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
int n;
|
int n;
|
||||||
|
int row0;
|
||||||
int prey;
|
int prey;
|
||||||
int sepy;
|
int sepy;
|
||||||
int rowsy;
|
int rowsy;
|
||||||
|
|||||||
6
fn.h
6
fn.h
@@ -28,9 +28,10 @@ void dictthread(void*);
|
|||||||
void dictlookup(Dictreq*, Dictres*);
|
void dictlookup(Dictreq*, Dictres*);
|
||||||
|
|
||||||
void drawthread(void*);
|
void drawthread(void*);
|
||||||
void popupposition(Caret*, int, int, int, int, int, int, int*, int*);
|
void popuparea(Area*, int, Area*, int, int, Area*);
|
||||||
|
void popupposition(Caret*, int, int, Area*, int, int, int*, int*);
|
||||||
int pagemarker(char*, int, int, int, int);
|
int pagemarker(char*, int, int, int, int);
|
||||||
void popuplayout(Drawcmd*, int, Popup*);
|
void popuplayout(Drawcmd*, int, int, Popup*);
|
||||||
void popupdraw(u32int*, Drawcmd*, Popup*);
|
void popupdraw(u32int*, Drawcmd*, Popup*);
|
||||||
void imthread(void*);
|
void imthread(void*);
|
||||||
Emit transmap(Im*, Rune);
|
Emit transmap(Im*, Rune);
|
||||||
@@ -49,6 +50,7 @@ void* emalloc(ulong);
|
|||||||
void* erealloc(void*, ulong);
|
void* erealloc(void*, ulong);
|
||||||
|
|
||||||
int textinit(void);
|
int textinit(void);
|
||||||
|
void textclose(void);
|
||||||
int textwidth(Str*);
|
int textwidth(Str*);
|
||||||
void textdraw(u32int*, int, int, int, int, Str*);
|
void textdraw(u32int*, int, int, int, int, Str*);
|
||||||
void textdrawfit(u32int*, int, int, int, int, int, Str*);
|
void textdrawfit(u32int*, int, int, int, int, int, Str*);
|
||||||
|
|||||||
8
font.c
8
font.c
@@ -13,8 +13,8 @@ resetlayout(void)
|
|||||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
textclear(void)
|
textclose(void)
|
||||||
{
|
{
|
||||||
if(layout != nil)
|
if(layout != nil)
|
||||||
g_object_unref(layout);
|
g_object_unref(layout);
|
||||||
@@ -52,7 +52,7 @@ setfont(void)
|
|||||||
int
|
int
|
||||||
textinit(void)
|
textinit(void)
|
||||||
{
|
{
|
||||||
textclear();
|
textclose();
|
||||||
fontmap = pango_cairo_font_map_new();
|
fontmap = pango_cairo_font_map_new();
|
||||||
if(fontmap == nil){
|
if(fontmap == nil){
|
||||||
fprint(2, "strans: popup: can't initialize PangoCairo\n");
|
fprint(2, "strans: popup: can't initialize PangoCairo\n");
|
||||||
@@ -64,7 +64,7 @@ textinit(void)
|
|||||||
layout = pango_layout_new(context);
|
layout = pango_layout_new(context);
|
||||||
if(context == nil || layout == nil){
|
if(context == nil || layout == nil){
|
||||||
fprint(2, "strans: popup: can't create text layout\n");
|
fprint(2, "strans: popup: can't create text layout\n");
|
||||||
textclear();
|
textclose();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pango_layout_set_single_paragraph_mode(layout, TRUE);
|
pango_layout_set_single_paragraph_mode(layout, TRUE);
|
||||||
|
|||||||
179
popup_layout.c
179
popup_layout.c
@@ -28,24 +28,98 @@ fillrect(u32int *buf, int w, int h, int x, int y, int rw, int rh,
|
|||||||
fill(buf + y0*w + x0, max(x1 - x0, 0), color);
|
fill(buf + y0*w + x0, max(x1 - x0, 0), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
validarea(Area *a)
|
||||||
|
{
|
||||||
|
return a != nil && a->w > 0 && a->h > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vlong
|
||||||
|
areadistance(Area *a, int x, int y)
|
||||||
|
{
|
||||||
|
vlong dx, dy, right, bottom;
|
||||||
|
|
||||||
|
right = (vlong)a->x + a->w;
|
||||||
|
bottom = (vlong)a->y + a->h;
|
||||||
|
dx = x < a->x ? (vlong)a->x - x : x >= right ? x - right : 0;
|
||||||
|
dy = y < a->y ? (vlong)a->y - y : y >= bottom ? y - bottom : 0;
|
||||||
|
return dx + dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
popuparea(Area *mon, int nmon, Area *work, int x, int y, Area *out)
|
||||||
|
{
|
||||||
|
vlong best, bottom, d, right, x0, x1, y0, y1;
|
||||||
|
int i, pick;
|
||||||
|
|
||||||
|
memset(out, 0, sizeof *out);
|
||||||
|
pick = -1;
|
||||||
|
best = (vlong)1 << 62;
|
||||||
|
for(i = 0; i < nmon; i++){
|
||||||
|
if(!validarea(&mon[i]))
|
||||||
|
continue;
|
||||||
|
right = (vlong)mon[i].x + mon[i].w;
|
||||||
|
bottom = (vlong)mon[i].y + mon[i].h;
|
||||||
|
if(x >= mon[i].x && x < right &&
|
||||||
|
y >= mon[i].y && y < bottom){
|
||||||
|
pick = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d = areadistance(&mon[i], x, y);
|
||||||
|
if(d < best){
|
||||||
|
best = d;
|
||||||
|
pick = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pick < 0)
|
||||||
|
return;
|
||||||
|
*out = mon[pick];
|
||||||
|
if(!validarea(work))
|
||||||
|
return;
|
||||||
|
x0 = max((vlong)out->x, work->x);
|
||||||
|
y0 = max((vlong)out->y, work->y);
|
||||||
|
x1 = min((vlong)out->x + out->w, (vlong)work->x + work->w);
|
||||||
|
y1 = min((vlong)out->y + out->h, (vlong)work->y + work->h);
|
||||||
|
if(x1 <= x0 || y1 <= y0)
|
||||||
|
return;
|
||||||
|
out->x = x0;
|
||||||
|
out->y = y0;
|
||||||
|
out->w = x1 - x0;
|
||||||
|
out->h = y1 - y0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pagemarker(char *buf, int nbuf, int first, int shown, int total)
|
pagemarker(char *buf, int nbuf, int first, int shown, int total)
|
||||||
{
|
{
|
||||||
if(nbuf <= 0)
|
if(nbuf <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
buf[0] = 0;
|
buf[0] = 0;
|
||||||
if(total <= Maxdisp || shown <= 0)
|
if(shown <= 0 || (first == 0 && shown >= total))
|
||||||
return 0;
|
return 0;
|
||||||
return snprint(buf, nbuf, "%d-%d/%d", first + 1,
|
return snprint(buf, nbuf, "%d-%d/%d", first + 1,
|
||||||
first + shown, total);
|
first + shown, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fitrows(int h, int pre, int mark, int n)
|
||||||
|
{
|
||||||
|
int fixed;
|
||||||
|
|
||||||
|
fixed = 2*PopupPad + mark*Fontsz;
|
||||||
|
if(pre)
|
||||||
|
fixed += Fontsz + (n != 0 ? PopupSep : 0);
|
||||||
|
if(h <= fixed)
|
||||||
|
return 0;
|
||||||
|
return min(n, (h - fixed) / Fontsz);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
popuplayout(Drawcmd *dc, int screenw, Popup *p)
|
popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
Str mark;
|
Str mark;
|
||||||
int nmark, npre, y;
|
vlong width;
|
||||||
|
int first, i, markrow, nall, nmark, npre, pad, total, y;
|
||||||
|
|
||||||
memset(p, 0, sizeof *p);
|
memset(p, 0, sizeof *p);
|
||||||
p->prey = -1;
|
p->prey = -1;
|
||||||
@@ -54,15 +128,52 @@ popuplayout(Drawcmd *dc, int screenw, Popup *p)
|
|||||||
p->markx = -1;
|
p->markx = -1;
|
||||||
p->marky = -1;
|
p->marky = -1;
|
||||||
p->sely = -1;
|
p->sely = -1;
|
||||||
p->n = min(max(dc->nkouho, 0), Maxdisp);
|
p->row0 = 0;
|
||||||
|
pad = PopupPad;
|
||||||
|
nall = min(max(dc->nkouho, 0), Maxdisp);
|
||||||
npre = dc->pre.n != 0;
|
npre = dc->pre.n != 0;
|
||||||
if(p->n == 0 && !npre)
|
if((nall == 0 && !npre) || areaw <= 0 || areah <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->w = min(Imgw, max(screenw, 0));
|
total = max(dc->total, dc->first + nall);
|
||||||
nmark = pagemarker(buf, sizeof buf, dc->first, p->n, dc->total);
|
markrow = dc->first > 0 || nall < total;
|
||||||
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
|
if(p->n < nall && !markrow){
|
||||||
|
markrow = 1;
|
||||||
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
|
}
|
||||||
|
if(p->n == 0 && markrow){
|
||||||
|
markrow = 0;
|
||||||
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
|
}
|
||||||
|
if(p->n == 0 && npre && nall != 0){
|
||||||
|
npre = 0;
|
||||||
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
|
}
|
||||||
|
if(p->n == 0 && nall != 0){
|
||||||
|
p->n = 1;
|
||||||
|
pad = 0;
|
||||||
|
}
|
||||||
|
if(p->n != 0 && dc->sel >= p->n)
|
||||||
|
p->row0 = min(dc->sel - p->n + 1, nall - p->n);
|
||||||
|
first = dc->first + p->row0;
|
||||||
|
nmark = markrow ? pagemarker(buf, sizeof buf, first, p->n, total) : 0;
|
||||||
|
if(nmark == 0)
|
||||||
|
markrow = 0;
|
||||||
|
|
||||||
y = PopupPad;
|
width = PopupBasew;
|
||||||
|
if(npre)
|
||||||
|
width = max(width, (vlong)textwidth(&dc->pre) + 2*PopupPad);
|
||||||
|
for(i = 0; i < p->n; i++)
|
||||||
|
width = max(width, (vlong)textwidth(&dc->kouho[p->row0+i]) +
|
||||||
|
PopupNumw + 2*PopupPad);
|
||||||
|
if(nmark != 0){
|
||||||
|
sinit(&mark, buf, nmark);
|
||||||
|
width = max(width, (vlong)textwidth(&mark) + 2*PopupPad);
|
||||||
|
}
|
||||||
|
p->w = min(width, areaw);
|
||||||
|
|
||||||
|
y = pad;
|
||||||
if(npre){
|
if(npre){
|
||||||
p->prey = y;
|
p->prey = y;
|
||||||
y += Fontsz;
|
y += Fontsz;
|
||||||
@@ -75,23 +186,22 @@ popuplayout(Drawcmd *dc, int screenw, Popup *p)
|
|||||||
p->rowsy = y;
|
p->rowsy = y;
|
||||||
y += p->n*Fontsz;
|
y += p->n*Fontsz;
|
||||||
}
|
}
|
||||||
if(nmark != 0){
|
if(markrow){
|
||||||
p->marky = y;
|
p->marky = y;
|
||||||
y += Fontsz;
|
y += Fontsz;
|
||||||
}
|
}
|
||||||
p->h = y + PopupPad;
|
p->h = min(y + pad, areah);
|
||||||
p->numx = PopupPad;
|
p->numx = PopupPad;
|
||||||
p->textx = PopupPad + PopupNumw;
|
p->textx = PopupPad + PopupNumw;
|
||||||
p->textw = max(p->w - PopupPad - p->textx, 0);
|
p->textw = max(p->w - PopupPad - p->textx, 0);
|
||||||
if(nmark != 0){
|
if(markrow){
|
||||||
sinit(&mark, buf, nmark);
|
|
||||||
p->markw = min(textwidth(&mark), max(p->w - 2*PopupPad, 0));
|
p->markw = min(textwidth(&mark), max(p->w - 2*PopupPad, 0));
|
||||||
p->markx = p->w - PopupPad - p->markw;
|
p->markx = p->w - PopupPad - p->markw;
|
||||||
}
|
}
|
||||||
p->selx = PopupPad;
|
p->selx = PopupPad;
|
||||||
p->selw = max(p->w - 2*PopupPad, 0);
|
p->selw = max(p->w - 2*PopupPad, 0);
|
||||||
if(dc->sel >= 0 && dc->sel < p->n)
|
if(dc->sel >= p->row0 && dc->sel < p->row0 + p->n)
|
||||||
p->sely = p->rowsy + dc->sel*Fontsz;
|
p->sely = p->rowsy + (dc->sel - p->row0)*Fontsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -100,11 +210,11 @@ popupdraw(u32int *img, Drawcmd *dc, Popup *p)
|
|||||||
char buf[32];
|
char buf[32];
|
||||||
Str mark, num;
|
Str mark, num;
|
||||||
u32int color;
|
u32int color;
|
||||||
int i, nmark, y;
|
int first, i, j, nmark, total, y;
|
||||||
|
|
||||||
if(img == nil || p->n < 0 || p->n > Maxdisp ||
|
if(img == nil || p->n < 0 || p->n > Maxdisp ||
|
||||||
p->w <= 0 || p->w > Imgw ||
|
p->row0 < 0 || p->row0 + p->n > dc->nkouho ||
|
||||||
p->h <= 0 || p->h > Imgh)
|
p->w <= 0 || p->h <= 0 || p->h > Imgh)
|
||||||
return;
|
return;
|
||||||
fill(img, p->w*p->h, Colbg);
|
fill(img, p->w*p->h, Colbg);
|
||||||
if(p->prey >= 0)
|
if(p->prey >= 0)
|
||||||
@@ -117,16 +227,19 @@ popupdraw(u32int *img, Drawcmd *dc, Popup *p)
|
|||||||
fillrect(img, p->w, p->h, p->selx, p->sely,
|
fillrect(img, p->w, p->h, p->selx, p->sely,
|
||||||
p->selw, Fontsz, Colsel);
|
p->selw, Fontsz, Colsel);
|
||||||
for(i = 0, y = p->rowsy; i < p->n; i++, y += Fontsz){
|
for(i = 0, y = p->rowsy; i < p->n; i++, y += Fontsz){
|
||||||
color = i == dc->sel ? Colselfg : Colfg;
|
j = p->row0 + i;
|
||||||
|
color = j == dc->sel ? Colselfg : Colfg;
|
||||||
sclear(&num);
|
sclear(&num);
|
||||||
sputr(&num, '1' + i + Asciitofull);
|
sputr(&num, '1' + j + Asciitofull);
|
||||||
textdrawfitcolor(img, p->w, p->h, p->numx, y,
|
textdrawfitcolor(img, p->w, p->h, p->numx, y,
|
||||||
min(PopupNumw,
|
min(PopupNumw,
|
||||||
max(p->w - PopupPad - p->numx, 0)), color, &num);
|
max(p->w - PopupPad - p->numx, 0)), color, &num);
|
||||||
textdrawfitcolor(img, p->w, p->h, p->textx, y,
|
textdrawfitcolor(img, p->w, p->h, p->textx, y,
|
||||||
p->textw, color, &dc->kouho[i]);
|
p->textw, color, &dc->kouho[j]);
|
||||||
}
|
}
|
||||||
nmark = pagemarker(buf, sizeof buf, dc->first, p->n, dc->total);
|
first = dc->first + p->row0;
|
||||||
|
total = max(dc->total, dc->first + dc->nkouho);
|
||||||
|
nmark = pagemarker(buf, sizeof buf, first, p->n, total);
|
||||||
if(nmark != 0 && p->marky >= 0){
|
if(nmark != 0 && p->marky >= 0){
|
||||||
sinit(&mark, buf, nmark);
|
sinit(&mark, buf, nmark);
|
||||||
textdrawfit(img, p->w, p->h, p->markx, p->marky,
|
textdrawfit(img, p->w, p->h, p->markx, p->marky,
|
||||||
@@ -135,15 +248,23 @@ popupdraw(u32int *img, Drawcmd *dc, Popup *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
popupposition(Caret *caret, int pointerx, int pointery, int screenw,
|
popupposition(Caret *caret, int pointerx, int pointery, Area *area,
|
||||||
int screenh, int w, int h, int *x, int *y)
|
int w, int h, int *x, int *y)
|
||||||
{
|
{
|
||||||
vlong below, px, py, xmax, ymax;
|
vlong below, bottom, px, py, right, xmax, ymax;
|
||||||
|
|
||||||
|
if(!validarea(area)){
|
||||||
|
*x = 0;
|
||||||
|
*y = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
right = (vlong)area->x + area->w;
|
||||||
|
bottom = (vlong)area->y + area->h;
|
||||||
|
|
||||||
if(caret->valid){
|
if(caret->valid){
|
||||||
px = caret->x;
|
px = caret->x;
|
||||||
below = (vlong)caret->y + max(caret->h, 0);
|
below = (vlong)caret->y + max(caret->h, 0);
|
||||||
if(below >= 0 && below + h <= screenh)
|
if(below >= area->y && below + h <= bottom)
|
||||||
py = below;
|
py = below;
|
||||||
else
|
else
|
||||||
py = (vlong)caret->y - h;
|
py = (vlong)caret->y - h;
|
||||||
@@ -151,8 +272,8 @@ popupposition(Caret *caret, int pointerx, int pointery, int screenw,
|
|||||||
px = (vlong)pointerx + 10;
|
px = (vlong)pointerx + 10;
|
||||||
py = (vlong)pointery + 10;
|
py = (vlong)pointery + 10;
|
||||||
}
|
}
|
||||||
xmax = max((vlong)screenw - w, 0);
|
xmax = max(right - w, area->x);
|
||||||
ymax = max((vlong)screenh - h, 0);
|
ymax = max(bottom - h, area->y);
|
||||||
*x = max(0, min(px, xmax));
|
*x = max((vlong)area->x, min(px, xmax));
|
||||||
*y = max(0, min(py, ymax));
|
*y = max((vlong)area->y, min(py, ymax));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,4 +253,7 @@ font_render(struct ct *t)
|
|||||||
}
|
}
|
||||||
checkguards(t, mem);
|
checkguards(t, mem);
|
||||||
free(mem);
|
free(mem);
|
||||||
|
textclose();
|
||||||
|
textclose();
|
||||||
|
CT_EQ_INT(t, 0, textwidth(&a));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Rgbmask = 0xffffff,
|
Rgbmask = 0xffffff,
|
||||||
@@ -39,6 +38,9 @@ checkpadding(struct ct *t, u32int *img, Popup *p)
|
|||||||
void
|
void
|
||||||
popup_layout(struct ct *t)
|
popup_layout(struct ct *t)
|
||||||
{
|
{
|
||||||
|
static int tinyheight[] = {
|
||||||
|
1, PopupPad, 2*PopupPad + Fontsz - 1,
|
||||||
|
};
|
||||||
static const struct {
|
static const struct {
|
||||||
int first;
|
int first;
|
||||||
int shown;
|
int shown;
|
||||||
@@ -47,6 +49,8 @@ popup_layout(struct ct *t)
|
|||||||
} markers[] = {
|
} markers[] = {
|
||||||
{ 0, 0, 0, "" },
|
{ 0, 0, 0, "" },
|
||||||
{ 0, 9, 9, "" },
|
{ 0, 9, 9, "" },
|
||||||
|
{ 0, 3, 9, "1-3/9" },
|
||||||
|
{ 8, 1, 9, "9-9/9" },
|
||||||
{ 0, 9, 10, "1-9/10" },
|
{ 0, 9, 10, "1-9/10" },
|
||||||
{ 9, 1, 10, "10-10/10" },
|
{ 9, 1, 10, "10-10/10" },
|
||||||
{ 0, 9, 18, "1-9/18" },
|
{ 0, 9, 18, "1-9/18" },
|
||||||
@@ -56,6 +60,7 @@ popup_layout(struct ct *t)
|
|||||||
{ 27, 5, 32, "28-32/32" },
|
{ 27, 5, 32, "28-32/32" },
|
||||||
};
|
};
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
Area area, mon[2], out, work;
|
||||||
Caret caret;
|
Caret caret;
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
Popup p;
|
Popup p;
|
||||||
@@ -70,59 +75,62 @@ popup_layout(struct ct *t)
|
|||||||
CT_CHECK(t, strcmp(markers[i].want, buf) == 0);
|
CT_CHECK(t, strcmp(markers[i].want, buf) == 0);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 12*Fontsz, PopupTextw);
|
CT_EQ_INT(t, 12*Fontsz, PopupTextw);
|
||||||
CT_EQ_INT(t, 2*PopupPad + PopupNumw + PopupTextw, Imgw);
|
CT_EQ_INT(t, 2*PopupPad + PopupNumw + PopupTextw, PopupBasew);
|
||||||
CT_EQ_INT(t, 2*PopupPad + (1 + Maxdisp + 1)*Fontsz + PopupSep,
|
CT_EQ_INT(t, 2*PopupPad + (1 + Maxdisp + 1)*Fontsz + PopupSep,
|
||||||
Imgh);
|
Imgh);
|
||||||
|
|
||||||
|
/* Monitor selection retains origins and intersects the EWMH work area. */
|
||||||
|
mon[0] = (Area){0, 0, 1920, 1080};
|
||||||
|
mon[1] = (Area){1920, 200, 1280, 1024};
|
||||||
|
work = (Area){0, 30, 3200, 1070};
|
||||||
|
popuparea(mon, 2, &work, 2500, 500, &out);
|
||||||
|
CT_EQ_INT(t, 1920, out.x);
|
||||||
|
CT_EQ_INT(t, 200, out.y);
|
||||||
|
CT_EQ_INT(t, 1280, out.w);
|
||||||
|
CT_EQ_INT(t, 900, out.h);
|
||||||
|
work = (Area){60, 0, 3140, 1224};
|
||||||
|
popuparea(mon, 2, &work, 100, 100, &out);
|
||||||
|
CT_EQ_INT(t, 60, out.x);
|
||||||
|
CT_EQ_INT(t, 0, out.y);
|
||||||
|
CT_EQ_INT(t, 1860, out.w);
|
||||||
|
CT_EQ_INT(t, 1080, out.h);
|
||||||
|
work = (Area){5000, 0, 100, 100};
|
||||||
|
popuparea(mon, 2, &work, 2500, 500, &out);
|
||||||
|
CT_EQ_INT(t, mon[1].x, out.x);
|
||||||
|
CT_EQ_INT(t, mon[1].y, out.y);
|
||||||
|
CT_EQ_INT(t, mon[1].w, out.w);
|
||||||
|
CT_EQ_INT(t, mon[1].h, out.h);
|
||||||
|
mon[0] = (Area){0, 0, 100, 100};
|
||||||
|
mon[1] = (Area){200, 0, 100, 100};
|
||||||
|
popuparea(mon, 2, nil, 150, 50, &out);
|
||||||
|
CT_EQ_INT(t, 0, out.x);
|
||||||
|
|
||||||
memset(&caret, 0, sizeof caret);
|
memset(&caret, 0, sizeof caret);
|
||||||
popupposition(&caret, 40, 50, 800, 600, 100, 60, &x, &y);
|
area = (Area){1920, 30, 1280, 900};
|
||||||
CT_EQ_INT(t, 50, x);
|
popupposition(&caret, 2000, 50, &area, 100, 60, &x, &y);
|
||||||
|
CT_EQ_INT(t, 2010, x);
|
||||||
CT_EQ_INT(t, 60, y);
|
CT_EQ_INT(t, 60, y);
|
||||||
caret.valid = 1;
|
caret.valid = 1;
|
||||||
caret.x = 70;
|
caret.x = 2100;
|
||||||
caret.y = 80;
|
caret.y = 80;
|
||||||
caret.h = 20;
|
caret.h = 20;
|
||||||
popupposition(&caret, 40, 50, 800, 600, 100, 60, &x, &y);
|
popupposition(&caret, 0, 0, &area, 100, 60, &x, &y);
|
||||||
CT_EQ_INT(t, 70, x);
|
CT_EQ_INT(t, 2100, x);
|
||||||
CT_EQ_INT(t, 100, y);
|
CT_EQ_INT(t, 100, y);
|
||||||
caret.x = 790;
|
caret.x = 3150;
|
||||||
caret.y = 590;
|
caret.y = 850;
|
||||||
popupposition(&caret, 0, 0, 800, 600, 100, 60, &x, &y);
|
popupposition(&caret, 0, 0, &area, 200, 100, &x, &y);
|
||||||
CT_EQ_INT(t, 700, x);
|
CT_EQ_INT(t, 3000, x);
|
||||||
CT_EQ_INT(t, 530, y);
|
CT_EQ_INT(t, 750, y);
|
||||||
|
|
||||||
/* Neither side fits: choose above, then clamp to the screen. */
|
/* A popup no larger than a small work area stays inside its origin. */
|
||||||
caret.x = 20;
|
area = (Area){100, 200, 80, 80};
|
||||||
caret.y = 30;
|
caret.x = 120;
|
||||||
|
caret.y = 230;
|
||||||
caret.h = 20;
|
caret.h = 20;
|
||||||
popupposition(&caret, 0, 0, 80, 80, 100, 100, &x, &y);
|
popupposition(&caret, 0, 0, &area, 80, 80, &x, &y);
|
||||||
CT_EQ_INT(t, 0, x);
|
CT_EQ_INT(t, 100, x);
|
||||||
CT_EQ_INT(t, 0, y);
|
CT_EQ_INT(t, 200, y);
|
||||||
|
|
||||||
caret.x = 70;
|
|
||||||
caret.y = 80;
|
|
||||||
caret.h = 0;
|
|
||||||
popupposition(&caret, 0, 0, 800, 600, 100, 60, &x, &y);
|
|
||||||
CT_EQ_INT(t, 70, x);
|
|
||||||
CT_EQ_INT(t, 80, y);
|
|
||||||
caret.h = -20;
|
|
||||||
popupposition(&caret, 0, 0, 800, 600, 100, 60, &x, &y);
|
|
||||||
CT_EQ_INT(t, 70, x);
|
|
||||||
CT_EQ_INT(t, 80, y);
|
|
||||||
|
|
||||||
caret.x = INT_MIN;
|
|
||||||
caret.y = INT_MAX;
|
|
||||||
caret.h = INT_MAX;
|
|
||||||
popupposition(&caret, 0, 0, 800, 600, 100, 60, &x, &y);
|
|
||||||
CT_EQ_INT(t, 0, x);
|
|
||||||
CT_EQ_INT(t, 540, y);
|
|
||||||
caret.x = INT_MAX;
|
|
||||||
caret.y = INT_MIN;
|
|
||||||
caret.h = INT_MIN;
|
|
||||||
popupposition(&caret, 0, 0, INT_MAX, INT_MAX,
|
|
||||||
INT_MAX, INT_MAX, &x, &y);
|
|
||||||
CT_EQ_INT(t, 0, x);
|
|
||||||
CT_EQ_INT(t, 0, y);
|
|
||||||
|
|
||||||
if(!CT_CHECK(t, textinit()))
|
if(!CT_CHECK(t, textinit()))
|
||||||
return;
|
return;
|
||||||
@@ -130,7 +138,7 @@ popup_layout(struct ct *t)
|
|||||||
/* Empty sections reserve nothing. */
|
/* Empty sections reserve nothing. */
|
||||||
memset(&dc, 0, sizeof dc);
|
memset(&dc, 0, sizeof dc);
|
||||||
dc.sel = -1;
|
dc.sel = -1;
|
||||||
popuplayout(&dc, Imgw, &p);
|
popuplayout(&dc, PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, 0, p.w);
|
CT_EQ_INT(t, 0, p.w);
|
||||||
CT_EQ_INT(t, 0, p.h);
|
CT_EQ_INT(t, 0, p.h);
|
||||||
CT_EQ_INT(t, -1, p.prey);
|
CT_EQ_INT(t, -1, p.prey);
|
||||||
@@ -139,8 +147,8 @@ popup_layout(struct ct *t)
|
|||||||
|
|
||||||
/* Preedit only. */
|
/* Preedit only. */
|
||||||
dc.pre = mkstr("preedit");
|
dc.pre = mkstr("preedit");
|
||||||
popuplayout(&dc, 2*Imgw, &p);
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, Imgw, p.w);
|
CT_EQ_INT(t, PopupBasew, p.w);
|
||||||
CT_EQ_INT(t, PopupPad, p.prey);
|
CT_EQ_INT(t, PopupPad, p.prey);
|
||||||
CT_EQ_INT(t, -1, p.sepy);
|
CT_EQ_INT(t, -1, p.sepy);
|
||||||
CT_EQ_INT(t, -1, p.rowsy);
|
CT_EQ_INT(t, -1, p.rowsy);
|
||||||
@@ -153,8 +161,8 @@ popup_layout(struct ct *t)
|
|||||||
dc.nkouho = 2;
|
dc.nkouho = 2;
|
||||||
dc.kouho[0] = mkstr("short");
|
dc.kouho[0] = mkstr("short");
|
||||||
dc.kouho[1] = mkstr("candidate");
|
dc.kouho[1] = mkstr("candidate");
|
||||||
popuplayout(&dc, 2*Imgw, &p);
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, Imgw, p.w);
|
CT_EQ_INT(t, PopupBasew, p.w);
|
||||||
CT_EQ_INT(t, -1, p.prey);
|
CT_EQ_INT(t, -1, p.prey);
|
||||||
CT_EQ_INT(t, -1, p.sepy);
|
CT_EQ_INT(t, -1, p.sepy);
|
||||||
CT_EQ_INT(t, PopupPad, p.rowsy);
|
CT_EQ_INT(t, PopupPad, p.rowsy);
|
||||||
@@ -167,8 +175,8 @@ popup_layout(struct ct *t)
|
|||||||
|
|
||||||
/* Preedit and candidates meet at one separator, with no empty rows. */
|
/* Preedit and candidates meet at one separator, with no empty rows. */
|
||||||
dc.pre = mkstr("preedit");
|
dc.pre = mkstr("preedit");
|
||||||
popuplayout(&dc, 2*Imgw, &p);
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, Imgw, p.w);
|
CT_EQ_INT(t, PopupBasew, p.w);
|
||||||
CT_EQ_INT(t, PopupPad, p.prey);
|
CT_EQ_INT(t, PopupPad, p.prey);
|
||||||
CT_EQ_INT(t, p.prey + Fontsz, p.sepy);
|
CT_EQ_INT(t, p.prey + Fontsz, p.sepy);
|
||||||
CT_EQ_INT(t, p.sepy + PopupSep, p.rowsy);
|
CT_EQ_INT(t, p.sepy + PopupSep, p.rowsy);
|
||||||
@@ -176,6 +184,15 @@ popup_layout(struct ct *t)
|
|||||||
CT_EQ_INT(t, p.rowsy + 2*Fontsz + PopupPad, p.h);
|
CT_EQ_INT(t, p.rowsy + 2*Fontsz + PopupPad, p.h);
|
||||||
CT_EQ_INT(t, 2*PopupPad + 3*Fontsz + PopupSep, p.h);
|
CT_EQ_INT(t, 2*PopupPad + 3*Fontsz + PopupSep, p.h);
|
||||||
|
|
||||||
|
/* Long preedit expands to the monitor cap just like a candidate. */
|
||||||
|
sclear(&longrow);
|
||||||
|
for(i = 0; i < Maxrunes; i++)
|
||||||
|
sputr(&longrow, 'W');
|
||||||
|
memset(&dc, 0, sizeof dc);
|
||||||
|
dc.pre = longrow;
|
||||||
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
|
CT_EQ_INT(t, 2*PopupBasew, p.w);
|
||||||
|
|
||||||
/* The largest panel includes all sections and fits its backing image. */
|
/* The largest panel includes all sections and fits its backing image. */
|
||||||
memset(&dc, 0, sizeof dc);
|
memset(&dc, 0, sizeof dc);
|
||||||
dc.pre = mkstr("preedit");
|
dc.pre = mkstr("preedit");
|
||||||
@@ -183,13 +200,10 @@ popup_layout(struct ct *t)
|
|||||||
dc.sel = 4;
|
dc.sel = 4;
|
||||||
dc.first = 0;
|
dc.first = 0;
|
||||||
dc.total = Maxdisp + 1;
|
dc.total = Maxdisp + 1;
|
||||||
sclear(&longrow);
|
|
||||||
for(i = 0; i < Maxrunes; i++)
|
|
||||||
sputr(&longrow, 'W');
|
|
||||||
for(i = 0; i < Maxdisp; i++)
|
for(i = 0; i < Maxdisp; i++)
|
||||||
dc.kouho[i] = mkstr(i == dc.sel ? "M" : "candidate");
|
dc.kouho[i] = mkstr(i == dc.sel ? "M" : "candidate");
|
||||||
dc.kouho[0] = longrow;
|
dc.kouho[0] = longrow;
|
||||||
popuplayout(&dc, 2*Imgw, &p);
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, Maxdisp, p.n);
|
CT_EQ_INT(t, Maxdisp, p.n);
|
||||||
CT_EQ_INT(t, PopupPad, p.prey);
|
CT_EQ_INT(t, PopupPad, p.prey);
|
||||||
CT_EQ_INT(t, p.prey + Fontsz, p.sepy);
|
CT_EQ_INT(t, p.prey + Fontsz, p.sepy);
|
||||||
@@ -197,7 +211,7 @@ popup_layout(struct ct *t)
|
|||||||
CT_EQ_INT(t, p.rowsy + Maxdisp*Fontsz, p.marky);
|
CT_EQ_INT(t, p.rowsy + Maxdisp*Fontsz, p.marky);
|
||||||
CT_EQ_INT(t, p.marky + Fontsz + PopupPad, p.h);
|
CT_EQ_INT(t, p.marky + Fontsz + PopupPad, p.h);
|
||||||
CT_EQ_INT(t, Imgh, p.h);
|
CT_EQ_INT(t, Imgh, p.h);
|
||||||
CT_EQ_INT(t, Imgw, p.w);
|
CT_EQ_INT(t, 2*PopupBasew, p.w);
|
||||||
CT_CHECK(t, p.h <= Imgh);
|
CT_CHECK(t, p.h <= Imgh);
|
||||||
CT_EQ_INT(t, p.w - PopupPad, p.markx + p.markw);
|
CT_EQ_INT(t, p.w - PopupPad, p.markx + p.markw);
|
||||||
CT_EQ_INT(t, PopupPad, p.selx);
|
CT_EQ_INT(t, PopupPad, p.selx);
|
||||||
@@ -207,7 +221,7 @@ popup_layout(struct ct *t)
|
|||||||
CT_EQ_INT(t, p.numx + PopupNumw, p.textx);
|
CT_EQ_INT(t, p.numx + PopupNumw, p.textx);
|
||||||
CT_EQ_INT(t, p.w - PopupPad, p.textx + p.textw);
|
CT_EQ_INT(t, p.w - PopupPad, p.textx + p.textw);
|
||||||
|
|
||||||
img = emalloc(Imgw*Imgh*sizeof img[0]);
|
img = emalloc(2*PopupBasew*Imgh*sizeof img[0]);
|
||||||
popupdraw(img, &dc, &p);
|
popupdraw(img, &dc, &p);
|
||||||
checkpadding(t, img, &p);
|
checkpadding(t, img, &p);
|
||||||
for(x = 0; x < p.w; x++)
|
for(x = 0; x < p.w; x++)
|
||||||
@@ -254,15 +268,15 @@ popup_layout(struct ct *t)
|
|||||||
}
|
}
|
||||||
CT_CHECK(t, markink > 0);
|
CT_CHECK(t, markink > 0);
|
||||||
|
|
||||||
/* A fitted long row is bounded by the fixed candidate content area. */
|
/* A long candidate grows from the stable base to the monitor cap. */
|
||||||
memset(&dc, 0, sizeof dc);
|
memset(&dc, 0, sizeof dc);
|
||||||
dc.sel = -1;
|
dc.sel = -1;
|
||||||
dc.nkouho = 1;
|
dc.nkouho = 1;
|
||||||
dc.kouho[0] = longrow;
|
dc.kouho[0] = longrow;
|
||||||
n = textwidth(&longrow);
|
n = textwidth(&longrow);
|
||||||
popuplayout(&dc, 2*Imgw, &p);
|
popuplayout(&dc, 2*PopupBasew, Imgh, &p);
|
||||||
CT_EQ_INT(t, Imgw, p.w);
|
CT_EQ_INT(t, 2*PopupBasew, p.w);
|
||||||
CT_EQ_INT(t, PopupTextw, p.textw);
|
CT_CHECK(t, p.textw > PopupTextw);
|
||||||
CT_CHECK(t, n > p.textw);
|
CT_CHECK(t, n > p.textw);
|
||||||
CT_EQ_INT(t, PopupPad, p.rowsy);
|
CT_EQ_INT(t, PopupPad, p.rowsy);
|
||||||
CT_EQ_INT(t, p.w - PopupPad, p.textx + p.textw);
|
CT_EQ_INT(t, p.w - PopupPad, p.textx + p.textw);
|
||||||
@@ -281,7 +295,54 @@ popup_layout(struct ct *t)
|
|||||||
CT_CHECK(t, ink > 0);
|
CT_CHECK(t, ink > 0);
|
||||||
CT_EQ_INT(t, n, textwidth(&longrow));
|
CT_EQ_INT(t, n, textwidth(&longrow));
|
||||||
|
|
||||||
popuplayout(&dc, Imgw - 1, &p);
|
popuplayout(&dc, PopupBasew - 1, Imgh, &p);
|
||||||
CT_EQ_INT(t, Imgw - 1, p.w);
|
CT_EQ_INT(t, PopupBasew - 1, p.w);
|
||||||
|
|
||||||
|
/* Height truncation scrolls the row window to the selected candidate. */
|
||||||
|
memset(&dc, 0, sizeof dc);
|
||||||
|
dc.nkouho = Maxdisp;
|
||||||
|
dc.sel = Maxdisp - 1;
|
||||||
|
dc.total = Maxdisp;
|
||||||
|
for(i = 0; i < Maxdisp; i++)
|
||||||
|
dc.kouho[i] = mkstr("candidate");
|
||||||
|
popuplayout(&dc, PopupBasew, 2*PopupPad + 2*Fontsz, &p);
|
||||||
|
CT_EQ_INT(t, 1, p.n);
|
||||||
|
CT_EQ_INT(t, Maxdisp - 1, p.row0);
|
||||||
|
CT_EQ_INT(t, PopupPad, p.sely);
|
||||||
|
CT_CHECK(t, p.marky >= 0);
|
||||||
|
CT_CHECK(t, p.h <= 2*PopupPad + 2*Fontsz);
|
||||||
|
popupdraw(img, &dc, &p);
|
||||||
|
numink = 0;
|
||||||
|
for(y = p.rowsy; y < p.rowsy + Fontsz; y++)
|
||||||
|
for(x = p.numx; x < p.numx + PopupNumw; x++)
|
||||||
|
if(pixel(img, &p, x, y) != (Colsel & Rgbmask))
|
||||||
|
numink++;
|
||||||
|
markink = 0;
|
||||||
|
for(y = p.marky; y < p.marky + Fontsz; y++)
|
||||||
|
for(x = p.markx; x < p.markx + p.markw; x++)
|
||||||
|
if(pixel(img, &p, x, y) != (Colbg & Rgbmask))
|
||||||
|
markink++;
|
||||||
|
CT_CHECK(t, numink > 0); /* full-width 9 */
|
||||||
|
CT_CHECK(t, markink > 0); /* 9-9/9 */
|
||||||
|
|
||||||
|
/* The selected row wins over preedit and footer in one-row height. */
|
||||||
|
dc.pre = mkstr("preedit");
|
||||||
|
popuplayout(&dc, PopupBasew, 2*PopupPad + Fontsz, &p);
|
||||||
|
CT_EQ_INT(t, -1, p.prey);
|
||||||
|
CT_EQ_INT(t, 1, p.n);
|
||||||
|
CT_EQ_INT(t, Maxdisp - 1, p.row0);
|
||||||
|
CT_EQ_INT(t, -1, p.marky);
|
||||||
|
|
||||||
|
/* With less than one padded row, selected content starts at the top. */
|
||||||
|
for(i = 0; i < nelem(tinyheight); i++){
|
||||||
|
popuplayout(&dc, PopupBasew, tinyheight[i], &p);
|
||||||
|
CT_EQ_INT(t, min(tinyheight[i], Fontsz), p.h);
|
||||||
|
CT_EQ_INT(t, 0, p.rowsy);
|
||||||
|
CT_EQ_INT(t, 0, p.sely);
|
||||||
|
CT_EQ_INT(t, 1, p.n);
|
||||||
|
CT_EQ_INT(t, Maxdisp - 1, p.row0);
|
||||||
|
popupdraw(img, &dc, &p);
|
||||||
|
CT_EQ_UINT(t, Colsel, pixel(img, &p, p.w - PopupPad - 1, 0));
|
||||||
|
}
|
||||||
free(img);
|
free(img);
|
||||||
}
|
}
|
||||||
|
|||||||
222
win.c
222
win.c
@@ -1,4 +1,5 @@
|
|||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/randr.h>
|
||||||
#include "dat.h"
|
#include "dat.h"
|
||||||
#include "fn.h"
|
#include "fn.h"
|
||||||
|
|
||||||
@@ -8,7 +9,9 @@ static xcb_window_t win;
|
|||||||
static xcb_gcontext_t gc;
|
static xcb_gcontext_t gc;
|
||||||
static xcb_pixmap_t pix;
|
static xcb_pixmap_t pix;
|
||||||
static u32int *img;
|
static u32int *img;
|
||||||
static int depth;
|
static xcb_atom_t currentdesktop;
|
||||||
|
static xcb_atom_t workarea;
|
||||||
|
static int depth, hasrandr, imgh, imgw;
|
||||||
|
|
||||||
static xcb_screen_t*
|
static xcb_screen_t*
|
||||||
getscr(xcb_connection_t *c, int n)
|
getscr(xcb_connection_t *c, int n)
|
||||||
@@ -69,9 +72,137 @@ validformat(xcb_connection_t *c, xcb_screen_t *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xcb_atom_t
|
||||||
|
getatom(char *name, int exists)
|
||||||
|
{
|
||||||
|
xcb_intern_atom_cookie_t cookie;
|
||||||
|
xcb_intern_atom_reply_t *reply;
|
||||||
|
xcb_atom_t atom;
|
||||||
|
|
||||||
|
cookie = xcb_intern_atom(conn, exists, strlen(name), name);
|
||||||
|
reply = xcb_intern_atom_reply(conn, cookie, nil);
|
||||||
|
atom = reply == nil ? XCB_ATOM_NONE : reply->atom;
|
||||||
|
free(reply);
|
||||||
|
return atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getcardinals(xcb_atom_t atom, u32int off, int n, u32int *v)
|
||||||
|
{
|
||||||
|
xcb_get_property_cookie_t cookie;
|
||||||
|
xcb_get_property_reply_t *reply;
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
if(atom == XCB_ATOM_NONE)
|
||||||
|
return 0;
|
||||||
|
cookie = xcb_get_property(conn, 0, scr->root, atom,
|
||||||
|
XCB_ATOM_CARDINAL, off, n);
|
||||||
|
reply = xcb_get_property_reply(conn, cookie, nil);
|
||||||
|
ok = reply != nil && reply->type == XCB_ATOM_CARDINAL &&
|
||||||
|
reply->format == 32 &&
|
||||||
|
xcb_get_property_value_length(reply) == n*(int)sizeof v[0];
|
||||||
|
if(ok)
|
||||||
|
memmove(v, xcb_get_property_value(reply), n*sizeof v[0]);
|
||||||
|
free(reply);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getworkarea(Area *a)
|
||||||
|
{
|
||||||
|
u32int desktop, v[4];
|
||||||
|
|
||||||
|
if(!getcardinals(currentdesktop, 0, 1, &desktop) ||
|
||||||
|
desktop > 0x3fffffff ||
|
||||||
|
!getcardinals(workarea, desktop*4, 4, v) ||
|
||||||
|
v[0] > 0x7fffffff || v[1] > 0x7fffffff ||
|
||||||
|
v[2] == 0 || v[2] > 0x7fffffff ||
|
||||||
|
v[3] == 0 || v[3] > 0x7fffffff)
|
||||||
|
return 0;
|
||||||
|
a->x = v[0];
|
||||||
|
a->y = v[1];
|
||||||
|
a->w = v[2];
|
||||||
|
a->h = v[3];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getrootarea(Area *a)
|
||||||
|
{
|
||||||
|
xcb_get_geometry_cookie_t cookie;
|
||||||
|
xcb_get_geometry_reply_t *reply;
|
||||||
|
|
||||||
|
a->x = 0;
|
||||||
|
a->y = 0;
|
||||||
|
a->w = scr->width_in_pixels;
|
||||||
|
a->h = scr->height_in_pixels;
|
||||||
|
cookie = xcb_get_geometry(conn, scr->root);
|
||||||
|
reply = xcb_get_geometry_reply(conn, cookie, nil);
|
||||||
|
if(reply != nil && reply->width > 0 && reply->height > 0){
|
||||||
|
a->w = reply->width;
|
||||||
|
a->h = reply->height;
|
||||||
|
}
|
||||||
|
free(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
popupwork(int x, int y, Area *out)
|
||||||
|
{
|
||||||
|
xcb_generic_error_t *err;
|
||||||
|
xcb_randr_get_monitors_cookie_t cookie;
|
||||||
|
xcb_randr_get_monitors_reply_t *reply;
|
||||||
|
xcb_randr_monitor_info_iterator_t it;
|
||||||
|
Area root, net, *mon;
|
||||||
|
int i, j, n;
|
||||||
|
|
||||||
|
mon = nil;
|
||||||
|
n = 0;
|
||||||
|
err = nil;
|
||||||
|
reply = nil;
|
||||||
|
if(hasrandr){
|
||||||
|
cookie = xcb_randr_get_monitors(conn, scr->root, 1);
|
||||||
|
reply = xcb_randr_get_monitors_reply(conn, cookie, &err);
|
||||||
|
if(reply != nil)
|
||||||
|
n = xcb_randr_get_monitors_monitors_length(reply);
|
||||||
|
if(n > 0 && (uvlong)n <= (uvlong)(~(ulong)0)/sizeof mon[0])
|
||||||
|
mon = malloc(n*sizeof mon[0]);
|
||||||
|
if(mon != nil){
|
||||||
|
it = xcb_randr_get_monitors_monitors_iterator(reply);
|
||||||
|
for(i = j = 0; i < n && it.rem; i++, xcb_randr_monitor_info_next(&it)){
|
||||||
|
if(it.data->width == 0 || it.data->height == 0)
|
||||||
|
continue;
|
||||||
|
mon[j].x = it.data->x;
|
||||||
|
mon[j].y = it.data->y;
|
||||||
|
mon[j].w = it.data->width;
|
||||||
|
mon[j].h = it.data->height;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
n = j;
|
||||||
|
if(n == 0){
|
||||||
|
free(mon);
|
||||||
|
mon = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(mon == nil){
|
||||||
|
getrootarea(&root);
|
||||||
|
mon = &root;
|
||||||
|
n = 1;
|
||||||
|
}
|
||||||
|
if(getworkarea(&net))
|
||||||
|
popuparea(mon, n, &net, x, y, out);
|
||||||
|
else
|
||||||
|
popuparea(mon, n, nil, x, y, out);
|
||||||
|
if(mon != &root)
|
||||||
|
free(mon);
|
||||||
|
free(reply);
|
||||||
|
free(err);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wincleanup(void)
|
wincleanup(void)
|
||||||
{
|
{
|
||||||
|
textclose();
|
||||||
free(img);
|
free(img);
|
||||||
img = nil;
|
img = nil;
|
||||||
if(conn != nil){
|
if(conn != nil){
|
||||||
@@ -82,6 +213,11 @@ wincleanup(void)
|
|||||||
win = 0;
|
win = 0;
|
||||||
gc = 0;
|
gc = 0;
|
||||||
pix = 0;
|
pix = 0;
|
||||||
|
currentdesktop = XCB_ATOM_NONE;
|
||||||
|
workarea = XCB_ATOM_NONE;
|
||||||
|
hasrandr = 0;
|
||||||
|
imgh = 0;
|
||||||
|
imgw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -91,6 +227,9 @@ wininit(void)
|
|||||||
u32int mask, vals[4];
|
u32int mask, vals[4];
|
||||||
xcb_intern_atom_cookie_t c1, c2;
|
xcb_intern_atom_cookie_t c1, c2;
|
||||||
xcb_intern_atom_reply_t *r1, *r2;
|
xcb_intern_atom_reply_t *r1, *r2;
|
||||||
|
xcb_randr_query_version_cookie_t rc;
|
||||||
|
xcb_randr_query_version_reply_t *rr;
|
||||||
|
const xcb_query_extension_reply_t *rext;
|
||||||
|
|
||||||
conn = xcb_connect(nil, &n);
|
conn = xcb_connect(nil, &n);
|
||||||
if(conn == nil || xcb_connection_has_error(conn)){
|
if(conn == nil || xcb_connection_has_error(conn)){
|
||||||
@@ -105,6 +244,16 @@ wininit(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
depth = scr->root_depth;
|
depth = scr->root_depth;
|
||||||
|
rext = xcb_get_extension_data(conn, &xcb_randr_id);
|
||||||
|
if(rext != nil && rext->present){
|
||||||
|
rc = xcb_randr_query_version(conn, 1, 5);
|
||||||
|
rr = xcb_randr_query_version_reply(conn, rc, nil);
|
||||||
|
hasrandr = rr != nil && (rr->major_version > 1 ||
|
||||||
|
(rr->major_version == 1 && rr->minor_version >= 5));
|
||||||
|
free(rr);
|
||||||
|
}
|
||||||
|
currentdesktop = getatom("_NET_CURRENT_DESKTOP", 0);
|
||||||
|
workarea = getatom("_NET_WORKAREA", 0);
|
||||||
win = xcb_generate_id(conn);
|
win = xcb_generate_id(conn);
|
||||||
mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
|
mask = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
|
||||||
XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
|
XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
|
||||||
@@ -129,11 +278,6 @@ wininit(void)
|
|||||||
free(r2);
|
free(r2);
|
||||||
gc = xcb_generate_id(conn);
|
gc = xcb_generate_id(conn);
|
||||||
xcb_create_gc(conn, gc, win, 0, nil);
|
xcb_create_gc(conn, gc, win, 0, nil);
|
||||||
pix = xcb_generate_id(conn);
|
|
||||||
xcb_create_pixmap(conn, depth, pix, win, Imgw, Imgh);
|
|
||||||
mask = XCB_CW_BACK_PIXMAP;
|
|
||||||
xcb_change_window_attributes(conn, win, mask, &pix);
|
|
||||||
img = emalloc(Imgw * Imgh * sizeof(img[0]));
|
|
||||||
if(!textinit()){
|
if(!textinit()){
|
||||||
fprint(2, "strans: popup disabled: no usable fonts\n");
|
fprint(2, "strans: popup disabled: no usable fonts\n");
|
||||||
wincleanup();
|
wincleanup();
|
||||||
@@ -142,10 +286,53 @@ wininit(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
resizebacking(int w, int h)
|
||||||
|
{
|
||||||
|
xcb_generic_error_t *err;
|
||||||
|
xcb_pixmap_t old, new;
|
||||||
|
xcb_void_cookie_t cookie;
|
||||||
|
uvlong pixels;
|
||||||
|
int nh, nw;
|
||||||
|
|
||||||
|
if(w <= 0 || h <= 0)
|
||||||
|
return 0;
|
||||||
|
if(w <= imgw && h <= imgh)
|
||||||
|
return 1;
|
||||||
|
nw = max(w, imgw);
|
||||||
|
nh = max(h, imgh);
|
||||||
|
pixels = (uvlong)nw * nh;
|
||||||
|
if(pixels > (uvlong)(~(ulong)0)/sizeof img[0])
|
||||||
|
return 0;
|
||||||
|
img = erealloc(img, pixels*sizeof img[0]);
|
||||||
|
new = xcb_generate_id(conn);
|
||||||
|
cookie = xcb_create_pixmap_checked(conn, depth, new, win, nw, nh);
|
||||||
|
err = xcb_request_check(conn, cookie);
|
||||||
|
if(err != nil){
|
||||||
|
free(err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cookie = xcb_change_window_attributes_checked(conn, win,
|
||||||
|
XCB_CW_BACK_PIXMAP, &new);
|
||||||
|
err = xcb_request_check(conn, cookie);
|
||||||
|
if(err != nil){
|
||||||
|
free(err);
|
||||||
|
xcb_free_pixmap(conn, new);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
old = pix;
|
||||||
|
pix = new;
|
||||||
|
imgw = nw;
|
||||||
|
imgh = nh;
|
||||||
|
if(old != 0)
|
||||||
|
xcb_free_pixmap(conn, old);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
putimage(int w, int h)
|
putimage(int w, int h)
|
||||||
{
|
{
|
||||||
if(w <= 0 || w > Imgw || h <= 0 || h > Imgh)
|
if(w <= 0 || w > imgw || h <= 0 || h > imgh)
|
||||||
return;
|
return;
|
||||||
xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc,
|
xcb_put_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc,
|
||||||
w, h, 0, 0, 0, depth, w * h * 4, (u8int*)img);
|
w, h, 0, 0, 0, depth, w * h * 4, (u8int*)img);
|
||||||
@@ -163,8 +350,9 @@ winhide(void)
|
|||||||
static int
|
static int
|
||||||
winshow(Drawcmd *dc)
|
winshow(Drawcmd *dc)
|
||||||
{
|
{
|
||||||
|
Area area;
|
||||||
Popup p;
|
Popup p;
|
||||||
int px, py;
|
int ax, ay, px, py;
|
||||||
u32int vals[4];
|
u32int vals[4];
|
||||||
xcb_query_pointer_reply_t *ptr;
|
xcb_query_pointer_reply_t *ptr;
|
||||||
xcb_query_pointer_cookie_t cookie;
|
xcb_query_pointer_cookie_t cookie;
|
||||||
@@ -172,11 +360,6 @@ winshow(Drawcmd *dc)
|
|||||||
if(dc->nkouho <= 0 && dc->pre.n == 0){
|
if(dc->nkouho <= 0 && dc->pre.n == 0){
|
||||||
return winhide();
|
return winhide();
|
||||||
}
|
}
|
||||||
popuplayout(dc, scr->width_in_pixels, &p);
|
|
||||||
if(p.w <= 0 || p.w > Imgw || p.h <= 0 || p.h > Imgh)
|
|
||||||
return 0;
|
|
||||||
vals[2] = p.w;
|
|
||||||
vals[3] = p.h;
|
|
||||||
px = py = 0;
|
px = py = 0;
|
||||||
if(!dc->caret.valid){
|
if(!dc->caret.valid){
|
||||||
cookie = xcb_query_pointer(conn, scr->root);
|
cookie = xcb_query_pointer(conn, scr->root);
|
||||||
@@ -187,17 +370,24 @@ winshow(Drawcmd *dc)
|
|||||||
py = ptr->root_y;
|
py = ptr->root_y;
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
popupposition(&dc->caret, px, py, scr->width_in_pixels,
|
ax = dc->caret.valid ? dc->caret.x : px;
|
||||||
scr->height_in_pixels, p.w, p.h, &px, &py);
|
ay = dc->caret.valid ? dc->caret.y : py;
|
||||||
|
popupwork(ax, ay, &area);
|
||||||
|
popuplayout(dc, area.w, area.h, &p);
|
||||||
|
if(p.w <= 0 || p.h <= 0 || !resizebacking(p.w, p.h))
|
||||||
|
return 0;
|
||||||
|
vals[2] = p.w;
|
||||||
|
vals[3] = p.h;
|
||||||
|
popupposition(&dc->caret, px, py, &area, p.w, p.h, &px, &py);
|
||||||
vals[1] = py;
|
vals[1] = py;
|
||||||
vals[0] = px;
|
vals[0] = px;
|
||||||
xcb_configure_window(conn, win,
|
xcb_configure_window(conn, win,
|
||||||
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
|
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
|
||||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||||
vals);
|
vals);
|
||||||
xcb_map_window(conn, win);
|
|
||||||
popupdraw(img, dc, &p);
|
popupdraw(img, dc, &p);
|
||||||
putimage(p.w, p.h);
|
putimage(p.w, p.h);
|
||||||
|
xcb_map_window(conn, win);
|
||||||
return xcb_flush(conn) > 0;
|
return xcb_flush(conn) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user