ref: 386ed6ba96647167e1a230033b02398f1d2d7a45
parent: fb7cc13fe8c7e198e6130f973448b13ac8614470
author: aap <aap@papnet.eu>
date: Mon Jul 22 17:58:35 EDT 2024
major additions: window decorations virtual desktops themes
--- /dev/null
+++ b/README
@@ -1,0 +1,41 @@
+# lola
+
+Lola is the attempt at a new window system. Its architecture is based
+on that of rio, and it borrows some of its code, but it is not a
+modified rio.
+
+The first milestone was to reach something like feature parity with rio.
+The goals were:
+
+- use lib9p instead of implementing the 9p server from scratch
+ -> 9p no longer in separate proc, easier synchronization
+- de-couple text handling from windows
+ -> text.c
+- cleaner code, make it more hackable
+
+
+After that had been more or less achieved some new features were implemented:
+
+- window decorations including title bars
+ - various styles:
+ - flat style (extremely minimal)
+ - simple style (TODO: maybe rename this...)
+ - windows 3.x
+ - windows 95/nt4
+ - (no)title, (no)border wctl messages
+- support for different color schemes
+ - uses named devdraw images
+- virtual desktops
+ - 1-2 chord on desktop opens screen menu
+ - screenoffset wctl message
+ - (no)sticky wctl message
+- select window with mouse by reading from `pick' file
+- misc
+ - 1-3 chord on desktop opens secondary menu
+
+# Building
+
+The window decoration style is set by linking in the relevant file,
+so edit the `mkfile' to try different styles.
+The options are: flat.c, simple.c, win3.c, win95.c
+
--- a/TODO
+++ /dev/null
@@ -1,20 +1,0 @@
-rethink resizing and repainting
-rethink hiding/unhiding
-check for bad rects (what's left here?)
-top/bottom/current seems to work a bit different in rio
-make sure there are no deadlocks
-...
-
-ideas:
- case-insensitive 'look'
- virtual screen (like fvwm)
- cursor movement
- decorations (at least make them possible)
- tabbed window
-
-problems:
- Borderwidth hardcoded in gengetwindow
- originwindow doesn't work with gengetwindow
- non-origin screen breaks samterm scrollbars
- raw mode where?
- initkeyboard with /dev/kbd support (also fix leaks in old code)
--- a/data.c
+++ b/data.c
@@ -171,23 +171,63 @@
return allocimage(display, Rect(0,0,1,1), screen->chan, 1, col);
}
+Image*
+getcolor(char *name, ulong col)
+{
+ Image *img;
+
+ name = smprint("th_%s", name);
+
+ img = namedimage(display, name);
+ if(img == nil){
+ img = mkcolor(col);
+ if(nameimage(img, name, 1) == 0)
+ panic("couldn't name image\n");
+ }
+ free(name);
+ return img;
+}
+
+Image *pal[8];
+
+Image*
+mkicon(char *px, int w, int h)
+{
+ int i, j, idx;
+ Image *img;
+
+ img = allocimage(display, Rect(0,0,w,h), RGBA32, 1, 0x00000000);
+ for(i = 0; i < h; i++)
+ for(j = 0; j < w; j++) {
+ idx = px[i*w + j];
+ if(idx)
+ draw(img, Rect(j,i,j+1,i+1), pal[idx], nil, ZP);
+ }
+ return img;
+}
+
void
initdata(void)
{
- background = mkcolor(0x777777FF);
- colors[BACK] = mkcolor(0xFFFFFFFF);
- colors[HIGH] = mkcolor(0xCCCCCCFF);
- colors[BORD] = mkcolor(0x999999FF);
- colors[TEXT] = mkcolor(0x000000FF);
- colors[HTEXT] = mkcolor(0x000000FF);
+ background = getcolor("background", 0x777777FF);
+ colors[BACK] = getcolor("back", 0xFFFFFFFF);
+ colors[HIGH] = getcolor("high", 0xCCCCCCFF);
+ colors[BORD] = getcolor("bord", 0x999999FF);
+ colors[TEXT] = getcolor("text", 0x000000FF);
+ colors[HTEXT] = getcolor("htext", 0x000000FF);
+ colors[PALETEXT] = getcolor("paletext", 0x666666FF);
+ colors[HOLDTEXT] = getcolor("holdtext", DMedblue);
+ colors[PALEHOLDTEXT] = getcolor("paleholdtext", DGreyblue);
- colors[TITLE] = mkcolor(DGreygreen);
- colors[LTITLE] = mkcolor(DPalegreygreen);
- colors[TITLEHOLD] = mkcolor(DMedblue);
- colors[LTITLEHOLD] = mkcolor(DPalegreyblue);
+ // this is probably dumb.
+ pal[0] = mkcolor(0x00000000);
+ pal[1] = mkcolor(0x000000FF);
+ pal[2] = mkcolor(0xFFFFFFFF);
+ pal[3] = mkcolor(0xC0C0C0FF);
+ pal[4] = mkcolor(0x808080FF);
+ pal[5] = mkcolor(0x0000FFFF);
+ pal[6] = mkcolor(0x87888FFF);
+ pal[7] = mkcolor(0xC0C7C8FF);
- colors[PALETEXT] = mkcolor(0x666666FF);
- colors[HOLDTEXT] = mkcolor(DMedblue);
- colors[PALEHOLDTEXT] = mkcolor(DGreyblue);
+ inittheme();
}
-
--- /dev/null
+++ b/deskmenu.c
@@ -1,0 +1,169 @@
+#include "inc.h"
+
+static Image *menutxt;
+static Image *back;
+static Image *high;
+static Image *bord;
+static Image *text;
+static Image *htext;
+
+enum
+{
+ Border = 2,
+ ItemBorder = 1,
+ Itemwidth = 40,
+ Itemheight = 30
+};
+
+static
+void
+menucolors(void)
+{
+ /* Main tone is greenish, with negative selection */
+ back = getcolor("menuback", 0xEAFFEAFF);
+ high = getcolor("menuhigh", 0x448844FF); /* dark green */
+ bord = getcolor("menubord", 0x88CC88FF); /* not as dark green */
+ text = getcolor("menutext", 0x000000FF);
+ htext = getcolor("menuhtext", 0xEAFFEAFF);
+ if(back==nil || high==nil || bord==nil || text==nil || htext==nil)
+ goto Error;
+ return;
+
+ Error:
+ freeimage(back);
+ freeimage(high);
+ freeimage(bord);
+ freeimage(text);
+ freeimage(htext);
+ back = display->white;
+ high = display->black;
+ bord = display->black;
+ text = display->black;
+ htext = display->white;
+}
+
+static Rectangle
+menurect(Rectangle r, int i, int j)
+{
+ if(i < 0 || j < 0)
+ return Rect(0, 0, 0, 0);
+ return rectaddpt(Rect(0, 0, Itemwidth, Itemheight),
+ Pt(r.min.x+i*Itemwidth, r.min.y+j*Itemheight));
+}
+
+static void
+paintitem(Image *m, Rectangle contr, int i, int j, int highlight)
+{
+ Rectangle r;
+
+ if(i < 0 || j < 0)
+ return;
+ r = menurect(contr, i, j);
+ draw(m, r, highlight? high : back, nil, ZP);
+ border(m, r, ItemBorder, bord, ZP);
+}
+
+static Point
+menusel(Rectangle r, Point p)
+{
+ if(!ptinrect(p, r))
+ return Pt(-1,-1);
+ return Pt((p.x-r.min.x)/Itemwidth, (p.y-r.min.y)/Itemheight);
+}
+
+
+static Point
+menuscan(Image *m, int but, Mousectl *mc, Rectangle contr)
+{
+ Point ij, lastij;
+
+ lastij = menusel(contr, mc->xy);
+ paintitem(m, contr, lastij.x, lastij.y, 1);
+ readmouse(mc);
+ while(mc->buttons & (1<<(but-1))){
+ ij = menusel(contr, mc->xy);
+ if(!eqpt(ij, lastij))
+ paintitem(m, contr, lastij.x, lastij.y, 0);
+ if(ij.x == -1 || ij.y == -1)
+ return Pt(-1,-1);
+ lastij = ij;
+ paintitem(m, contr, lastij.x, lastij.y, 1);
+
+ readmouse(mc);
+ }
+ return lastij;
+}
+
+static void
+menupaint(Image *m, Rectangle contr, int nx, int ny)
+{
+ int i, j;
+
+ draw(m, contr, back, nil, ZP);
+ for(i = 0; i < nx; i++)
+ for(j = 0; j < ny; j++)
+ paintitem(m, contr, i, j, 0);
+}
+
+static Point
+clampscreen(Rectangle r)
+{
+ Point pt;
+
+ pt = ZP;
+ if(r.max.x>screen->r.max.x)
+ pt.x = screen->r.max.x-r.max.x;
+ if(r.max.y>screen->r.max.y)
+ pt.y = screen->r.max.y-r.max.y;
+ if(r.min.x<screen->r.min.x)
+ pt.x = screen->r.min.x-r.min.x;
+ if(r.min.y<screen->r.min.y)
+ pt.y = screen->r.min.y-r.min.y;
+ return pt;
+}
+
+Point
+dmenuhit(int but, Mousectl *mc, int nx, int ny, Point last)
+{
+ Rectangle r, menur, contr;
+ Point delta;
+ Point sel;
+
+ if(back == nil)
+ menucolors();
+
+ if(last.x < 0) last.x = 0;
+ if(last.x >= nx) last.x = nx-1;
+ if(last.y < 0) last.y = 0;
+ if(last.y >= ny) last.y = ny-1;
+
+ r = insetrect(Rect(0, 0, nx*Itemwidth, ny*Itemheight), -Border);
+ r = rectsubpt(r, Pt(last.x*Itemwidth+Itemwidth/2, last.y*Itemheight+Itemheight/2));
+ menur = rectaddpt(r, mc->xy);
+ delta = clampscreen(menur);
+ menur = rectaddpt(menur, delta);
+ contr = insetrect(menur, Border);
+
+ Image *b, *backup;
+ {
+ b = screen;
+ backup = allocimage(display, menur, screen->chan, 0, -1);
+ draw(backup, menur, screen, nil, menur.min);
+ }
+ draw(b, menur, back, nil, ZP);
+ border(b, menur, Border, bord, ZP);
+ menupaint(b, contr, nx, ny);
+
+ sel = Pt(-1, -1);
+ while(mc->buttons & (1<<(but-1))){
+ sel = menuscan(b, but, mc, contr);
+ }
+
+ if(backup){
+ draw(screen, menur, backup, nil, menur.min);
+ freeimage(backup);
+ }
+ flushimage(display, 1);
+
+ return sel;
+}
--- /dev/null
+++ b/flat.c
@@ -1,0 +1,77 @@
+#include "inc.h"
+
+int bordersz = 4;
+int titlesz = 18;
+
+enum {
+ TITLE,
+ LTITLE,
+ TITLEHOLD,
+ LTITLEHOLD,
+ TITLETEXT,
+ LTITLETEXT,
+ TITLEHOLDTEXT,
+ LTITLEHOLDTEXT,
+
+ NumWinColors
+};
+
+Image *wincolors[NumWinColors];
+
+void
+wdecor(Window *w)
+{
+ if(w->frame == nil)
+ return;
+ int c = w->holdmode ?
+ w == focused ? TITLEHOLD : LTITLEHOLD :
+ w == focused ? TITLE : LTITLE;
+
+ Rectangle r = w->frame->r;
+
+ if(!w->noborder){
+ border(w->frame, r, bordersz, wincolors[c], ZP);
+ r = insetrect(r, bordersz);
+ }
+
+ if(!w->notitle){
+ r.max.y = r.min.y + titlesz;
+ draw(w->frame, r, wincolors[c], nil, ZP);
+
+ Point pt = Pt(r.min.x, r.min.y);
+ string(w->frame, pt, wincolors[c+4], pt, font, w->label);
+ }
+}
+
+void
+wtitlectl(Window *w)
+{
+ if(mctl->buttons & 7){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 1) {
+ if(!w->maximized)
+ grab(w, 1);
+ }
+ if(mctl->buttons & 4)
+ btn3menu();
+ }
+}
+
+void
+inittheme(void)
+{
+ wincolors[TITLE] = getcolor("title", DGreygreen);
+ wincolors[LTITLE] = getcolor("ltitle", DPalegreygreen);
+// wincolors[TITLE] = getcolor("title", 0x2F78EDFF);
+// wincolors[LTITLE] = getcolor("ltitle", 0x7C9DE3FF);
+
+ wincolors[TITLEHOLD] = getcolor("titlehold", DMedblue);
+ wincolors[LTITLEHOLD] = getcolor("ltitlehold", DPalegreyblue);
+
+
+ wincolors[TITLETEXT] = getcolor("titletext", 0xFFFFFFFF);
+ wincolors[LTITLETEXT] = getcolor("ltitletext", 0x808080FF);
+ wincolors[TITLEHOLDTEXT] = getcolor("titleholdtext", 0xFFFFFFFF);
+ wincolors[LTITLEHOLDTEXT] = getcolor("ltitleholdtext", 0xC0C0C0FF);
+}
--- a/fs.c
+++ b/fs.c
@@ -7,7 +7,8 @@
Qsnarf,
Qwctl,
Qtap,
- Qglobal = Qtap, /* last global one */
+ Qpick,
+ Qglobal = Qpick, /* last global one */
/* these need a window */
Qcons,
@@ -51,6 +52,7 @@
{ Qscreen, QTFILE, "screen", 0400 },
{ Qwindow, QTFILE, "window", 0400 },
{ Qwctl, QTFILE, "wctl", 0600 },
+ { Qpick, QTFILE, "pick", 0400 },
{ Qtap, QTFILE, "kbdtap", 0660 }
};
@@ -269,8 +271,9 @@
}
if(id = strtol(name, &end, 10), *end == '\0'){
w = wfind(id);
- if(w){
- incref(w);
+ if(w || id == 0){
+ if(w)
+ incref(w);
wrelease(xf->w);
xf->w = w;
fid->qid = (Qid){QID(ID(w),Qroot), 0, QTDIR};
@@ -341,10 +344,12 @@
static void
fsopen(Req *r)
{
+ Xfid *xf;
Window *w;
int rd, wr;
- w = XF(r->fid)->w;
+ xf = XF(r->fid);
+ w = xf->w;
/* TODO: check and sanitize mode */
@@ -408,6 +413,22 @@
}
break;
+ case Qpick:
+ if(xf->w){
+ wrelease(xf->w);
+ xf->w = nil;
+ }
+ /* pick window from main thread.
+ * TODO: this may not be optimal because
+ * it might block this thread. */
+ Channel *wc = chancreate(sizeof(Window*), 0);
+ sendp(pickchan, wc);
+ xf->w = w = recvp(wc);
+ if(w)
+ incref(w);
+ chanfree(wc);
+ break;
+
case Qtap:
if(rd && totap || wr && fromtap){
respond(r, Einuse);
@@ -639,17 +660,20 @@
respond(r, readimg(r, screen));
return;
case Qwindow:
- respond(r, readimg(r, w->img));
+ respond(r, readimg(r, w->frame));
return;
case Qwctl:
/* TODO: what's with the Etooshort conditions?? */
if(w == nil){
- if(r->ifcall.count < 6*12){
+ if(r->ifcall.count < 4*12){
respond(r, Etooshort);
return;
}
- data = smprint("%11d %11d %11d %11d nowindow nowindow ",
- screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y);
+// data = smprint("%11d %11d %11d %11d %11s %11s ",
+ data = smprint("%11d %11d %11d %11d %11d %11d ",
+ screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y,
+// "nowindow", "nowindow");
+ screenoff.x, screenoff.y);
readstr(r, data);
free(data);
}else{
@@ -660,6 +684,11 @@
respond(r, readblocking(r, w->wctlread));
return;
}
+ break;
+ case Qpick:
+ data = smprint("%11d ", w ? w->id : -1);
+ readstr(r, data);
+ free(data);
break;
case Qtap:
respond(r, readblocking(r, totap));
--- a/inc.h
+++ b/inc.h
@@ -94,12 +94,7 @@
enum
{
// NCOL is defined by libframe, add more after it
- TITLE = NCOL,
- LTITLE,
- TITLEHOLD,
- LTITLEHOLD,
-
- PALETEXT,
+ PALETEXT = NCOL,
HOLDTEXT,
PALEHOLDTEXT,
@@ -116,22 +111,20 @@
extern Cursor *corners[9];
void initdata(void);
+extern bool scrolling;
+extern bool notitle;
+extern int ndeskx;
+extern int ndesky;
+
extern Screen *wscreen;
+extern Image *fakebg;
extern Mousectl *mctl;
-extern int scrolling;
extern char *startdir;
-extern int shiftdown;
-extern int gotscreen;
-extern int servekbd;
+extern bool shiftdown, ctldown;
+extern bool gotscreen;
+extern bool servekbd;
-extern Cursor *cursor;
-void setcursoroverride(Cursor *c, int ov);
-void setcursornormal(Cursor *c);
-Rectangle newrect(void);
-int goodrect(Rectangle r);
-
-
typedef struct RuneConvBuf RuneConvBuf;
struct RuneConvBuf
{
@@ -192,6 +185,9 @@
Wakeup
};
+extern int bordersz;
+extern int titlesz;
+
typedef struct Window Window;
struct Window
{
@@ -200,16 +196,23 @@
bool hidden;
Window *lower;
Window *higher;
- Image *img;
+ Image *frame;
+ Image *content;
int id;
char name[32];
int namecount;
char *label;
- bool noborder;
- Rectangle contrect;
+ int noborder;
int notefd;
char *dir;
+ bool notitle;
+ bool maximized;
+ bool sticky;
+ Rectangle origrect;
+ Rectangle titlerect;
+ Rectangle contrect;
+
Text text;
Rectangle scrollr;
Rectangle textr;
@@ -248,8 +251,12 @@
extern Window *windows[MAXWINDOWS];
extern int nwindows;
extern Window *focused, *cursorwin;
+extern Point screenoff;
+void wtitlectl(Window *w);
void wdecor(Window *w);
+void wmaximize(Window *w);
+void wrestore(Window *w);
void wresize(Window *w, Rectangle r);
Window *wcreate(Rectangle r, bool hidden, bool scrolling);
void wrelease(Window *w);
@@ -273,6 +280,8 @@
void wtype(Window *w, Rune r);
int wincmd(Window *w, int pid, char *dir, char **argv);
+void screenoffset(int offx, int offy);
+
typedef struct Wctlcmd Wctlcmd;
struct Wctlcmd
{
@@ -291,10 +300,34 @@
char *writewctl(Window *w, char *data);
+extern Cursor *cursor;
+void setcursoroverride(Cursor *c, int ov);
+void setcursornormal(Cursor *c);
+
+Rectangle newrect(void);
+int goodrect(Rectangle r);
+Rectangle centerrect(Rectangle r, Rectangle s);
+void borderTL(Image *img, Rectangle r, Image *c);
+void borderBR(Image *img, Rectangle r, Image *c);
+void winborder(Image *img, Rectangle r, Image *c1, Image *c2);
+
+void refresh(void);
+Point dmenuhit(int but, Mousectl *mc, int nx, int ny, Point last);
+void drainmouse(Mousectl *mc, Window *w);
+void grab(Window *w, int btn);
+void btn3menu(void);
+
+void inittheme(void);
+Image *getcolor(char *name, ulong defcol);
+Image *mkicon(char *px, int w, int h);
+
+
extern Channel *opentap; /* open fromtap or totap */
extern Channel *closetap; /* close fromtap or totap */
extern Channel *fromtap; /* input from kbd tap program to window */
extern Channel *totap; /* our keyboard input to tap program */
+
+extern Channel *pickchan;
extern Srv fsys;
--- a/main.c
+++ b/main.c
@@ -1,14 +1,19 @@
#include "inc.h"
+bool scrolling;
+bool notitle;
+int ndeskx = 3;
+int ndesky = 3;
+
RKeyboardctl *kbctl;
Mousectl *mctl;
-int scrolling = 1;
char *startdir;
-int shiftdown;
-int gotscreen;
-int servekbd;
+bool shiftdown, ctldown;
+bool gotscreen;
+bool servekbd;
Screen *wscreen;
+Image *fakebg;
void
killprocs(void)
@@ -305,15 +310,15 @@
}
void
-grab(Window *w)
+grab(Window *w, int btn)
{
if(w == nil)
- w = clickwindow(3, mctl);
+ w = clickwindow(btn, mctl);
if(w == nil)
setcursoroverride(nil, FALSE);
else{
- Rectangle r = dragrect(3, w->img->r, mctl);
- if(Dx(r) > 0 || Dy(r) > 0){
+ Rectangle r = dragrect(btn, w->frame->r, mctl);
+ if((Dx(r) > 0 || Dy(r) > 0) && !eqrect(r, w->frame->r)){
wmove(w, r.min);
wfocus(w);
flushimage(display, 1);
@@ -341,8 +346,8 @@
bandresize(Window *w)
{
Rectangle r;
- r = bandrect(w->img->r, mctl->buttons, mctl);
- if(!eqrect(r, w->img->r)){
+ r = bandrect(w->frame->r, mctl->buttons, mctl);
+ if(!eqrect(r, w->frame->r)){
wresize(w, r);
flushimage(display, 1);
}
@@ -356,19 +361,19 @@
if(!rectclip(&r, screen->r))
return 1;
for(; t; t = t->higher){
- if(t->hidden || Dx(t->img->r) == 0 || Dy(t->img->r) == 0 || rectXrect(r, t->img->r) == 0)
+ if(t->hidden || Dx(t->frame->r) == 0 || Dy(t->frame->r) == 0 || rectXrect(r, t->frame->r) == 0)
continue;
- if(r.min.y < t->img->r.min.y)
- if(!obscured(w, Rect(r.min.x, r.min.y, r.max.x, t->img->r.min.y), t))
+ if(r.min.y < t->frame->r.min.y)
+ if(!obscured(w, Rect(r.min.x, r.min.y, r.max.x, t->frame->r.min.y), t))
return 0;
- if(r.min.x < t->img->r.min.x)
- if(!obscured(w, Rect(r.min.x, r.min.y, t->img->r.min.x, r.max.y), t))
+ if(r.min.x < t->frame->r.min.x)
+ if(!obscured(w, Rect(r.min.x, r.min.y, t->frame->r.min.x, r.max.y), t))
return 0;
- if(r.max.y > t->img->r.max.y)
- if(!obscured(w, Rect(r.min.x, t->img->r.max.y, r.max.x, r.max.y), t))
+ if(r.max.y > t->frame->r.max.y)
+ if(!obscured(w, Rect(r.min.x, t->frame->r.max.y, r.max.x, r.max.y), t))
return 0;
- if(r.max.x > t->img->r.max.x)
- if(!obscured(w, Rect(t->img->r.max.x, r.min.y, r.max.x, r.max.y), t))
+ if(r.max.x > t->frame->r.max.x)
+ if(!obscured(w, Rect(t->frame->r.max.x, r.min.y, r.max.x, r.max.y), t))
return 0;
return 1;
}
@@ -391,13 +396,14 @@
* that includes the border on each side with an extra pixel
* so that the text is still drawn
*/
- if(Dx(r) < 100 || Dy(r) < 2*(Borderwidth+1)+font->height)
+ if(Dx(r) < 100 || Dy(r) < 2*(bordersz+1)+font->height)
return 0;
+//TODO(vdesk) this changes
/* window must be on screen */
if(!rectXrect(screen->r, r))
return 0;
/* must have some screen and border visible so we can move it out of the way */
- if(rectinrect(screen->r, insetrect(r, Borderwidth)))
+ if(rectinrect(screen->r, insetrect(r, bordersz)))
return 0;
return 1;
}
@@ -409,8 +415,8 @@
static int i = 0;
int minx, miny, dx, dy;
- dx = min(600, Dx(screen->r) - 2*Borderwidth);
- dy = min(400, Dy(screen->r) - 2*Borderwidth);
+ dx = min(600, Dx(screen->r) - 2*bordersz);
+ dy = min(400, Dy(screen->r) - 2*bordersz);
minx = 32 + 16*i;
miny = 32 + 16*i;
i++;
@@ -420,50 +426,30 @@
}
-enum {
- Cut,
- Paste,
- Snarf,
- Plumb,
- Look,
- Send,
- Scroll
-};
-char *menu2str[] = {
- "cut",
- "paste",
- "snarf",
- "plumb",
- "look",
- "send",
- "scroll",
- nil
-};
-Menu menu2 = { menu2str };
-
-enum {
- New,
- Reshape,
- Move,
- Delete,
- Hide,
- Exit
-};
-int Hidden = Exit+1;
-char *menu3str[7 + MAXWINDOWS] = {
- "New",
- "Resize",
- "Move",
- "Delete",
- "Hide",
- "Exit",
- nil
-};
-Menu menu3 = { menu3str };
-
void
btn2menu(Window *w)
{
+ enum {
+ Cut,
+ Paste,
+ Snarf,
+ Plumb,
+ Look,
+ Send,
+ Scroll
+ };
+ static char *menu2str[] = {
+ "cut",
+ "paste",
+ "snarf",
+ "plumb",
+ "look",
+ "send",
+ "scroll",
+ nil
+ };
+ static Menu menu2 = { menu2str };
+
int sel;
Text *x;
Cursor *c;
@@ -508,6 +494,24 @@
void
btn3menu(void)
{
+ enum {
+ New,
+ Reshape,
+ Move,
+ Delete,
+ Hide,
+ Hidden
+ };
+ static char *str[Hidden+1 + MAXWINDOWS] = {
+ "New",
+ "Resize",
+ "Move",
+ "Delete",
+ "Hide",
+ nil
+ };
+ static Menu menu = { str };
+
static Window *hidden[MAXWINDOWS];
int nhidden;
Window *w, *t;
@@ -516,15 +520,17 @@
nhidden = 0;
for(i = 0; i < nwindows; i++){
t = windows[i];
- if(t->hidden || obscured(t, t->img->r, t->higher)){
+ if(!rectXrect(screen->r, t->frame->r))
+ continue;
+ if(t->hidden || obscured(t, t->frame->r, t->higher)){
hidden[nhidden] = windows[i];
- menu3str[nhidden+Hidden] = windows[i]->label;
+ str[nhidden+Hidden] = windows[i]->label;
nhidden++;
}
}
- menu3str[nhidden+Hidden] = nil;
+ str[nhidden+Hidden] = nil;
- sel = menuhit(3, mctl, &menu3, wscreen);
+ sel = menuhit(3, mctl, &menu, wscreen);
switch(sel){
case New:
sweep(nil);
@@ -534,7 +540,7 @@
if(w) sweep(w);
break;
case Move:
- grab(nil);
+ grab(nil, 3);
break;
case Delete:
w = pick();
@@ -544,9 +550,6 @@
w = pick();
if(w) whide(w);
break;
- case Exit:
- killprocs();
- threadexitsall(nil);
default:
if(sel >= Hidden){
w = hidden[sel-Hidden];
@@ -562,57 +565,131 @@
}
void
+btn13menu(void)
+{
+ enum {
+ RefreshScreen,
+ Exit
+ };
+ static char *str[] = {
+ "Refresh",
+ "Exit",
+ nil
+ };
+ static Menu menu = { str };
+
+ switch(menuhit(3, mctl, &menu, wscreen)){
+ case RefreshScreen:
+ refresh();
+ break;
+ case Exit:
+ killprocs();
+ threadexitsall(nil);
+ }
+}
+
+void
+btn12menu(void)
+{
+ int dx, dy, i, j;
+
+ dx = Dx(screen->r);
+ dy = Dy(screen->r);
+ i = screenoff.x/dx;
+ j = screenoff.y/dy;
+ Point ssel = dmenuhit(2, mctl, ndeskx, ndesky, Pt(i,j));
+ if(ssel.x >= 0 && ssel.y >= 0)
+ screenoffset(ssel.x*dx, ssel.y*dy);
+}
+
+void
mthread(void*)
{
Window *w;
+ Channel *wc;
threadsetname("mousethread");
- while(readmouse(mctl) != -1){
- w = wpointto(mctl->xy);
- cursorwin = w;
+ enum { Amouse, Apick, NALT };
+ Alt alts[NALT+1] = {
+ [Amouse] {.c = mctl->c, .v = &mctl->Mouse, .op = CHANRCV},
+ [Apick] {.c = pickchan, .v = &wc, .op = CHANRCV},
+ [NALT] {.op = CHANEND},
+ };
+ for(;;){
+ // normally done in readmouse
+ Display *d = mctl->image->display;
+ if(d->bufp > d->buf)
+ flushimage(d, 1);
+ switch(alt(alts)){
+ case Apick:
+ sendp(wc, pick());
+ break;
+ case Amouse:
+ w = wpointto(mctl->xy);
+ cursorwin = w;
again:
- if(w == nil){
- setcursornormal(nil);
- if(mctl->buttons & 4)
- btn3menu();
- }else if(!ptinrect(mctl->xy, w->contrect)){
- /* border */
- setcursornormal(corners[whichcorner(w->img->r, mctl->xy)]);
- if(mctl->buttons & 7){
- wraise(w);
- wfocus(w);
+ if(w == nil){
+ /* background */
+ setcursornormal(nil);
+ while(mctl->buttons & 1){
+ if(mctl->buttons & 2)
+ btn12menu();
+ else if(mctl->buttons & 4)
+ btn13menu();
+ readmouse(mctl);
+ }
if(mctl->buttons & 4)
- grab(w);
- if(mctl->buttons & 3)
- bandresize(w);
- }
- }else if(w != focused){
- wsetcursor(w);
- if(mctl->buttons & 7 ||
- mctl->buttons & (8|16) && focused->mouseopen){
- wraise(w);
- wfocus(w);
- if(mctl->buttons & 1)
- drainmouse(mctl, nil);
- else
- goto again;
- }
- }else if(!w->mouseopen){
- wsetcursor(w);
- if(mctl->buttons && topwin != w)
- wraise(w);
- if(mctl->buttons & (1|8|16) || ptinrect(mctl->xy, w->text.scrollr))
+ btn3menu();
+ }else if(!ptinrect(mctl->xy, w->contrect)){
+ /* decoration */
+ if(!w->noborder &&
+ !ptinrect(mctl->xy, insetrect(w->frame->r, bordersz))){
+ /* border */
+ setcursornormal(corners[whichcorner(w->frame->r, mctl->xy)]);
+ if(mctl->buttons & 7){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 4)
+ grab(w, 3);
+ if(mctl->buttons & 3)
+ bandresize(w);
+ }
+ }else{
+ /* title bar */
+ setcursornormal(nil);
+ wtitlectl(w);
+ }
+ }else if(w != focused){
+ /* inactive window */
+ wsetcursor(w);
+ if(mctl->buttons & 7 ||
+ mctl->buttons & (8|16) && focused->mouseopen){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 1)
+ drainmouse(mctl, nil);
+ else
+ goto again;
+ }
+ }else if(!w->mouseopen){
+ /* active text window */
+ wsetcursor(w);
+ if(mctl->buttons && topwin != w)
+ wraise(w);
+ if(mctl->buttons & (1|8|16) || ptinrect(mctl->xy, w->text.scrollr))
+ drainmouse(mctl, w);
+ if(mctl->buttons & 2){
+ incref(w);
+ btn2menu(w);
+ wrelease(w);
+ }
+ if(mctl->buttons & 4)
+ btn3menu();
+ }else{
+ /* active graphics window */
+ wsetcursor(w);
drainmouse(mctl, w);
- if(mctl->buttons & 2){
- incref(w);
- btn2menu(w);
- wrelease(w);
}
- if(mctl->buttons & 4)
- btn3menu();
- }else{
- wsetcursor(w);
- drainmouse(mctl, w);
}
}
}
@@ -633,18 +710,42 @@
nr = screen->clipr;
freescrtemps();
+ freeimage(fakebg);
freescreen(wscreen);
wscreen = allocscreen(screen, background, 0);
- draw(screen, screen->r, background, nil, ZP);
+ fakebg = allocwindow(wscreen, screen->r, Refbackup, DNofill);
+ draw(fakebg, fakebg->r, background, nil, ZP);
delta = subpt(nr.min, or.min);
- for(w = bottomwin; w; w = w->higher)
- wresize(w, rectaddpt(w->img->r, delta));
+ for(w = bottomwin; w; w = w->higher){
+ if(w->maximized){
+ wrestore(w);
+ wresize(w, rectaddpt(w->frame->r, delta));
+ wmaximize(w);
+ }else
+ wresize(w, rectaddpt(w->frame->r, delta));
+ }
flushimage(display, 1);
}
}
+void
+refresh(void)
+{
+ Window *w;
+
+ draw(fakebg, fakebg->r, background, nil, ZP);
+ for(w = bottomwin; w; w = w->higher){
+ if(w->maximized){
+ wrestore(w);
+ wresize(w, w->frame->r);
+ wmaximize(w);
+ }else
+ wresize(w, w->frame->r);
+ }
+}
+
/*
* kbd -----+-------> to tap
* \
@@ -690,8 +791,10 @@
switch(alt(alts)){
case Akbd:
/* from keyboard to tap or to window */
- if(*s == 'k' || *s == 'K')
+ if(*s == 'k' || *s == 'K'){
shiftdown = utfrune(s+1, Kshift) != nil;
+ ctldown = utfrune(s+1, Kctl) != nil;
+ }
prev = cur;
cur = focused;
if(totap){
@@ -760,13 +863,42 @@
}
}
+Channel *pickchan;
+
void
-threadmain(int, char *[])
+usage(void)
{
+ fprint(2, "usage: lola [-s] [-t]\n");
+ exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
char buf[256];
-//rfork(RFENVG);
-//newwindow("-dx 1280 -dy 800");
+if(strcmp(argv[0]+1, ".out") == 0){
+rfork(RFENVG);
+newwindow("-dx 1280 -dy 800");
+scrolling = TRUE;
+notitle = FALSE;
+}
+ ARGBEGIN{
+/*
+ case 'i':
+ initstr = EARGF(usage());
+ break;
+*/
+ case 's':
+ scrolling = TRUE;
+ break;
+ case 't':
+ notitle = TRUE;
+ break;
+ default:
+ usage();
+ }ARGEND
+
if(getwd(buf, sizeof(buf)) == nil)
startdir = estrdup(".");
else
@@ -782,6 +914,8 @@
opentap = chancreate(sizeof(Channel*), 0);
closetap = chancreate(sizeof(Channel*), 0);
+ pickchan = chancreate(sizeof(Channel*), 0);
+
servekbd = kbctl->kbdfd >= 0;
snarffd = open("/dev/snarf", OREAD|OCEXEC);
gotscreen = access("/dev/screen", AEXIST)==0;
@@ -789,7 +923,8 @@
initdata();
wscreen = allocscreen(screen, background, 0);
- draw(screen, screen->r, background, nil, ZP);
+ fakebg = allocwindow(wscreen, screen->r, Refbackup, DNofill);
+ draw(fakebg, fakebg->r, background, nil, ZP);
timerinit();
--- /dev/null
+++ b/menuhit.c
@@ -1,0 +1,280 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+
+enum
+{
+ Margin = 4, /* outside to text */
+ Border = 2, /* outside to selection boxes */
+ Blackborder = 2, /* width of outlining border */
+ Vspacing = 2, /* extra spacing between lines of text */
+ Maxunscroll = 25, /* maximum #entries before scrolling turns on */
+ Nscroll = 20, /* number entries in scrolling part */
+ Scrollwid = 14, /* width of scroll bar */
+ Gap = 4, /* between text and scroll bar */
+};
+
+static Image *menutxt;
+static Image *back;
+static Image *high;
+static Image *bord;
+static Image *text;
+static Image *htext;
+
+Image *getcolor(char *name, ulong col);
+
+static
+void
+menucolors(void)
+{
+ /* Main tone is greenish, with negative selection */
+ back = getcolor("menuback", 0xEAFFEAFF);
+ high = getcolor("menuhigh", 0x448844FF); /* dark green */
+ bord = getcolor("menubord", 0x88CC88FF); /* not as dark green */
+ text = getcolor("menutext", 0x000000FF);
+ htext = getcolor("menuhtext", 0xEAFFEAFF);
+ if(back==nil || high==nil || bord==nil || text==nil || htext==nil)
+ goto Error;
+ return;
+
+ Error:
+ freeimage(back);
+ freeimage(high);
+ freeimage(bord);
+ freeimage(text);
+ freeimage(htext);
+ back = display->white;
+ high = display->black;
+ bord = display->black;
+ text = display->black;
+ htext = display->white;
+}
+
+/*
+ * r is a rectangle holding the text elements.
+ * return the rectangle, including its black edge, holding element i.
+ */
+static Rectangle
+menurect(Rectangle r, int i)
+{
+ if(i < 0)
+ return Rect(0, 0, 0, 0);
+ r.min.y += (font->height+Vspacing)*i;
+ r.max.y = r.min.y+font->height+Vspacing;
+ return insetrect(r, Border-Margin);
+}
+
+/*
+ * r is a rectangle holding the text elements.
+ * return the element number containing p.
+ */
+static int
+menusel(Rectangle r, Point p)
+{
+ if(!ptinrect(p, r))
+ return -1;
+ return (p.y-r.min.y)/(font->height+Vspacing);
+}
+
+static void
+paintitem(Image *m, Menu *menu, Rectangle textr, int off, int i, int highlight, Image *save, Image *restore)
+{
+ char *item;
+ Rectangle r;
+ Point pt;
+
+ if(i < 0)
+ return;
+ r = menurect(textr, i);
+ if(restore){
+ draw(m, r, restore, nil, restore->r.min);
+ return;
+ }
+ if(save)
+ draw(save, save->r, m, nil, r.min);
+ item = menu->item? menu->item[i+off] : (*menu->gen)(i+off);
+ pt.x = (textr.min.x+textr.max.x-stringwidth(font, item))/2;
+ pt.y = textr.min.y+i*(font->height+Vspacing);
+ draw(m, r, highlight? high : back, nil, pt);
+ string(m, pt, highlight? htext : text, pt, font, item);
+}
+
+/*
+ * menur is a rectangle holding all the highlightable text elements.
+ * track mouse while inside the box, return what's selected when button
+ * is raised, -1 as soon as it leaves box.
+ * invariant: nothing is highlighted on entry or exit.
+ */
+static int
+menuscan(Image *m, Menu *menu, int but, Mousectl *mc, Rectangle textr, int off, int lasti, Image *save)
+{
+ int i;
+
+ paintitem(m, menu, textr, off, lasti, 1, save, nil);
+ for(readmouse(mc); mc->buttons & (1<<(but-1)); readmouse(mc)){
+ i = menusel(textr, mc->xy);
+ if(i != -1 && i == lasti)
+ continue;
+ paintitem(m, menu, textr, off, lasti, 0, nil, save);
+ if(i == -1)
+ return i;
+ lasti = i;
+ paintitem(m, menu, textr, off, lasti, 1, save, nil);
+ }
+ return lasti;
+}
+
+static void
+menupaint(Image *m, Menu *menu, Rectangle textr, int off, int nitemdrawn)
+{
+ int i;
+
+ draw(m, insetrect(textr, Border-Margin), back, nil, ZP);
+ for(i = 0; i<nitemdrawn; i++)
+ paintitem(m, menu, textr, off, i, 0, nil, nil);
+}
+
+static void
+menuscrollpaint(Image *m, Rectangle scrollr, int off, int nitem, int nitemdrawn)
+{
+ Rectangle r;
+
+ draw(m, scrollr, back, nil, ZP);
+ r.min.x = scrollr.min.x;
+ r.max.x = scrollr.max.x;
+ r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem;
+ r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem;
+ if(r.max.y < r.min.y+2)
+ r.max.y = r.min.y+2;
+ border(m, r, 1, bord, ZP);
+ if(menutxt == 0)
+ menutxt = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DDarkgreen); /* border color; BUG? */
+ if(menutxt)
+ draw(m, insetrect(r, 1), menutxt, nil, ZP);
+}
+
+int
+menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr)
+{
+ int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem;
+ int scrolling;
+ Rectangle r, menur, sc, textr, scrollr;
+ Image *b, *save, *backup;
+ Point pt;
+ char *item;
+
+ if(back == nil)
+ menucolors();
+ sc = screen->clipr;
+ replclipr(screen, 0, screen->r);
+ maxwid = 0;
+ for(nitem = 0;
+ item = menu->item? menu->item[nitem] : (*menu->gen)(nitem);
+ nitem++){
+ i = stringwidth(font, item);
+ if(i > maxwid)
+ maxwid = i;
+ }
+ if(menu->lasthit<0 || menu->lasthit>=nitem)
+ menu->lasthit = 0;
+ screenitem = (Dy(screen->r)-10)/(font->height+Vspacing);
+ if(nitem>Maxunscroll || nitem>screenitem){
+ scrolling = 1;
+ nitemdrawn = Nscroll;
+ if(nitemdrawn > screenitem)
+ nitemdrawn = screenitem;
+ wid = maxwid + Gap + Scrollwid;
+ off = menu->lasthit - nitemdrawn/2;
+ if(off < 0)
+ off = 0;
+ if(off > nitem-nitemdrawn)
+ off = nitem-nitemdrawn;
+ lasti = menu->lasthit-off;
+ }else{
+ scrolling = 0;
+ nitemdrawn = nitem;
+ wid = maxwid;
+ off = 0;
+ lasti = menu->lasthit;
+ }
+ r = insetrect(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin);
+ r = rectsubpt(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2));
+ r = rectaddpt(r, mc->xy);
+ pt = ZP;
+ if(r.max.x>screen->r.max.x)
+ pt.x = screen->r.max.x-r.max.x;
+ if(r.max.y>screen->r.max.y)
+ pt.y = screen->r.max.y-r.max.y;
+ if(r.min.x<screen->r.min.x)
+ pt.x = screen->r.min.x-r.min.x;
+ if(r.min.y<screen->r.min.y)
+ pt.y = screen->r.min.y-r.min.y;
+ menur = rectaddpt(r, pt);
+ textr.max.x = menur.max.x-Margin;
+ textr.min.x = textr.max.x-maxwid;
+ textr.min.y = menur.min.y+Margin;
+ textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing);
+ if(scrolling){
+ scrollr = insetrect(menur, Border);
+ scrollr.max.x = scrollr.min.x+Scrollwid;
+ }else
+ scrollr = Rect(0, 0, 0, 0);
+
+ if(scr){
+ b = allocwindow(scr, menur, Refbackup, DWhite);
+ if(b == nil)
+ b = screen;
+ backup = nil;
+ }else{
+ b = screen;
+ backup = allocimage(display, menur, screen->chan, 0, -1);
+ if(backup)
+ draw(backup, menur, screen, nil, menur.min);
+ }
+ draw(b, menur, back, nil, ZP);
+ border(b, menur, Blackborder, bord, ZP);
+ save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1);
+ r = menurect(textr, lasti);
+ if(pt.x || pt.y)
+ moveto(mc, divpt(addpt(r.min, r.max), 2));
+ menupaint(b, menu, textr, off, nitemdrawn);
+ if(scrolling)
+ menuscrollpaint(b, scrollr, off, nitem, nitemdrawn);
+ while(mc->buttons & (1<<(but-1))){
+ lasti = menuscan(b, menu, but, mc, textr, off, lasti, save);
+ if(lasti >= 0)
+ break;
+ while(!ptinrect(mc->xy, textr) && (mc->buttons & (1<<(but-1)))){
+ if(scrolling && ptinrect(mc->xy, scrollr)){
+ noff = ((mc->xy.y-scrollr.min.y)*nitem)/Dy(scrollr);
+ noff -= nitemdrawn/2;
+ if(noff < 0)
+ noff = 0;
+ if(noff > nitem-nitemdrawn)
+ noff = nitem-nitemdrawn;
+ if(noff != off){
+ off = noff;
+ menupaint(b, menu, textr, off, nitemdrawn);
+ menuscrollpaint(b, scrollr, off, nitem, nitemdrawn);
+ }
+ }
+ readmouse(mc);
+ }
+ }
+ if(b != screen)
+ freeimage(b);
+ if(backup){
+ draw(screen, menur, backup, nil, menur.min);
+ freeimage(backup);
+ }
+ freeimage(save);
+ replclipr(screen, 0, sc);
+ flushimage(display, 1);
+ if(lasti >= 0){
+ menu->lasthit = lasti+off;
+ return menu->lasthit;
+ }
+ return -1;
+}
--- a/mkfile
+++ b/mkfile
@@ -10,7 +10,10 @@
util.$O \
kbd.$O \
time.$O \
- data.$O
+ data.$O \
+ menuhit.$O \
+ deskmenu.$O \
+ simple.$O
HFILES=inc.h
--- /dev/null
+++ b/simple.c
@@ -1,0 +1,233 @@
+#include "inc.h"
+
+int bordersz = 4;
+int titlesz = 17;//19;
+
+enum {
+ TITLE,
+ LTITLE,
+ TITLEHOLD,
+ LTITLEHOLD,
+ TITLETEXT,
+ LTITLETEXT,
+ TITLEHOLDTEXT,
+ LTITLEHOLDTEXT,
+ FRAME,
+ LFRAME,
+
+ NumWinColors
+};
+
+Image *wincolors[NumWinColors];
+Image *icons[4];
+
+void
+btn(Image *img, Rectangle r, Image *col, Image *icon, int down)
+{
+ USED(down);
+
+// border(img, r, 1, col, ZP);
+ r = centerrect(r, icon->r);
+ draw(img, r, col, icon, ZP);
+}
+
+int
+btnctl(Image *img, Rectangle r, Image *col, Image *icon)
+{
+ int over, prevover;
+
+ prevover = 1;
+ btn(img, r, col, icon, 1);
+ while(mctl->buttons){
+ readmouse(mctl);
+ over = ptinrect(mctl->xy, r);
+ if(over != prevover)
+ btn(img, r, col, icon, over);
+ prevover = over;
+ }
+ if(prevover)
+ btn(img, r, col, icon, 0);
+ return ptinrect(mctl->xy, r);
+}
+
+
+void
+wdecor(Window *w)
+{
+ if(w->frame == nil)
+ return;
+ int c = w->holdmode ?
+ w == focused ? TITLEHOLD : LTITLEHOLD :
+ w == focused ? TITLE : LTITLE;
+ int c2 = w == focused ? FRAME : LFRAME;
+
+ Rectangle r, b1, b2, b3;
+
+ if(!w->noborder){
+ r = w->frame->r;
+ border(w->frame, r, bordersz, wincolors[c], ZP);
+ border(w->frame, r, 1, wincolors[c2], ZP);
+ border(w->frame, insetrect(w->contrect,-1), 1, wincolors[c2], ZP);
+ }
+
+ if(!w->notitle){
+ r = w->titlerect;
+ r.max.y--;
+ draw(w->frame, r, wincolors[c], nil, ZP);
+
+ b1 = r;
+b1.max.x -= bordersz/2;
+ b1.min.x = b1.max.x - titlesz + bordersz;
+ b1.max.y = b1.min.y + Dx(b1);
+ b2 = rectsubpt(b1, Pt(titlesz, 0));
+ b3 = rectsubpt(b2, Pt(titlesz, 0));
+ btn(w->frame, b1, wincolors[c+4], icons[3], 0);
+ btn(w->frame, b2, wincolors[c+4], icons[1+w->maximized], 0);
+ btn(w->frame, b3, wincolors[c+4], icons[0], 0);
+
+r.min.x += bordersz/2;
+r.min.y -= 2;
+ Point pt = Pt(r.min.x, r.min.y);
+ string(w->frame, pt, wincolors[c+4], pt, font, w->label);
+ }
+}
+
+void
+wtitlectl(Window *w)
+{
+ if(mctl->buttons & 7){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 1) {
+ int c = w->holdmode ?
+ w == focused ? TITLEHOLD : LTITLEHOLD :
+ w == focused ? TITLE : LTITLE;
+
+ Rectangle r = w->titlerect;
+ Rectangle br = Rect(0,0,titlesz-bordersz,titlesz-bordersz);
+r.max.x -= bordersz/2;
+ Rectangle br1 = rectaddpt(br, Pt(r.max.x-titlesz+bordersz, r.min.y));
+ Rectangle br2 = rectsubpt(br1, Pt(titlesz, 0));
+ Rectangle br3 = rectsubpt(br2, Pt(titlesz, 0));
+ // hack...
+ if(w->notitle)
+ br1 = br2 = br3 = Rect(0,0,0,0);
+
+ if(ptinrect(mctl->xy, br1)){
+ if(btnctl(w->frame, br1, wincolors[c+4], icons[3]))
+ wdelete(w);
+ }else if(ptinrect(mctl->xy, br2)){
+ if(btnctl(w->frame, br2, wincolors[c+4], icons[1+w->maximized])){
+ if(w->maximized)
+ wrestore(w);
+ else
+ wmaximize(w);
+ }
+ }else if(ptinrect(mctl->xy, br3)){
+ if(btnctl(w->frame, br3, wincolors[c+4], icons[0]))
+ whide(w);
+ }else if(!w->maximized)
+ grab(w, 1);
+ }
+ if(mctl->buttons & 4)
+ btn3menu();
+ }
+}
+
+
+static char minbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char maxbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char rstbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char closebtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+void
+inittheme(void)
+{
+ freeimage(colors[HOLDTEXT]);
+ freeimage(colors[PALEHOLDTEXT]);
+ colors[HOLDTEXT] = getcolor("holdtext", 0x990000FF);
+ colors[PALEHOLDTEXT] = getcolor("paleholdtext", 0xBB5D00FF);
+
+// wincolors[TITLE] = getcolor("title", 0x607DA1FF);
+// wincolors[LTITLE] = getcolor("ltitle", 0xA1A1A1FF);
+
+// wincolors[TITLE] = getcolor("title", 0x2F78EDFF);
+// wincolors[LTITLE] = getcolor("ltitle", 0x7C9DE3FF);
+
+ wincolors[TITLE] = getcolor("title", 0x5297F9FF);
+ wincolors[LTITLE] = getcolor("ltitle", 0x2C60B2FF);
+ wincolors[TITLEHOLD] = getcolor("titlehold", 0xED2F2FFF);
+ wincolors[LTITLEHOLD] = getcolor("ltitlehold", 0xE36A6AFF);
+
+ wincolors[FRAME] = getcolor("frame", 0x000000FF);
+ wincolors[LFRAME] = getcolor("lframe", 0x000000FF);
+
+ wincolors[TITLETEXT] = getcolor("titletext", 0xFFFFFFFF);
+ wincolors[LTITLETEXT] = getcolor("ltitletext", 0xFFFFFFFF);
+ wincolors[TITLEHOLDTEXT] = getcolor("titleholdtext", 0xFFFFFFFF);
+ wincolors[LTITLEHOLDTEXT] = getcolor("ltitleholdtext", 0xFFFFFFFF);
+
+ icons[0] = mkicon(minbtn, 16, 13);
+ icons[1] = mkicon(maxbtn, 16, 13);
+ icons[2] = mkicon(rstbtn, 16, 13);
+ icons[3] = mkicon(closebtn, 16, 13);
+}
--- a/util.c
+++ b/util.c
@@ -1,5 +1,44 @@
#include "inc.h"
+/* Center rect s in rect r */
+Rectangle
+centerrect(Rectangle r, Rectangle s)
+{
+ int dx = (Dx(r) - Dx(s))/2;
+ int dy = (Dy(r) - Dy(s))/2;
+ return rectaddpt(Rect(0, 0, Dx(s), Dy(s)), Pt(r.min.x+dx, r.min.y+dy));
+}
+
+void
+borderTL(Image *img, Rectangle r, Image *c)
+{
+ // left
+ draw(img, Rect(r.min.x, r.min.y, r.min.x+1, r.max.y),
+ c, nil, ZP);
+ // top
+ draw(img, Rect(r.min.x, r.min.y, r.max.x, r.min.y+1),
+ c, nil, ZP);
+}
+
+void
+borderBR(Image *img, Rectangle r, Image *c)
+{
+ // bottom
+ draw(img, Rect(r.min.x, r.max.y-1, r.max.x, r.max.y),
+ c, nil, ZP);
+ // right
+ draw(img, Rect(r.max.x-1, r.min.y, r.max.x, r.max.y),
+ c, nil, ZP);
+}
+
+void
+winborder(Image *img, Rectangle r, Image *c1, Image *c2)
+{
+ borderTL(img, r, c1);
+ borderBR(img, r, c2);
+}
+
+
void
panic(char *s)
{
--- a/wctl.c
+++ b/wctl.c
@@ -7,14 +7,22 @@
char Ebadwr[] = "bad rectangle in wctl request";
char Ewalloc[] = "window allocation failed in wctl request";
-/* >= Top are disallowed if mouse button is pressed */
+/* >= Top are disallowed if mouse button is pressed.
+ * >= New need a window. */
enum
{
+ Screenoffset,
New,
Resize,
Move,
Scroll,
Noscroll,
+ Border,
+ Noborder,
+ Title,
+ Notitle,
+ Sticky,
+ Nosticky,
Set,
Top,
Bottom,
@@ -25,11 +33,18 @@
};
static char *cmds[] = {
+ [Screenoffset] = "screenoffset",
[New] = "new",
[Resize] = "resize",
[Move] = "move",
[Scroll] = "scroll",
[Noscroll] = "noscroll",
+ [Border] = "border",
+ [Noborder] = "noborder",
+ [Title] = "title",
+ [Notitle] = "notitle",
+ [Sticky] = "sticky",
+ [Nosticky] = "nosticky",
[Set] = "set",
[Top] = "top",
[Bottom] = "bottom",
@@ -161,8 +176,14 @@
cmd.cmd = word(&s, cmds);
if(cmd.cmd < 0)
goto Lose;
- if(cmd.cmd == New)
+ switch(cmd.cmd){
+ case Screenoffset:
+ r = ZR;
+ break;
+ case New:
r = newrect();
+ break;
+ }
while((param = word(&s, params)) >= 0){
switch(param){ /* special cases */
@@ -247,7 +268,10 @@
break;
}
}
- cmd.r = rectonscreen(rectaddpt(r, screen->r.min));
+ if(cmd.cmd == Screenoffset)
+ cmd.r = r;
+ else
+ cmd.r = rectonscreen(rectaddpt(r, screen->r.min));
while(isspacerune(*s))
s++;
if(cmd.cmd != New && *s != '\0'){
@@ -266,16 +290,16 @@
{
switch(cmd){
case Move:
- r = rectaddpt(Rect(0,0,Dx(w->img->r),Dy(w->img->r)), r.min);
+ r = rectaddpt(Rect(0,0,Dx(w->frame->r),Dy(w->frame->r)), r.min);
if(!goodrect(r))
return Ebadwr;
- if(!eqpt(r.min, w->img->r.min))
+ if(!eqpt(r.min, w->frame->r.min))
wmove(w, r.min);
break;
case Resize:
if(!goodrect(r))
return Ebadwr;
- if(!eqrect(r, w->img->r))
+ if(!eqrect(r, w->frame->r))
wresize(w, r);
break;
// TODO: these three work somewhat differently in rio
@@ -315,6 +339,31 @@
w->scrolling = FALSE;
wsendmsg(w, Wakeup);
break;
+ case Border:
+ w->noborder &= ~1;
+ wresize(w, w->frame->r);
+ break;
+ case Noborder:
+ w->noborder |= 1;
+ wresize(w, w->frame->r);
+ break;
+ case Title:
+ w->notitle = FALSE;
+ wresize(w, w->frame->r);
+ break;
+ case Notitle:
+ w->notitle = TRUE;
+ wresize(w, w->frame->r);
+ break;
+ case Sticky:
+ w->sticky = TRUE;
+ break;
+ case Nosticky:
+ w->sticky = FALSE;
+ break;
+ case Screenoffset:
+ screenoffset(r.min.x, r.min.y);
+ break;
default:
return "invalid wctl message";
}
@@ -359,7 +408,7 @@
if(w == nil)
r = ZR;
else
- r = rectsubpt(w->img->r, screen->r.min);
+ r = rectsubpt(w->frame->r, screen->r.min);
cmd = parsewctl(data, r);
if(cmd.error)
return cmd.error;
@@ -370,7 +419,7 @@
return "no such window id";
}
- if(w == nil && cmd.cmd != New)
+ if(w == nil && cmd.cmd > New)
return "command needs to be run within a window";
switch(cmd.cmd){
--- /dev/null
+++ b/win3.c
@@ -1,0 +1,311 @@
+#include "inc.h"
+
+int bordersz = 4;
+int titlesz = 19;
+
+enum {
+ ColDefault,
+ ColHilight,
+ ColShadow,
+ ColTitle,
+ ColTitleInact,
+ ColTitleText,
+ ColTitleTextInact,
+
+ ColFrame,
+ ColBorder,
+ ColBorderInact,
+
+ NumWinColors
+};
+
+Image *wincolors[NumWinColors];
+Image *icons[5];
+
+void
+winbtn(Image *img, Rectangle r, Image *icon, int down)
+{
+ draw(img, r, wincolors[ColDefault], nil, ZP);
+ if(down){
+ borderTL(img, r, wincolors[ColShadow]);
+ r = insetrect(r, 1);
+ }else{
+ winborder(img, r, wincolors[ColHilight], wincolors[ColShadow]);
+ r = insetrect(r, 1);
+ borderBR(img, r, wincolors[ColShadow]);
+ }
+
+ r = centerrect(r, icon->r);
+ if(down)
+ r = rectaddpt(r, Pt(1,1));
+ draw(img, r, icon, icon, ZP);
+}
+
+void
+winbtnflat(Image *img, Rectangle r, Image *icon, Image *icondown, int down)
+{
+ if(down){
+ draw(img, r, wincolors[ColShadow], nil, ZP);
+ }else{
+ draw(img, r, wincolors[ColDefault], nil, ZP);
+ }
+
+ r = centerrect(r, icon->r);
+ if(down)
+ icon = icondown;
+ draw(img, r, icon, icon, ZP);
+}
+
+int
+winbtnctl(Image *img, Rectangle r, Image *icon)
+{
+ int over, prevover;
+
+ prevover = 1;
+ winbtn(img, r, icon, 1);
+ while(mctl->buttons){
+ readmouse(mctl);
+ over = ptinrect(mctl->xy, r);
+ if(over != prevover)
+ winbtn(img, r, icon, over);
+ prevover = over;
+ }
+ if(prevover)
+ winbtn(img, r, icon, 0);
+ return ptinrect(mctl->xy, r);
+}
+
+int
+winbtnctlflat(Image *img, Rectangle r, Image *icon, Image *icondown)
+{
+ int over, prevover;
+
+ prevover = 1;
+ winbtnflat(img, r, icon, icondown, 1);
+ while(mctl->buttons){
+ readmouse(mctl);
+ over = ptinrect(mctl->xy, r);
+ if(over != prevover)
+ winbtnflat(img, r, icon, icondown, over);
+ prevover = over;
+ }
+ if(prevover)
+ winbtnflat(img, r, icon, icondown, 0);
+ return ptinrect(mctl->xy, r);
+}
+
+
+
+void
+wdecor(Window *w)
+{
+ if(w->frame == nil)
+ return;
+
+ Rectangle r = w->frame->r;
+
+ if(!w->noborder){
+ border(w->frame, r, bordersz, wincolors[w == focused ? ColBorder : ColBorderInact], ZP);
+ border(w->frame, r, 1, wincolors[ColFrame], ZP);
+ border(w->frame, insetrect(r,3), 1, wincolors[ColFrame], ZP);
+
+ Rectangle br = rectaddpt(Rect(0,0,1,bordersz), r.min);
+ int dx = Dx(r);
+ int dy = Dy(r);
+ int off = bordersz+titlesz-1;
+ draw(w->frame, rectaddpt(br, Pt(off,0)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(off,dy-bordersz)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(dx-1-off,0)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(dx-1-off,dy-bordersz)), wincolors[ColFrame], nil, ZP);
+
+ br = rectaddpt(Rect(0,0,bordersz,1), r.min);
+ draw(w->frame, rectaddpt(br, Pt(0,off)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(dx-bordersz,off)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(0,dy-1-off)), wincolors[ColFrame], nil, ZP);
+ draw(w->frame, rectaddpt(br, Pt(dx-bordersz,dy-1-off)), wincolors[ColFrame], nil, ZP);
+
+ r = insetrect(r, bordersz);
+ }
+
+ if(!w->notitle){
+ r.max.y = r.min.y + titlesz-1;
+ draw(w->frame, r, wincolors[w == focused ? ColTitle : ColTitleInact], nil, ZP);
+ draw(w->frame, Rect(r.min.x,r.max.y,r.max.x,r.max.y+1), wincolors[ColFrame], nil, ZP);
+
+ // menu
+ Rectangle br = Rect(r.min.x,r.min.y,r.min.x+titlesz-1,r.min.y+titlesz-1);
+ winbtnflat(w->frame, br, icons[3], icons[4], 0);
+ border(w->frame, insetrect(br,-1), 1, display->black, ZP);
+
+ // max/restore
+ br.max.x = r.max.x;
+ br.min.x = br.max.x-titlesz-1;
+ winbtn(w->frame, br, icons[1+w->maximized], 0);
+ border(w->frame, insetrect(br,-1), 1, display->black, ZP);
+
+ // min
+ br = rectaddpt(br, Pt(-titlesz-2,0));
+ winbtn(w->frame, br, icons[0], 0);
+ border(w->frame, insetrect(br,-1), 1, display->black, ZP);
+
+ int sp = (Dx(r)-stringwidth(font, w->label))/2;
+ Point pt = Pt(r.min.x+sp, r.min.y);
+ string(w->frame, pt, wincolors[w == focused ? ColTitleText : ColTitleTextInact], pt, font, w->label);
+ }
+}
+
+void
+wtitlectl(Window *w)
+{
+ if(mctl->buttons & 7){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 1) {
+ Rectangle r = w->frame->r;
+ if(!w->noborder)
+ r = insetrect(r, bordersz);
+ Rectangle br = Rect(0,0,titlesz-1,titlesz-1);
+ Rectangle br1 = rectaddpt(br, r.min);
+ Rectangle br2 = rectaddpt(br1, Pt(Dx(r)-titlesz-1, 0));
+ Rectangle br3 = rectaddpt(br2, Pt(-titlesz-2, 0));
+ // hack...
+ if(w->notitle)
+ br1 = br2 = br3 = Rect(0,0,0,0);
+
+ if(ptinrect(mctl->xy, br1)){
+ if(winbtnctlflat(w->frame, br1, icons[3], icons[4]))
+ wdelete(w);
+ }else if(ptinrect(mctl->xy, br2)){
+ if(winbtnctl(w->frame, br2, icons[1+w->maximized])){
+ if(w->maximized)
+ wrestore(w);
+ else
+ wmaximize(w);
+ }
+ }else if(ptinrect(mctl->xy, br3)){
+ if(winbtnctl(w->frame, br3, icons[0]))
+ whide(w);
+ }else if(!w->maximized)
+ grab(w, 1);
+ }
+ if(mctl->buttons & 4)
+ btn3menu();
+ }
+}
+
+
+static char minbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char maxbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char rstbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char menubtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 6, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 0,
+ 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static char menubtninv[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 7, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0,
+ 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+
+void
+inittheme(void)
+{
+ wincolors[ColDefault] = getcolor("button_face", 0xC0C7C8FF);
+ wincolors[ColHilight] = getcolor("button_hilight", 0xFFFFFFFF);
+ wincolors[ColShadow] = getcolor("button_shadow", 0x87888FFF);
+ wincolors[ColTitle] = getcolor("titlebar_active", 0x5787a8FF);
+ wincolors[ColTitleInact] = getcolor("titlebar_inactive", 0xFFFFFFFF);
+ wincolors[ColTitleText] = getcolor("titlebar_text_active", 0xFFFFFFFF);
+ wincolors[ColTitleTextInact] = getcolor("titlebar_text_inactive", 0x000000FF);
+ wincolors[ColFrame] = getcolor("window_frame", 0x000000FF);
+ wincolors[ColBorder] = getcolor("border_active", 0xC0C7C8FF);
+ wincolors[ColBorderInact] = getcolor("border_inactive", 0xFFFFFFFF);
+
+ icons[0] = mkicon(minbtn, 16, 16);
+ icons[1] = mkicon(maxbtn, 16, 16);
+ icons[2] = mkicon(rstbtn, 16, 16);
+ icons[3] = mkicon(menubtn, 16, 16);
+ icons[4] = mkicon(menubtninv, 16, 16);
+}
--- /dev/null
+++ b/win95.c
@@ -1,0 +1,254 @@
+#include "inc.h"
+
+int bordersz = 4;
+int titlesz = 19;
+
+enum {
+ ColDefault,
+ ColLight1,
+ ColLight2,
+ ColDark1,
+ ColDark2,
+ ColTitle,
+ ColTitleInact,
+ ColTitleText,
+ ColTitleTextInact,
+
+ NumWinColors
+};
+
+Image *wincolors[NumWinColors];
+Image *icons[5];
+
+void
+winbtn(Image *img, Rectangle r, Image *icon, int down)
+{
+ if(down){
+ winborder(img, r, wincolors[ColDark2], wincolors[ColLight2]);
+ r = insetrect(r, 1);
+ winborder(img, r, wincolors[ColDark1], wincolors[ColLight1]);
+ }else{
+ winborder(img, r, wincolors[ColLight2], wincolors[ColDark2]);
+ r = insetrect(r, 1);
+ winborder(img, r, wincolors[ColLight1], wincolors[ColDark1]);
+ }
+ r = insetrect(r, 1);
+ draw(img, r, wincolors[ColDefault], nil, ZP);
+
+ r = insetrect(r,-2);
+ if(down)
+ r = rectaddpt(r, Pt(1,1));
+ draw(img, r, icon, icon, ZP);
+}
+
+void
+winframe(Image *img, Rectangle r)
+{
+ winborder(img, r, wincolors[ColLight1], wincolors[ColDark2]);
+ r = insetrect(r, 1);
+ winborder(img, r, wincolors[ColLight2], wincolors[ColDark1]);
+}
+
+int
+winbtnctl(Image *img, Rectangle r, Image *icon)
+{
+ int over, prevover;
+
+ prevover = 1;
+ winbtn(img, r, icon, 1);
+ while(mctl->buttons){
+ readmouse(mctl);
+ over = ptinrect(mctl->xy, r);
+ if(over != prevover)
+ winbtn(img, r, icon, over);
+ prevover = over;
+ }
+ if(prevover)
+ winbtn(img, r, icon, 0);
+ return ptinrect(mctl->xy, r);
+}
+
+void
+wdecor(Window *w)
+{
+ if(w->frame == nil)
+ return;
+
+ Rectangle r = w->frame->r;
+
+ if(!w->noborder){
+ border(w->frame, r, bordersz, wincolors[ColDefault], ZP);
+ winframe(w->frame, r);
+ r = insetrect(r, bordersz);
+ }
+
+ if(!w->notitle){
+ r.max.y = r.min.y + titlesz-1;
+ draw(w->frame, r, wincolors[w == focused ? ColTitle : ColTitleInact], nil, ZP);
+ draw(w->frame, Rect(r.min.x,r.max.y,r.max.x,r.max.y+1), wincolors[ColDefault], nil, ZP);
+
+ // draw buttons
+ Rectangle br = insetrect(r, 2);
+ br.min.x = br.max.x - Dy(br) - 2;
+ winbtn(w->frame, br, icons[3], 0);
+ br = rectaddpt(br, Pt(-Dx(br)-2, 0));
+ winbtn(w->frame, br, icons[1+w->maximized], 0);
+ br = rectaddpt(br, Pt(-Dx(br), 0));
+ winbtn(w->frame, br, icons[0], 0);
+
+ br = rectaddpt(icons[4]->r, insetrect(r,1).min);
+ draw(w->frame, br, icons[4], icons[4], ZP);
+
+ Point pt = Pt(r.min.x + 2 + titlesz-1, r.min.y);
+ string(w->frame, pt, wincolors[w == focused ? ColTitleText : ColTitleTextInact], pt, font, w->label);
+ }
+}
+
+void
+wtitlectl(Window *w)
+{
+ if(mctl->buttons & 7){
+ wraise(w);
+ wfocus(w);
+ if(mctl->buttons & 1) {
+ Rectangle r = w->frame->r;
+ if(!w->noborder)
+ r = insetrect(r, bordersz);
+ r.max.y = r.min.y + titlesz-1;
+ Rectangle br1 = insetrect(r, 2);
+ br1.min.x = br1.max.x - Dy(br1) - 2;
+ Rectangle br2 = rectaddpt(br1, Pt(-Dx(br1)-2, 0));
+ Rectangle br3 = rectaddpt(br1, Pt(-2*Dx(br1)-2, 0));
+ // hack...
+ if(w->notitle)
+ br1 = br2 = br3 = Rect(0,0,0,0);
+
+ if(ptinrect(mctl->xy, br1)){
+ if(winbtnctl(w->frame, br1, icons[3]))
+ wdelete(w);
+ }else if(ptinrect(mctl->xy, br2)){
+ if(winbtnctl(w->frame, br2, icons[1+w->maximized])){
+ if(w->maximized)
+ wrestore(w);
+ else
+ wmaximize(w);
+ }
+ }else if(ptinrect(mctl->xy, br3)){
+ if(winbtnctl(w->frame, br3, icons[0]))
+ whide(w);
+ }else if(!w->maximized)
+ grab(w, 1);
+ }
+ if(mctl->buttons & 4)
+ btn3menu();
+ }
+}
+
+
+
+static char minbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char maxbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char rstbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char closebtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static char appbtn[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 0, 0, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 1,
+ 0, 0, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 1,
+ 0, 0, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+void
+inittheme(void)
+{
+ wincolors[ColDefault] = getcolor("3d_face", 0xC0C0C0FF);
+ wincolors[ColLight1] = getcolor("3d_hilight1", 0xDFDFDFFF);
+ wincolors[ColLight2] = getcolor("3d_hilight2", 0xFFFFFFFF);
+ wincolors[ColDark1] = getcolor("3d_shadow1", 0x808080FF);
+ wincolors[ColDark2] = getcolor("3d_shadow2", 0x000000FF);
+ wincolors[ColTitle] = getcolor("titlebar_active", 0x000080FF);
+ wincolors[ColTitleInact] = getcolor("titlebar_inactive", 0x808080FF);
+ wincolors[ColTitleText] = getcolor("titlebar_text_active", 0xFFFFFFFF);
+ wincolors[ColTitleTextInact] = getcolor("titlebar_text_inactive", 0xC0C0C0FF);
+
+ icons[0] = mkicon(minbtn, 16, 14);
+ icons[1] = mkicon(maxbtn, 16, 14);
+ icons[2] = mkicon(rstbtn, 16, 14);
+ icons[3] = mkicon(closebtn, 16, 14);
+ icons[4] = mkicon(appbtn, 16, 16);
+}
--- a/wind.c
+++ b/wind.c
@@ -5,6 +5,8 @@
int nwindows;
Window *focused, *cursorwin;
+Point screenoff;
+
static void winthread(void *arg);
static void
@@ -43,31 +45,43 @@
}
void
-wcalcrects(Window *w)
+wmaximize(Window *w)
{
- if(w->noborder)
- w->contrect = w->img->r;
- else
- w->contrect = insetrect(w->img->r, Borderwidth);
- Rectangle r = insetrect(w->contrect, 1);
- w->scrollr = r;
- w->scrollr.max.x = w->scrollr.min.x + 12;
- w->textr = r;
- w->textr.min.x = w->scrollr.max.x + 4;
+ w->maximized = 1;
+ w->noborder |= 2;
+ w->origrect = w->frame->r;
+ wresize(w, screen->r);
}
void
-wdecor(Window *w)
+wrestore(Window *w)
{
- if(w->noborder)
- return;
- int c = w->holdmode ?
- w == focused ? TITLEHOLD : LTITLEHOLD :
- w == focused ? TITLE : LTITLE;
- border(w->img, w->img->r, Borderwidth, colors[c], ZP);
+ w->maximized = 0;
+ w->noborder &= ~2;
+ wresize(w, w->origrect);
}
void
+wcalcrects(Window *w, Rectangle r)
+{
+ w->contrect = r;
+ if(!w->noborder)
+ w->contrect = insetrect(w->contrect, bordersz);
+ if(!w->notitle){
+ w->titlerect = w->contrect;
+ w->titlerect.max.y = w->titlerect.min.y + titlesz;
+ w->contrect.min.y += titlesz;
+ }else
+ w->titlerect = ZR;
+
+ r = insetrect(w->contrect, 1);
+ w->scrollr = r;
+ w->scrollr.max.x = w->scrollr.min.x + 12;
+ w->textr = r;
+ w->textr.min.x = w->scrollr.max.x + 4;
+}
+
+void
wsetcolors(Window *w)
{
int c = w->holdmode ?
@@ -77,21 +91,41 @@
}
static void
+wfreeimages(Window *w)
+{
+ if(w->frame == nil)
+ return;
+
+ Screen *s = w->content->screen;
+ freeimage(w->content);
+ w->content = nil;
+
+ freescreen(s);
+
+ freeimage(w->frame);
+ w->frame = nil;
+}
+
+static void
wsetsize(Window *w, Rectangle r)
{
Rectangle hr;
+ Screen *s;
- if(w->img)
- freeimage(w->img);
+ wfreeimages(w);
if(w->hidden){
hr = rectaddpt(r, subpt(screen->r.max, r.min));
- w->img = allocwindow(wscreen, hr, Refbackup, DNofill);
- originwindow(w->img, r.min, hr.min);
+ w->frame = allocwindow(wscreen, hr, Refbackup, DNofill);
+ originwindow(w->frame, r.min, hr.min);
}else
- w->img = allocwindow(wscreen, r, Refbackup, DNofill);
- wcalcrects(w);
- draw(w->img, w->img->r, colors[BACK], nil, ZP);
- xinit(&w->text, w->textr, w->scrollr, font, w->img, colors);
+ w->frame = allocwindow(wscreen, r, Refbackup, DNofill);
+ s = allocscreen(w->frame, colors[BACK], 0);
+ assert(s);
+ wcalcrects(w, r);
+ w->content = allocwindow(s, w->contrect, Refnone, DNofill);
+ assert(w->content);
+ draw(w->frame, w->frame->r, colors[BACK], nil, ZP);
+ xinit(&w->text, w->textr, w->scrollr, font, w->content, colors);
}
static int id = 1;
@@ -109,6 +143,7 @@
w->dir = estrdup(startdir);
w->hidden = hidden;
w->scrolling = scrolling;
+ w->notitle = notitle; // TODO: argument?
wsetsize(w, r);
wdecor(w);
wlistpushfront(w);
@@ -117,7 +152,6 @@
windows[nwindows++] = w;
w->mc.c = chancreate(sizeof(Mouse), 16);
-
w->gone = chancreate(sizeof(int), 0);
w->kbd = chancreate(sizeof(char*), 16);
w->ctl = chancreate(sizeof(int), 0);
@@ -175,12 +209,7 @@
memmove(&windows[i], &windows[i+1], (nwindows-i)*sizeof(Window*));
break;
}
- if(w->img){
- /* rio does this, not sure if useful */
- originwindow(w->img, w->img->r.min, screen->r.max);
- freeimage(w->img);
- }
- w->img = nil;
+ wfreeimages(w);
flushimage(display, 1);
}
@@ -231,7 +260,7 @@
Window *w;
for(w = topwin; w; w = w->lower)
- if(!w->hidden && ptinrect(pt, w->img->r))
+ if(!w->hidden && ptinrect(pt, w->frame->r))
return w;
return nil;
}
@@ -248,6 +277,7 @@
{
free(w->label);
w->label = estrdup(label);
+ wdecor(w);
}
void
@@ -256,9 +286,9 @@
int i, n;
char err[ERRMAX];
- n = snprint(w->name, sizeof(w->name)-2, "%s.%d.%d", w->noborder ? "noborder" : "window", w->id, w->namecount++);
+ n = snprint(w->name, sizeof(w->name)-2, "%s.%d.%d", "noborder", w->id, w->namecount++);
for(i='A'; i<='Z'; i++){
- if(nameimage(w->img, w->name, 1) > 0)
+ if(nameimage(w->content, w->name, 1) > 0)
return;
errstr(err, sizeof err);
if(strcmp(err, "image name in use") != 0)
@@ -314,7 +344,7 @@
Window *w;
for(w = bottomwin; w; w = w->higher)
if(!w->hidden)
- topwindow(w->img);
+ topwindow(w->frame);
}
void
@@ -337,14 +367,14 @@
*
* We don't care if we're handling resizing ourselves though */
- if(w->mouseopen){
- delta = subpt(pos, w->img->r.min);
- wresize(w, rectaddpt(w->img->r, delta));
+ if(1 || w->mouseopen){
+ delta = subpt(pos, w->frame->r.min);
+ wresize(w, rectaddpt(w->frame->r, delta));
}else{
- originwindow(w->img, pos, w->hidden ? screen->r.max : pos);
+ originwindow(w->frame, pos, w->hidden ? screen->r.max : pos);
if(w != topwin && !w->hidden)
worder();
- wcalcrects(w);
+ wcalcrects(w, w->frame->r);
xsetrects(&w->text, w->textr, w->scrollr);
wsendmsg(w, Moved);
}
@@ -355,7 +385,7 @@
{
wlistremove(w);
wlistpushfront(w);
- topwindow(w->img);
+ topwindow(w->frame);
flushimage(display, 1);
}
@@ -364,7 +394,8 @@
{
wlistremove(w);
wlistpushback(w);
- bottomwindow(w->img);
+ bottomwindow(w->frame);
+ bottomwindow(fakebg);
flushimage(display, 1);
}
@@ -403,9 +434,13 @@
wfocuschanged(focused);
}
+/* Take away focus but also get rid of the window visually.
+ * For hiding/deleting */
void
wunfocus(Window *w)
{
+ if(!w->deleted)
+ originwindow(w->frame, w->frame->r.min, screen->r.max);
if(w == focused)
wfocus(nil);
}
@@ -419,7 +454,6 @@
wunfocus(w);
w->hidden = TRUE;
w->wctlready = TRUE;
- originwindow(w->img, w->img->r.min, screen->r.max);
wsendmsg(w, Wakeup);
wrelease(w);
return 1;
@@ -433,7 +467,7 @@
incref(w);
w->hidden = FALSE;
w->wctlready = TRUE;
- originwindow(w->img, w->img->r.min, w->img->r.min);
+ originwindow(w->frame, w->frame->r.min, w->frame->r.min);
wraise(w);
wfocus(w);
wrelease(w);
@@ -753,7 +787,7 @@
/* take over window again */
if(w->deleted)
break;
- draw(w->img, w->img->r, x->cols[BACK], nil, ZP);
+ draw(w->content, w->content->r, x->cols[BACK], nil, ZP);
wdecor(w);
xfullredraw(&w->text);
break;
@@ -948,7 +982,8 @@
w->wctlready = FALSE;
recv(fsc, &pair);
pair.ns = snprint(pair.s, pair.ns, "%11d %11d %11d %11d %11s %11s ",
- w->img->r.min.x, w->img->r.min.y, w->img->r.max.x, w->img->r.max.y,
+ w->frame->r.min.x, w->frame->r.min.y,
+ w->frame->r.max.x, w->frame->r.max.y,
w == focused ? "current" : "notcurrent",
w->hidden ? "hidden" : "visible");
send(fsc, &pair);
@@ -959,7 +994,7 @@
break;
case AComplete:
- if(w->img!=nil){
+ if(w->frame){
if(!comp->advance)
showcandidates(w, comp);
if(comp->advance){
@@ -1064,4 +1099,31 @@
}
return pid;
+}
+
+void
+screenoffset(int offx, int offy)
+{
+ Window *w;
+ Point off, delta;
+
+ off = Pt(offx, offy);
+ delta = subpt(off, screenoff);
+ screenoff = off;
+ for(w = bottomwin; w; w = w->higher){
+ if(w->sticky){
+ /* Don't move but cause resize event because
+ * program may want some kind of notification */
+ wmove(w, w->frame->r.min);
+ continue;
+ }
+ if(w->maximized){
+ wrestore(w);
+ wmove(w, subpt(w->frame->r.min, delta));
+ wmaximize(w);
+ }else
+ wmove(w, subpt(w->frame->r.min, delta));
+ }
+
+ flushimage(display, 1);
}