Prevet a GPF when calling get_status on a failed connection.
[luaxcb.git] / lxcb.c
blob129f5ce1c763a22e1fe0d65e550bfb9441573625
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <lua5.1/lua.h>
4 #include <lua5.1/lauxlib.h>
6 #include <xcb/xcb.h>
8 #define MT_DISPLAY "XCB.display"
11 extern void push_ERROR(lua_State *L, xcb_generic_error_t *e);
13 typedef void (*eventFunc)(lua_State *L, xcb_generic_event_t *);
14 eventFunc push_event[256] = { NULL };
16 void RegisterEvent(int index, eventFunc func)
18 push_event[index] = func;
21 static void PushEvent(lua_State *L, xcb_generic_event_t *event)
23 lua_newtable(L);
24 lua_pushinteger(L, event->response_type);
25 lua_setfield(L, -2, "response_type");
26 lua_pushinteger(L, event->sequence);
27 lua_setfield(L, -2, "sequence");
28 lua_pushinteger(L, event->full_sequence);
29 lua_setfield(L, -2, "full_sequence");
31 if (push_event[event->response_type])
32 push_event[event->response_type](L, event);
35 static int Connect(lua_State *L)
37 xcb_connection_t *c;
38 int screen;
39 const char *name = NULL;
41 if (!lua_isnil(L, 1))
42 name = lua_tostring(L, 1);
43 c = xcb_connect(name, &screen);
44 if (!c)
45 return 0;
47 lua_newuserdata(L, sizeof(xcb_connection_t *));
48 ((xcb_connection_t **)lua_touserdata(L, -1))[0] = c;
49 luaL_getmetatable(L, MT_DISPLAY);
50 lua_setmetatable(L, -2);
52 lua_newtable(L);
53 lua_setfenv(L, -2);
55 lua_pushinteger(L, screen);
56 return 2;
59 static int gc_connection(lua_State *L)
61 xcb_connection_t *c;
62 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
64 lua_getfenv(L, 1);
65 lua_getfield(L, -1, "closed");
66 if (!lua_toboolean(L, -1))
67 xcb_disconnect(c);
69 return 0;
72 static int Disconnect(lua_State *L)
74 xcb_connection_t *c;
75 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
77 lua_getfenv(L, 1);
78 lua_getfield(L, -1, "closed");
79 if (lua_toboolean(L, -1))
80 luaL_error(L, "Error: already disconnected");
82 lua_pushboolean(L, 1);
83 lua_setfield(L, -3, "closed");
85 xcb_disconnect(c);
86 return 0;
89 static int Flush(lua_State *L)
91 xcb_connection_t *c;
92 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
94 lua_pushinteger(L, xcb_flush(c));
95 return 1;
98 static int GenerateID(lua_State *L)
100 lua_pushinteger(L, xcb_generate_id(((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0]));
102 return 1;
106 extern void push_Setup(lua_State *L, const xcb_setup_t *x); //Temporary until I get headers sorted out
108 static int GetSetup(lua_State *L)
110 xcb_connection_t *c;
111 const xcb_setup_t *setup;
113 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
115 lua_getfenv(L, 1);
116 lua_getfield(L, -1, "closed");
117 if (lua_toboolean(L, -1))
118 luaL_error(L, "Error: already disconnected");
120 setup = xcb_get_setup(c);
121 if (!setup)
122 luaL_error(L, "Error: connection failed");
124 push_Setup(L, setup);
125 return 1;
128 static int PollForEvent(lua_State *L)
130 xcb_connection_t *c;
131 xcb_generic_event_t *e;
133 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
135 lua_getfenv(L, 1);
136 lua_getfield(L, -1, "closed");
137 if (lua_toboolean(L, -1))
138 luaL_error(L, "Error: already disconnected");
140 e = xcb_poll_for_event(c);
141 if (!e)
142 lua_pushnil(L);
143 else if (!e->response_type)
144 push_ERROR(L, (xcb_generic_error_t *)e);
145 else
146 PushEvent(L, e);
148 if (e)
149 free(e);
151 return 1;
154 static int WaitForEvent(lua_State *L)
156 xcb_connection_t *c;
157 xcb_generic_event_t *e;
159 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
161 lua_getfenv(L, 1);
162 lua_getfield(L, -1, "closed");
163 if (lua_toboolean(L, -1))
164 luaL_error(L, "Error: already disconnected");
166 e = xcb_wait_for_event(c);
167 if (!e)
168 lua_pushnil(L);
169 else if (!e->response_type)
170 push_ERROR(L, (xcb_generic_error_t *)e);
171 else
172 PushEvent(L, e);
174 if (e)
175 free(e);
177 return 1;
180 static int HasError(lua_State *L)
182 xcb_connection_t *c;
183 c = ((xcb_connection_t **)luaL_checkudata(L, 1, MT_DISPLAY))[0];
185 lua_getfenv(L, 1);
186 lua_getfield(L, -1, "closed");
187 if (lua_toboolean(L, -1))
188 luaL_error(L, "Error: already disconnected");
190 lua_pushboolean(L, xcb_connection_has_error(c));
191 return 1;
196 static luaL_Reg lxcb[] = {
197 { "connect", Connect },
198 { NULL, NULL }
201 static luaL_Reg display_m[] = {
202 { "__gc", gc_connection },
203 { "disconnect", Disconnect },
204 { "flush", Flush },
205 { "generate_id", GenerateID },
206 { "get_setup", GetSetup },
207 { "poll_for_event", PollForEvent },
208 { "wait_for_event", WaitForEvent },
209 { "has_error", HasError },
210 /* TODO:
211 { "connect_to_display_with_auth_info", ConnectToDisplayWithAuthInfo },
212 { "connect_to_fd", ConnectToFD },
213 { "get_file_descriptor", GetFileDescriptor },
214 { "get_maximum_request_length", GetMaximumRequestLength },
215 { "parse_display", ParseDisplay },
216 { "prefetch_extension_data", PrefetchExtensionData },
217 { "prefetch_maximum_request_length", PrefetchMaximumRequestLength },
218 { "query_extension_reply", QueryExtensionReply },
219 { "request_check", RequestCheck },
221 { NULL, NULL }
224 #ifdef _MSC_VER
225 #define DLLEXPORT __declspec(dllexport)
226 #else
227 /* Must be gcc if not MSC */
228 #define DLLEXPORT __attribute__((visibility("default")))
229 #endif
231 extern void init_xproto(lua_State *L); // Temporary, until I get headers sorted.
233 DLLEXPORT int luaopen_lxcb(lua_State *L)
235 luaL_register(L, "lxcb", lxcb);
237 luaL_newmetatable(L, MT_DISPLAY);
238 lua_pushvalue(L, -1);
239 lua_setfield(L, -2, "__index");
240 luaL_register(L, NULL, display_m);
242 init_xproto(L);
243 lua_pop(L, 1);
245 return 1;