summaryrefslogtreecommitdiff
path: root/appl/lib/wmclient.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/wmclient.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/wmclient.b')
-rw-r--r--appl/lib/wmclient.b346
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);
+}