31 |
|
|
32 |
#include <sys/time.h> |
#include <sys/time.h> |
33 |
#include <time.h> |
#include <time.h> |
34 |
|
#include <unistd.h> |
35 |
|
#include <fcntl.h> |
36 |
|
|
37 |
#include <libos/Os.hxx> |
#include <libos/Os.hxx> |
38 |
|
|
157 |
|
|
158 |
typedef ::Window Win; // work around a syntax error. |
typedef ::Window Win; // work around a syntax error. |
159 |
|
|
160 |
|
/** Return the current time as milliseconds after some unit. |
161 |
|
*/ |
162 |
long curTime() { |
long curTime() { |
163 |
struct timeval t; |
struct timeval t; |
164 |
gettimeofday(&t, 0); |
gettimeofday(&t, 0); |
183 |
} |
} |
184 |
|
|
185 |
struct LXWindowSystem : public Os::WindowSystem { |
struct LXWindowSystem : public Os::WindowSystem { |
186 |
|
|
187 |
|
/** A pipe, used to interrupt waiting of eventloop. |
188 |
|
*/ |
189 |
|
int interruptPipe[2]; |
190 |
|
|
191 |
|
fd_set readFds; |
192 |
|
fd_set tmpReadFds; |
193 |
|
int fdsMax; |
194 |
|
|
195 |
Display *dpy; |
Display *dpy; |
196 |
XSetWindowAttributes swa; |
XSetWindowAttributes swa; |
197 |
int swaMask; |
int swaMask; |
222 |
Drawable pixmapDrawable; |
Drawable pixmapDrawable; |
223 |
|
|
224 |
LXWindowSystem() { |
LXWindowSystem() { |
225 |
|
if(pipe(interruptPipe) < 0) { |
226 |
|
perror("Making interrupt pipe"); |
227 |
|
exit(1); |
228 |
|
} |
229 |
|
fcntl(interruptPipe[0], F_SETFL, O_NONBLOCK); |
230 |
|
fcntl(interruptPipe[1], F_SETFL, O_NONBLOCK); |
231 |
|
|
232 |
if(!(dpy = XOpenDisplay( NULL ))) BARF("Can't start X"); |
if(!(dpy = XOpenDisplay( NULL ))) BARF("Can't start X"); |
233 |
|
|
234 |
|
FD_ZERO(&readFds); |
235 |
|
FD_SET(ConnectionNumber(dpy), &readFds); |
236 |
|
FD_SET(interruptPipe[0], &readFds); |
237 |
|
fdsMax = (ConnectionNumber(dpy) >? interruptPipe[0]) + 5; |
238 |
|
|
239 |
|
|
240 |
int nel; |
int nel; |
241 |
|
|
329 |
return f; |
return f; |
330 |
} |
} |
331 |
|
|
332 |
|
void interrupt(); |
333 |
void eventLoop(bool wait); |
void eventLoop(bool wait); |
334 |
|
|
335 |
/* |
/* |
339 |
*/ |
*/ |
340 |
|
|
341 |
private: |
private: |
|
bool tryRepaint(); |
|
342 |
|
|
343 |
}; |
}; |
344 |
|
|
436 |
virtual void setEventHandler(Eventhandler *h) { |
virtual void setEventHandler(Eventhandler *h) { |
437 |
eventhandler = h; |
eventhandler = h; |
438 |
DBG(dbg) << "Set window "<<xw<<" eventhandler to "<<((int)h)<<"\n"; |
DBG(dbg) << "Set window "<<xw<<" eventhandler to "<<((int)h)<<"\n"; |
|
repaint(); |
|
439 |
} |
} |
440 |
|
|
441 |
LXWindow(LXWindowSystem *ws, int x, int y, int w, int h) : ws(ws), |
LXWindow(LXWindowSystem *ws, int x, int y, int w, int h) : ws(ws), |
501 |
glXSwapBuffers(ws->dpy, xw); |
glXSwapBuffers(ws->dpy, xw); |
502 |
} |
} |
503 |
|
|
|
virtual void repaint() { |
|
|
needRepaint = true; |
|
|
} |
|
|
|
|
|
bool tryRepaint() { |
|
|
// cout << "TryRepaint\n"; |
|
|
if(needRepaint) { |
|
|
needRepaint = false; |
|
|
if(eventhandler) { |
|
|
eventhandler->repaint(); |
|
|
return true; |
|
|
} |
|
|
} |
|
|
return false; |
|
|
} |
|
504 |
|
|
505 |
virtual void move(int x, int y) { |
virtual void move(int x, int y) { |
506 |
XMoveWindow(ws->dpy, xw, x, y); |
XMoveWindow(ws->dpy, xw, x, y); |
602 |
} |
} |
603 |
case Expose: |
case Expose: |
604 |
DBG(dbg) << "Expose\n"; |
DBG(dbg) << "Expose\n"; |
605 |
repaint(); |
eventhandler->repaint(); |
606 |
break; |
break; |
607 |
case ConfigureNotify: |
case ConfigureNotify: |
608 |
DBG(dbg) << "Configurenotify\n"; |
DBG(dbg) << "Configurenotify\n"; |
609 |
repaint(); |
eventhandler->repaint(); |
610 |
break; |
break; |
611 |
case MapRequest: |
case MapRequest: |
612 |
DBG(dbg) << "MapRequest\n"; |
DBG(dbg) << "MapRequest\n"; |
613 |
repaint(); |
eventhandler->repaint(); |
614 |
break; |
break; |
615 |
case MapNotify: |
case MapNotify: |
616 |
DBG(dbg) << "MapNotify\n"; |
DBG(dbg) << "MapNotify\n"; |
617 |
repaint(); |
eventhandler->repaint(); |
618 |
break; |
break; |
619 |
default: |
default: |
620 |
DBG(dbg) << "Unknown event "<<e->type<<"\n"; |
DBG(dbg) << "Unknown event "<<e->type<<"\n"; |
645 |
return instance; |
return instance; |
646 |
} |
} |
647 |
|
|
648 |
|
char intr = 'S'; |
649 |
|
void LXWindowSystem::interrupt() { |
650 |
|
write(interruptPipe[1], &intr, 1); |
651 |
|
} |
652 |
|
|
653 |
|
|
654 |
void LXWindowSystem::eventLoop(bool wait) { |
void LXWindowSystem::eventLoop(bool wait) { |
655 |
DBG(dbg) << "In C++ eventloop : "<<wait<<"\n"; |
DBG(dbg) << "In C++ eventloop : "<<wait<<"\n"; |
656 |
// We don't want to block; |
// We don't want to block; |
657 |
while(1) { |
while(1) { |
658 |
DBG(dbg) << "Start loop\n"; |
DBG(dbg) << "Start loop\n"; |
|
XEvent e; |
|
|
if(tryRepaint()) { |
|
|
DBG(dbg) << "TryRepaint returned true, doing again... if no events (not now)\n"; |
|
|
/* |
|
|
if(!XEventsQueued(dpy, QueuedAfterFlush)) |
|
|
continue; |
|
|
*/ |
|
|
} |
|
|
/* |
|
|
for(int i=0; i<idletasks.size(); i++) { |
|
|
donthang = (donthang || idletasks[i]->tick()); |
|
|
} |
|
|
*/ |
|
|
DBG(dbg) << "Repaint done\n"; |
|
659 |
|
|
660 |
bool eventsWaiting = XEventsQueued(dpy, QueuedAfterFlush); |
bool eventsWaiting = XEventsQueued(dpy, QueuedAfterFlush); |
661 |
|
|
662 |
|
// If we should not wait and there are no events, return now |
663 |
if(!wait && !eventsWaiting) return; |
if(!wait && !eventsWaiting) return; |
664 |
|
// We only wait once: on the next iteration of the loop, |
665 |
|
// we'll return |
666 |
|
wait = false; |
667 |
|
|
668 |
DBG(dbg) << "Get next event\n"; |
DBG(dbg) << "Wait for next event, interrupt or timeout\n"; |
669 |
// If we're waiting for a timeout, handle things |
|
670 |
// differently. |
// If no events were waiting, now's the time to |
671 |
if(timeouts.size() && !eventsWaiting) { |
// wait for them. |
672 |
long t = curTime(); |
if(!eventsWaiting) { |
673 |
for(unsigned i=0; i<timeouts.size(); i++) { |
// Visit Java at least every .5 seconds |
674 |
if(timeouts[i].time < t) { |
timeval timeout; |
675 |
int id = timeouts[i].id; |
timeout.tv_sec = 0; |
676 |
LXWindow *w = windowsByX[timeouts[i].window]; |
timeout.tv_usec = 500 * 1000; |
677 |
timeouts.erase(timeouts.begin()+i); |
|
678 |
w->deliverTimeout(id); |
// If we're waiting for a timeout, sleep less. |
679 |
return; |
if(timeouts.size() && !eventsWaiting) { |
680 |
|
long t = curTime(); |
681 |
|
for(unsigned i=0; i<timeouts.size(); i++) { |
682 |
|
if(timeouts[i].time < t) { |
683 |
|
int id = timeouts[i].id; |
684 |
|
LXWindow *w = windowsByX[timeouts[i].window]; |
685 |
|
timeouts.erase(timeouts.begin()+i); |
686 |
|
w->deliverTimeout(id); |
687 |
|
return; |
688 |
|
} else { |
689 |
|
int ms = timeouts[i].time - t; |
690 |
|
if(ms < timeout.tv_usec / 1000) |
691 |
|
timeout.tv_sec = 1000 * ms; |
692 |
|
} |
693 |
} |
} |
694 |
} |
} |
695 |
timespec ts; |
// Call select to wait for something to happen. |
696 |
ts.tv_sec = 0; |
tmpReadFds = readFds; |
697 |
ts.tv_nsec = 50000000; // 50 ms - very bad |
select(fdsMax, &tmpReadFds, 0, 0, &timeout); |
698 |
nanosleep(&ts, &ts); |
char b[4]; |
699 |
continue; |
DBG(dbg) << "Emptying interrupt pipe\n"; |
700 |
|
while(read(interruptPipe[0], &b, 4) > 0) { |
701 |
|
DBG(dbg) << "Got "<<b[0]<<" "<<b[1]<<" "<<b[2]<< " "<<b[3]<<"\n"; |
702 |
|
} |
703 |
|
DBG(dbg) << "Empty\n"; |
704 |
} |
} |
705 |
wait = false; |
|
706 |
|
|
707 |
|
XEvent e; |
708 |
XNextEvent(dpy, &e); |
XNextEvent(dpy, &e); |
709 |
//cout << "getWindow\n"; |
//cout << "getWindow\n"; |
710 |
LXWindow *w = windowsByX[e.xkey.window]; |
LXWindow *w = windowsByX[e.xkey.window]; |
717 |
} |
} |
718 |
} |
} |
719 |
|
|
|
bool LXWindowSystem::tryRepaint() { |
|
|
for(unsigned i=0; i<windows.size(); i++) { |
|
|
if(windows[i]->tryRepaint()) return true; |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
720 |
/** Load an image into a raster using gdk-pixbuf. |
/** Load an image into a raster using gdk-pixbuf. |
721 |
*/ |
*/ |
722 |
ImageRaster loadImage(const char *filename) { |
ImageRaster loadImage(const char *filename) { |