rendered paste bodymodule gui.gui;
import bcd.xcb.xcb;
import lodepng.png;
import std.stdio;
import std.file;
import std.string;
GUI gui;
class GUI{
xcb_connection_t* conn;
xcb_screen_t* screen;
Window[xcb_window_t] windows;
Button[xcb_window_t] buttons;
xcb_generic_event_t* event;
this(){
int screen_num;
conn = xcb_connect(null, &screen_num);
/* Get the preferred screen. */
xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(xcb_get_setup(conn));
while(screen_num--)
xcb_screen_next(&screen_iter);
screen = screen_iter.data;
}
Window addWindow(geometry geom){
Window w = new Window(screen.root, 0, 0, geom); //Position handled by the window manager
xcb_change_window_attributes(gui.conn, w.id, XCB_CW_EVENT_MASK, cast(uint*)[XCB_EVENT_MASK_RESIZE_REDIRECT]);
windows[w.id] = w;
return w;
}
void loop(){
loop:
xcb_flush(gui.conn);
event = xcb_wait_for_event(conn);
switch(event.response_type){
case XCB_BUTTON_PRESS:
xcb_button_press_event_t* e = cast(xcb_button_press_event_t* )event;
if(e.event in buttons)
buttons[e.event].onPress();
break;
case XCB_BUTTON_RELEASE:
xcb_button_release_event_t* e = cast(xcb_button_release_event_t* )event;
if(e.event in buttons)
buttons[e.event].onRelease();
break;
case XCB_RESIZE_REQUEST://FIX
writefln("2"); //windows[id].recalculate();
break;
default:
break;
}
goto loop;
}
}
struct geometry{
uint width;
uint height;
}
geometry Geometry(uint width, uint height){
geometry geom;
geom.width = width;
geom.height = height;
return geom;
}
class Window{
xcb_window_t id;
Window[] subwindows;
this(xcb_window_t parent, int x, int y, geometry geom){
id = xcb_generate_id(gui.conn);
xcb_create_window(gui.conn, /* connection */
0, /* depth */
id, /* window id */
parent, /* parent window */
x, y, /* x, y */
geom.width, geom.height, /* width, height */
0, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
gui.screen.root_visual, /* visual */
0, /* masks */
null);
}
void map(){
xcb_map_window(gui.conn, id);
}
void unmap(){
xcb_unmap_window(gui.conn, id);
}
void resize(geometry geom){
xcb_configure_window(gui.conn, id, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
cast(uint*)[geom.width, geom.height]);
}
void moveResize(int x, int y, geometry geom){
xcb_configure_window(gui.conn, id, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, cast(uint*)[x, y, geom.width, geom.height]);
}
geometry getGeometry(){
xcb_get_geometry_reply_t* attr = xcb_get_geometry_reply(gui.conn, xcb_get_geometry(gui.conn, id), null);
return Geometry(attr.width,attr.height);
}
void setBackground(char[] filename){
ubyte[] data;
Info info = lodepng.png.decode32(data, cast(ubyte[])read(filename));
//if (info.error != 0)
//throw new Exception("Error loading png " ~ filename ~ ", errorcode: " ~ toString(info.error));
if(data.length % 4 != 0)
throw new Exception("Failcopter");
for(uint i; i<data.length; i+=4){
ubyte temp = data[i+2];
data[i+2] = data[i];
data[i] = temp;
}
xcb_gcontext_t gc = xcb_generate_id(gui.conn);
xcb_create_gc(gui.conn, gc, gui.screen.root, 0, null);
xcb_pixmap_t pixmap = xcb_generate_id(gui.conn);
/* Fill in the pixmap */
xcb_create_pixmap (gui.conn, /* Pointer to the xcb_connection_t structure */
24, /* Depth of the screen */
pixmap, /* Id of the pixmap */
gui.screen.root,
info.w, info.h); /* Height of the window (in pixels) */
xcb_put_image(gui.conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
pixmap, gc,
info.w, info.h, /* width, height */
0, 0, /* dst_x, dst_y */
0, 24, /* left_pad, depth */
data.length, data.ptr);
xcb_configure_window(gui.conn, id, XCB_CW_BACK_PIXMAP, cast(uint*)[pixmap]);
}
void recalculate(){
foreach(w; subwindows)
w.recalculate();
}
Container addContainer(int x, int y, geometry geom){
Container c = new Container(this, x, y, geom);
subwindows ~= c;
return c;
}
Container addContainer(float x1, float y1, float x2, float y2){
Container c = new Container(this, x1, y1, x2, y2);
subwindows ~= c;
return c;
}
Button addButton(int x, int y, geometry geom){
Button b = new Button(this, x, y, geom);
subwindows ~= b;
return b;
}
Button addButton(float x1, float y1, float x2, float y2){
Button b = new Button(this, x1, y1, x2, y2);
subwindows ~= b;
return b;
}
}
class Container : Window{
bool relative = false;
Window parent;
float w1,w2,h1,h2;
this(Window p, int x, int y, geometry geom){
parent = p;
super(parent.id, x, y, geom);
map();
}
this(Window p, float x1, float y1, float x2, float y2){
relative = true;
w1 = x1;
w2 = x2;
h1 = y1;
h2 = y2;
this(p, 0, 0, Geometry(0,0));
recalculate();
}
void recalculate(){
if(relative){
geometry geom = parent.getGeometry();
int x, y;
x = cast(int)(cast(float)geom.width * w1);
y = cast(int)(cast(float)geom.height * h1);
geom.width = cast(uint)(cast(float)w2*geom.width) - x;
geom.height = cast(uint)(cast(float)h2*geom.height) - y;
//std.math.rndtol
writefln(x);
writefln(y);
writefln(geom.width);
writefln(geom.height);
moveResize(x, y, geom);
}
super.recalculate();
}
}
class Button : Container{
void delegate() onPress;
void delegate() onRelease;
this(Window p, int x, int y, geometry geom){
super(p, x, y, geom);
xcb_change_window_attributes(gui.conn, id, XCB_CW_EVENT_MASK, cast(uint*)[XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS]);
gui.buttons[id] = this;
}
this(Window p, float x1, float y1, float x2, float y2){
super(p, x1, y1, x2, y2);
xcb_change_window_attributes(gui.conn, id, XCB_CW_EVENT_MASK, cast(uint*)[XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS]);
gui.buttons[id] = this;
}
}
void main(){
gui = new GUI();
Window w = gui.addWindow(Geometry(150,150));
//Button b = w.addButton(0, 0, Geometry(150,150));
Button b = w.addButton(.1f,.1f,.9f,.9f);
//b.setBackground("/home/joe/plasma.png"); //FIX
b.onRelease = &w.unmap;
b.onPress = {writefln("pressed");};
w.map();
gui.loop();
}