| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| |
| typedef struct Memimage Memimage; |
| |
| static int screenid; |
| |
| Screen* |
| allocscreen(Image *image, Image *fill, int public) |
| { |
| uchar *a; |
| Screen *s; |
| int id, try; |
| Display *d; |
| |
| d = image->display; |
| if(d != fill->display){ |
| werrstr("allocscreen: image and fill on different displays"); |
| return 0; |
| } |
| s = malloc(sizeof(Screen)); |
| if(s == 0) |
| return 0; |
| SET(id); |
| for(try=0; try<25; try++){ |
| /* loop until find a free id */ |
| a = bufimage(d, 1+4+4+4+1); |
| if(a == 0){ |
| free(s); |
| return 0; |
| } |
| id = ++screenid; |
| a[0] = 'A'; |
| BPLONG(a+1, id); |
| BPLONG(a+5, image->id); |
| BPLONG(a+9, fill->id); |
| a[13] = public; |
| if(flushimage(d, 0) != -1) |
| break; |
| } |
| s->display = d; |
| s->id = id; |
| s->image = image; |
| assert(s->image && s->image->chan != 0); |
| |
| s->fill = fill; |
| return s; |
| } |
| |
| Screen* |
| publicscreen(Display *d, int id, u32int chan) |
| { |
| uchar *a; |
| Screen *s; |
| |
| s = malloc(sizeof(Screen)); |
| if(s == 0) |
| return 0; |
| a = bufimage(d, 1+4+4); |
| if(a == 0){ |
| Error: |
| free(s); |
| return 0; |
| } |
| a[0] = 'S'; |
| BPLONG(a+1, id); |
| BPLONG(a+5, chan); |
| if(flushimage(d, 0) < 0) |
| goto Error; |
| |
| s->display = d; |
| s->id = id; |
| s->image = 0; |
| s->fill = 0; |
| return s; |
| } |
| |
| int |
| freescreen(Screen *s) |
| { |
| uchar *a; |
| Display *d; |
| |
| if(s == 0) |
| return 0; |
| d = s->display; |
| a = bufimage(d, 1+4); |
| if(a == 0) |
| return -1; |
| a[0] = 'F'; |
| BPLONG(a+1, s->id); |
| /* |
| * flush(1) because screen is likely holding last reference to |
| * window, and want it to disappear visually. |
| */ |
| if(flushimage(d, 1) < 0) |
| return -1; |
| free(s); |
| return 1; |
| } |
| |
| Image* |
| allocwindow(Screen *s, Rectangle r, int ref, u32int val) |
| { |
| return _allocwindow(nil, s, r, ref, val); |
| } |
| |
| Image* |
| _allocwindow(Image *i, Screen *s, Rectangle r, int ref, u32int val) |
| { |
| Display *d; |
| |
| d = s->display; |
| i = _allocimage(i, d, r, d->screenimage->chan, 0, val, s->id, ref); |
| if(i == 0) |
| return 0; |
| i->screen = s; |
| i->next = s->display->windows; |
| s->display->windows = i; |
| return i; |
| } |
| |
| static |
| void |
| topbottom(Image **w, int n, int top) |
| { |
| int i; |
| uchar *b; |
| Display *d; |
| |
| if(n < 0){ |
| Ridiculous: |
| fprint(2, "top/bottom: ridiculous number of windows\n"); |
| return; |
| } |
| if(n == 0) |
| return; |
| if(n > (w[0]->display->bufsize-100)/4) |
| goto Ridiculous; |
| /* |
| * this used to check that all images were on the same screen. |
| * we don't know the screen associated with images we acquired |
| * by name. instead, check that all images are on the same display. |
| * the display will check that they are all on the same screen. |
| */ |
| d = w[0]->display; |
| for(i=1; i<n; i++) |
| if(w[i]->display != d){ |
| fprint(2, "top/bottom: windows not on same screen\n"); |
| return; |
| } |
| |
| if(n==0) |
| return; |
| b = bufimage(d, 1+1+2+4*n); |
| b[0] = 't'; |
| b[1] = top; |
| BPSHORT(b+2, n); |
| for(i=0; i<n; i++) |
| BPLONG(b+4+4*i, w[i]->id); |
| } |
| |
| void |
| bottomwindow(Image *w) |
| { |
| if(w->screen == 0) |
| return; |
| topbottom(&w, 1, 0); |
| } |
| |
| void |
| topwindow(Image *w) |
| { |
| if(w->screen == 0) |
| return; |
| topbottom(&w, 1, 1); |
| } |
| |
| void |
| bottomnwindows(Image **w, int n) |
| { |
| topbottom(w, n, 0); |
| } |
| |
| void |
| topnwindows(Image **w, int n) |
| { |
| topbottom(w, n, 1); |
| } |
| |
| int |
| originwindow(Image *w, Point log, Point scr) |
| { |
| uchar *b; |
| Point delta; |
| |
| flushimage(w->display, 0); |
| b = bufimage(w->display, 1+4+2*4+2*4); |
| if(b == nil) |
| return 0; |
| b[0] = 'o'; |
| BPLONG(b+1, w->id); |
| BPLONG(b+5, log.x); |
| BPLONG(b+9, log.y); |
| BPLONG(b+13, scr.x); |
| BPLONG(b+17, scr.y); |
| if(flushimage(w->display, 1) < 0) |
| return -1; |
| delta = subpt(log, w->r.min); |
| w->r = rectaddpt(w->r, delta); |
| w->clipr = rectaddpt(w->clipr, delta); |
| return 1; |
| } |