diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/wmclient.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/wmclient.b')
| -rw-r--r-- | appl/lib/wmclient.b | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/appl/lib/wmclient.b b/appl/lib/wmclient.b new file mode 100644 index 00000000..d205f17c --- /dev/null +++ b/appl/lib/wmclient.b @@ -0,0 +1,346 @@ +implement Wmclient; + +# +# Copyright © 2003 Vita Nuova Holdings Limited +# + +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + Display, Image, Screen, Rect, Point, Pointer, Wmcontext, Context: import draw; +include "tk.m"; + tk: Tk; + Toplevel: import tk; +include "wmlib.m"; + wmlib: Wmlib; + qword, splitqword, s2r: import wmlib; +include "titlebar.m"; + titlebar: Titlebar; +include "wmclient.m"; + +Focusnone, Focusimage, Focustitle: con iota; + +Bdup: con int 16rffffffff; +Bddown: con int 16radadadff; + +init() +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + tk = load Tk Tk->PATH; + wmlib = load Wmlib Wmlib->PATH; + if(wmlib == nil){ + sys->fprint(sys->fildes(2), "wmclient: cannot load %s: %r\n", Wmlib->PATH); + raise "fail:bad module"; + } + wmlib->init(); + titlebar = load Titlebar Titlebar->PATH; + if(titlebar == nil){ + sys->fprint(sys->fildes(2), "wmclient: cannot load %s: %r\n", Titlebar->PATH); + raise "fail:bad module"; + } + titlebar->init(); +} + +makedrawcontext(): ref Draw->Context +{ + return wmlib->makedrawcontext(); +} + +cursorspec(img: ref Draw->Image): string +{ + Hex: con "0123456789abcdef"; + if(img == nil || img.depth != 1) + return "cursor"; + display := img.display; + hot := img.r.min; + if(img.r.min.x != 0 || img.r.min.y != 0){ + n := display.newimage(((0, 0), img.r.size()), Draw->GREY1, 0, Draw->Nofill); + n.draw(n.r, img, nil, img.r.min); + img = n; + } + s := sys->sprint("cursor %d %d %d %d ", hot.x, hot.y, img.r.dx(), img.r.dy()); + nb := img.r.dy() * draw->bytesperline(img.r, img.depth); + buf := array[nb] of byte; + if(img.readpixels(img.r, buf) == -1) + return "cursor"; + + for(i := 0; i < nb; i++){ + c := int buf[i]; + s[len s] = Hex[c >> 4]; + s[len s] = Hex[c & 16rf]; + } + return s; +} + +blankwin: Window; +window(ctxt: ref Draw->Context, title: string, buts: int): ref Window +{ + w := ref blankwin; + w.ctxt = wmlib->connect(ctxt); + w.display = ctxt.display; + w.ctl = chan of string; + readscreenrect(w); + + if(buts & Plain) + return w; + + if(ctxt.wm == nil) + buts &= ~(Resize|Hide); + + w.bd = 1; + w.titlebar = tk->toplevel(ctxt.display, nil); + top := w.titlebar; + top.wreq = nil; + + w.ctl = titlebar->new(top, buts); + titlebar->settitle(top, title); + sizetb(w); + w.wmctl("fixedorigin"); + return w; +} + +Window.pointer(w: self ref Window, p: Draw->Pointer): int +{ + if(w.screen == nil || w.titlebar == nil) + return 0; + + if(p.buttons && (w.ptrfocus == Focusnone || w.buttons == 0)){ + if(p.xy.in(w.tbrect)) + w.ptrfocus = Focustitle; + else + w.ptrfocus = Focusimage; + } + w.buttons = p.buttons; + if(w.ptrfocus == Focustitle){ + tk->pointer(w.titlebar, p); + return 1; + } + return 0; +} + +# titlebar requested size might have changed: +# find out what size it's requesting. +sizetb(w: ref Window) +{ + if(w.titlebar == nil) + return; + w.tbsize = tk->rect(w.titlebar, ".", Tk->Border|Tk->Required).size(); +} + +# reshape the image; the space needed for the +# titlebar is added to r. +Window.reshape(w: self ref Window, r: Rect) +{ + w.r = w.screenr(r); + if(w.screen == nil) + return; + w.wmctl(sys->sprint("!reshape . -1 %s", r2s(w.r))); +} + +putimage(w: ref Window, i: ref Image) +{ + if(w.screen != nil && i == w.screen.image) + return; + w.screen = Screen.allocate(i, w.display.color(Draw->White), 0); + ir := i.r.inset(w.bd); + if(ir.dx() < 0) + ir.max.x = ir.min.x; + if(ir.dy() < 0) + ir.max.y = ir.min.y; + if(w.titlebar != nil){ + w.tbrect = Rect(ir.min, (ir.max.x, ir.min.y + w.tbsize.y)); + tbimage := w.screen.newwindow(w.tbrect, Draw->Refnone, Draw->Nofill); + tk->putimage(w.titlebar, ".", tbimage, nil); + ir.min.y = w.tbrect.max.y; + } + if(ir.dy() < 0) + ir.max.y = ir.min.y; + w.image = w.screen.newwindow(ir, Draw->Refnone, Draw->Nofill); + drawborder(w); + w.r = i.r; +} + +# return a rectangle suitable to hold image r when the +# titlebar and border are included. +Window.screenr(w: self ref Window, r: Rect): Rect +{ + if(w.titlebar != nil){ + if(r.dx() < w.tbsize.x) + r.max.x = r.min.x + w.tbsize.x; + r.min.y -= w.tbsize.y; + } + return r.inset(-w.bd); +} + +# return the available space inside r when space for +# border and titlebar is taken away. +Window.imager(w: self ref Window, r: Rect): Rect +{ + r = r.inset(w.bd); + if(r.dx() < 0) + r.max.x = r.min.x; + if(r.dy() < 0) + r.max.y = r.min.y; + if(w.titlebar != nil){ + r.min.y += w.tbsize.y; + if(r.dy() < 0) + r.max.y = r.min.y; + } + return r; +} + +# draw an imitation tk border. +drawborder(w: ref Window) +{ + if(w.screen == nil) + return; + col := w.display.color(Bdup); + i := w.screen.image; + r := w.screen.image.r; + i.draw((r.min, (r.min.x+w.bd, r.max.y)), col, nil, (0, 0)); + i.draw(((r.min.x+w.bd, r.min.y), (r.max.x, r.min.y+w.bd)), col, nil, (0, 0)); + col = w.display.color(Bddown); + i.draw(((r.max.x-w.bd, r.min.y+w.bd), r.max), col, nil, (0, 0)); + i.draw(((r.min.x+w.bd, r.max.y-w.bd), (r.max.x-w.bd, r.max.y)), col, nil, (0, 0)); +} + +readscreenrect(w: ref Window) +{ + if((fd := sys->open("/chan/wmrect", Sys->OREAD)) != nil){ + buf := array[12*4] of byte; + n := sys->read(fd, buf, len buf); + if(n > 0){ + (w.displayr, nil) = s2r(string buf[0:n], 0); + return; + } + } + w.displayr = w.display.image.r; +} + +Window.onscreen(w: self ref Window, how: string) +{ + if(how == nil) + how = "place"; + w.wmctl(sys->sprint("!reshape . -1 %s %q", r2s(w.r), how)); +} + +Window.startinput(w: self ref Window, devs: list of string) +{ + for(; devs != nil; devs = tl devs) + w.wmctl(sys->sprint("start %q", hd devs)); +} + +# commands originating both from tkclient and wm (via ctl) +Window.wmctl(w: self ref Window, req: string): string +{ + (c, next) := qword(req, 0); + case c { + "exit" => + sys->fprint(sys->open("/prog/" + string sys->pctl(0, nil) + "/ctl", Sys->OWRITE), "killgrp"); + exit; + # old-style requests: pass them back around in proper form. + "move" => + # move x y + if(w.titlebar != nil) + titlebar->sendctl(w.titlebar, "!move . -1 " + req[next:]); + "size" => + if(w.titlebar != nil){ + minsz := titlebar->minsize(w.titlebar); + titlebar->sendctl(w.titlebar, "!size . -1 " + string minsz.x + " " + string minsz.y); + } + "ok" or + "help" => + ; + "rect" => + (w.displayr, nil) = s2r(req, next); + "haskbdfocus" => + w.focused = int qword(req, next).t0; + if(w.titlebar != nil){ + tk->cmd(w.titlebar, "focus -global " + string w.focused); + tk->cmd(w.titlebar, "update"); + } + drawborder(w); + "task" => + title := ""; + if(w.titlebar != nil) + title = titlebar->title(w.titlebar); + wmreq(w, sys->sprint("task %q", title), next); + w.saved = w.r.min; + # send window out of the way + # XXX oops, can't do this for plain windows... + titlebar->sendctl(w.titlebar, "!reshape . -1 " + r2s((w.displayr.max, w.displayr.max.add(w.r.size())))); + "untask" => + wmreq(w, req, next); + # put window back where it was before. + # XXX what do we we do if the window manager window has been reshape in the meantime...? + titlebar->sendctl(w.titlebar, "!reshape . -1 " + r2s((w.saved, w.saved.add(w.r.size())))); + * => + return wmreq(w, req, next); + } + return nil; +} + +wmreq(w: ref Window, req: string, e: int): string +{ + name: string; + if(req != nil && req[0] == '!'){ + (name, e) = qword(req, e); + if(name != ".") + return "invalid window name"; + } + if(w.ctxt.connfd != nil){ + if(sys->fprint(w.ctxt.connfd, "%s", req) == -1) + return sys->sprint("%r"); + if(req[0] == '!') + recvimage(w); + return nil; + } + # if we're getting an image and there's no window manager, + # then there's only one image to get... + if(req[0] == '!') + putimage(w, w.ctxt.ctxt.display.image); + else{ + (nil, nil, err) := wmlib->wmctl(w.ctxt, req); + return err; + } + return nil; +} + +recvimage(w: ref Window) +{ + i := <-w.ctxt.images; + if(i == nil) + i = <-w.ctxt.images; + putimage(w, i); +} + +Window.settitle(w: self ref Window, title: string): string +{ + if(w.titlebar == nil) + return nil; + oldr := w.imager(w.r); + old := titlebar->settitle(w.titlebar, title); + sizetb(w); + if(w.tbsize.x < w.r.dx()) + tk->putimage(w.titlebar, ".", w.titlebar.image, nil); # unsuspend the window + else + w.wmctl("!reshape . -1 " + r2s(w.screenr(oldr))); + return old; +} + +snarfget(): string +{ + return wmlib->snarfget(); +} + +snarfput(buf: string) +{ + return wmlib->snarfput(buf); +} + +r2s(r: Rect): string +{ + return sys->sprint("%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y); +} |
