Skip to content
Snippets Groups Projects
Commit 238e6753 authored by Keiko Katsuragawa's avatar Keiko Katsuragawa
Browse files

add examples for 1-5-Events

parent 3402edee
No related branches found
No related tags found
No related merge requests found
/*
CS 349 Code Examples: X Windows and XLib
animation.cpp Ball bouncing in window (minimal version)
- - - - - - - - - - - - - - - - - - - - - -
See associated makefile for compiling instructions
*/
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
// get microseconds
unsigned long now() {
timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
using namespace std;
Display* display;
Window window;
// frames per second to run animation loop
int FPS = 60;
int main( int argc, char *argv[] ) {
display = XOpenDisplay("");
if (display == NULL) exit (-1);
int screennum = DefaultScreen(display);
long background = WhitePixel(display, screennum);
long foreground = BlackPixel(display, screennum);
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
10, 10, 300, 200, 2, foreground, background);
XSelectInput(display, window,
ButtonPressMask | KeyPressMask); // select events
XMapRaised(display, window);
XFlush(display);
XEvent event; // save the event here
// ball postition, size, and velocity
XPoint ballPos;
ballPos.x = 50;
ballPos.y = 50;
int ballSize = 50;
XPoint ballDir;
ballDir.x = 3;
ballDir.y = 3;
// create gc for drawing
GC gc = XCreateGC(display, window, 0, 0);
// time of last window paint
unsigned long lastRepaint = 0;
XWindowAttributes w;
XGetWindowAttributes(display, window, &w);
// event loop
while ( true ) {
// TRY THIS
// comment out this conditional to see what happens when
// events block (run the program and keep pressing the mouse)
if (XPending(display) > 0) {
XNextEvent( display, &event );
switch ( event.type ) {
// mouse button press
case ButtonPress:
cout << "CLICK" << endl;
break;
case KeyPress: // any keypress
KeySym key;
char text[10];
int i = XLookupString( (XKeyEvent*)&event, text, 10, &key, 0 );
if ( i == 1 && text[0] == 'q' ) {
XCloseDisplay(display);
exit(0);
}
break;
}
}
unsigned long end = now(); // get time in microsecond
if (end - lastRepaint > 1000000 / FPS) {
// clear background
XClearWindow(display, window);
// draw ball from centre
XFillArc(display, window, gc,
ballPos.x - ballSize/2,
ballPos.y - ballSize/2,
ballSize, ballSize,
0, 360*64);
// update ball position
ballPos.x += ballDir.x;
ballPos.y += ballDir.y;
// bounce ball
if (ballPos.x + ballSize/2 > w.width ||
ballPos.x - ballSize/2 < 0)
ballDir.x = -ballDir.x;
if (ballPos.y + ballSize/2 > w.height ||
ballPos.y - ballSize/2 < 0)
ballDir.y = -ballDir.y;
XFlush( display );
lastRepaint = now(); // remember when the paint happened
}
// IMPORTANT: sleep for a bit to let other processes work
if (XPending(display) == 0) {
usleep(1000000 / FPS - (end - lastRepaint));
}
}
XCloseDisplay(display);
}
/*
CS 349 Code Examples: X Windows and XLib
doublebuffer1.cpp How to do double buffering (minimal version using animation.cpp)
Note, it's pretty hard to see any difference.
- - - - - - - - - - - - - - - - - - - - - -
See associated makefile for compiling instructions
*/
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
// get microseconds
unsigned long now() {
timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
using namespace std;
Display* display;
Window window;
// frames per second to run animation loop
int FPS = 60;
int main( int argc, char *argv[] ) {
display = XOpenDisplay("");
if (display == NULL) exit (-1);
int screennum = DefaultScreen(display);
long background = WhitePixel(display, screennum);
long foreground = BlackPixel(display, screennum);
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
10, 10, 300, 200, 2, foreground, background);
XSelectInput(display, window,
ButtonPressMask | KeyPressMask); // select events
XMapRaised(display, window);
XFlush(display);
XEvent event; // save the event here
// ball postition, size, and velocity
XPoint ballPos;
ballPos.x = 50;
ballPos.y = 50;
int ballSize = 50;
XPoint ballDir;
ballDir.x = 3;
ballDir.y = 3;
// create gc for drawing
GC gc = XCreateGC(display, window, 0, 0);
// time of last window paint
unsigned long lastRepaint = 0;
XWindowAttributes w;
XGetWindowAttributes(display, window, &w);
// DOUBLE BUFFER
// create bimap (pximap) to us a other buffer
int depth = DefaultDepth(display, DefaultScreen(display));
Pixmap buffer = XCreatePixmap(display, window, w.width, w.height, depth);
bool useBuffer = true;
// event loop
while ( true ) {
// TRY THIS
// comment out this conditional to see what happens when
// events block (run the program and keep pressing the mouse)
if (XPending(display) > 0) {
XNextEvent( display, &event );
switch ( event.type ) {
// mouse button press
case ButtonPress:
useBuffer = !useBuffer;
cout << "double buffer " << useBuffer << endl;
break;
case KeyPress: // any keypress
KeySym key;
char text[10];
int i = XLookupString( (XKeyEvent*)&event, text, 10, &key, 0 );
if ( i == 1 && text[0] == 'q' ) {
XCloseDisplay(display);
exit(0);
}
break;
}
}
unsigned long end = now();
if (end - lastRepaint > 1000000 / FPS) {
Pixmap pixmap;
if (useBuffer) {
pixmap = buffer;
// draw into the buffer
// note that a window and a pixmap are “drawables”
XSetForeground(display, gc, WhitePixel(display, DefaultScreen(display)));
XFillRectangle(display, pixmap, gc,
0, 0, w.width, w.height);
} else {
pixmap = window;
// clear background
XClearWindow(display, pixmap);
}
// draw ball from centre
XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
XFillArc(display, pixmap, gc,
ballPos.x - ballSize / 2,
ballPos.y - ballSize / 2,
ballSize, ballSize,
0, 360 * 64);
// update ball position
ballPos.x += ballDir.x;
ballPos.y += ballDir.y;
// bounce ball
if (ballPos.x + ballSize / 2 > w.width ||
ballPos.x - ballSize / 2 < 0)
ballDir.x = -ballDir.x;
if (ballPos.y + ballSize / 2 > w.height ||
ballPos.y - ballSize / 2 < 0)
ballDir.y = -ballDir.y;
// copy buffer to window
if (useBuffer) {
XCopyArea(display, pixmap, window, gc,
0, 0, w.width, w.height, // region of pixmap to copy
0, 0); // position to put top left corner of pixmap in window
}
XFlush( display );
lastRepaint = now(); // remember when the paint happened
}
// IMPORTANT: sleep for a bit to let other processes work
if (XPending(display) == 0) {
usleep(1000000 / FPS - (end - lastRepaint));
}
}
XCloseDisplay(display);
}
/*
CS 349 Code Examples: X Windows and XLib
doublebuffer2.cpp Adds many balls to animation to make doublebuffering
effect more obvious.
- - - - - - - - - - - - - - - - - - - - - -
See associated makefile for compiling instructions
*/
#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <vector>
// get microseconds
unsigned long now() {
timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
}
using namespace std;
Display* display;
Window window;
// frames per second to run animation loop
int FPS = 60;
int main( int argc, char *argv[] ) {
display = XOpenDisplay("");
if (display == NULL) exit (-1);
int screennum = DefaultScreen(display);
long background = WhitePixel(display, screennum);
long foreground = BlackPixel(display, screennum);
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
10, 10, 300, 200, 2, foreground, background);
XSelectInput(display, window,
ButtonPressMask | KeyPressMask); // select events
XMapRaised(display, window);
XFlush(display);
XEvent event; // save the event here
// ball postition, size, and velocity
vector<XPoint> ballPos;
vector<XPoint> ballDir;
int numBalls = 1000;
for (int i = 0; i < numBalls; i++) {
XPoint bp;
bp.x = rand() % 300;
bp.y = rand() % 200;
XPoint bd;
bd.x = rand() % 3;
bd.y = rand() % 3;
ballPos.push_back(bp);
ballDir.push_back(bd);
}
// XPoint ballPos;
// ballPos.x = 50;
// ballPos.y = 50;
int ballSize = 10;
// XPoint ballDir;
// ballDir.x = 3;
// ballDir.y = 3;
// create gc for drawing
GC gc = XCreateGC(display, window, 0, 0);
// time of last window paint
unsigned long lastRepaint = 0;
XWindowAttributes w;
XGetWindowAttributes(display, window, &w);
// DOUBLE BUFFER
// create bimap (pximap) to us a other buffer
int depth = DefaultDepth(display, DefaultScreen(display));
Pixmap buffer = XCreatePixmap(display, window, w.width, w.height, depth);
bool useBuffer = true;
// event loop
while ( true ) {
// TRY THIS
// comment out this conditional to see what happens when
// events block (run the program and keep pressing the mouse)
if (XPending(display) > 0) {
XNextEvent( display, &event );
switch ( event.type ) {
// mouse button press
case ButtonPress:
useBuffer = !useBuffer;
cout << "double buffer " << useBuffer << endl;
break;
case KeyPress: // any keypress
KeySym key;
char text[10];
int i = XLookupString( (XKeyEvent*)&event, text, 10, &key, 0 );
if ( i == 1 && text[0] == 'q' ) {
XCloseDisplay(display);
exit(0);
}
break;
}
}
unsigned long end = now();
if (end - lastRepaint > 1000000 / FPS) {
Pixmap pixmap;
if (useBuffer) {
pixmap = buffer;
// draw into the buffer
// note that a window and a pixmap are “drawables”
XSetForeground(display, gc, WhitePixel(display, DefaultScreen(display)));
XFillRectangle(display, pixmap, gc,
0, 0, w.width, w.height);
} else {
pixmap = window;
// clear background
XClearWindow(display, pixmap);
}
for (int i = 0; i < numBalls; i++) {
// draw ball from centre
XSetForeground(display, gc, BlackPixel(display, DefaultScreen(display)));
XFillArc(display, pixmap, gc,
ballPos[i].x - ballSize / 2,
ballPos[i].y - ballSize / 2,
ballSize, ballSize,
0, 360 * 64);
// update ball position
ballPos[i].x += ballDir[i].x;
ballPos[i].y += ballDir[i].y;
// bounce ball
if (ballPos[i].x + ballSize / 2 > w.width ||
ballPos[i].x - ballSize / 2 < 0)
ballDir[i].x = -ballDir[i].x;
if (ballPos[i].y + ballSize / 2 > w.height ||
ballPos[i].y - ballSize / 2 < 0)
ballDir[i].y = -ballDir[i].y;
}
// copy buffer to window
if (useBuffer) {
XCopyArea(display, pixmap, window, gc,
0, 0, w.width, w.height, // region of pixmap to copy
0, 0); // position to put top left corner of pixmap in window
}
XFlush( display );
lastRepaint = now(); // remember when the paint happened
}
// IMPORTANT: sleep for a bit to let other processes work
if (XPending(display) == 0) {
usleep(1000000 / FPS - (end - lastRepaint));
}
}
XCloseDisplay(display);
}
/*
CS 349 Code Examples: X Windows and XLib
eventloop Displays text at cursor location on mouse button press
- - - - - - - - - - - - - - - - - - - - - -
See associated makefile for compiling instructions
*/
#include <iostream>
#include <list>
#include <cstdlib>
#include <vector>
//#include <string>
//#include <sstream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
const int Border = 5;
const int BufferSize = 10;
int count_click = 0;
struct XInfo {
Display* display;
Window window;
GC gc;
};
// An abstract class representing displayable things.
class Displayable {
public:
virtual void paint(XInfo& xinfo) = 0;
};
// A text displayable
class Text : public Displayable {
public:
virtual void paint(XInfo& xinfo) {
XDrawImageString( xinfo.display, xinfo.window, xinfo.gc,
this->x, this->y, this->s.c_str(), this->s.length() );
}
Text(int x, int y, string s): x(x), y(y), s(s) {}
private:
int x;
int y;
string s; // string to show
};
// A displayable polyline
class Polyline : public Displayable {
public:
virtual void paint(XInfo& xinfo) {
// note the trick to pass a stl vector as an C array
XDrawLines(xinfo.display, xinfo.window, xinfo.gc,
&points[0], points.size(), // vector of points
CoordModeOrigin ); // use absolute coordinates
}
Polyline(int x, int y) {
add_point(x, y);
}
// add another point to the line
void add_point(int x, int y) {
XPoint p;
p.x = x;
p.y = y;
points.push_back(p);
}
private:
// need to use a vector to dynamically add points
vector < XPoint > points; // XPoint is a built in struct
};
// Function to put out a message on error exits.
void error( string str ) {
cerr << str << endl;
exit(0);
}
// Function to repaint a display list
void repaint( list<Displayable*> dList, XInfo& xinfo) {
list<Displayable*>::const_iterator begin = dList.begin();
list<Displayable*>::const_iterator end = dList.end();
XClearWindow( xinfo.display, xinfo.window );
while ( begin != end ) {
Displayable* d = *begin;
d->paint(xinfo);
begin++;
}
XFlush( xinfo.display );
}
// The loop responding to events from the user.
void eventloop(XInfo& xinfo) {
XEvent event;
KeySym key;
char text[BufferSize];
list<Displayable*> dList;
Polyline* polyline = NULL;
while ( true ) {
XNextEvent( xinfo.display, &event );
switch ( event.type ) {
// add item where mouse clicked
case ButtonPress:
// output to console
cout << "ButtonPress at " << event.xbutton.time << endl;
// add a new text object to the display list
dList.push_back(new Text(
event.xbutton.x, event.xbutton.y, "CLICK"));
// start a new polyline to draw
polyline = new Polyline(event.xbutton.x, event.xbutton.y);
dList.push_back(polyline);
repaint( dList, xinfo );
break;
// add item where mouse moved
case MotionNotify:
// add the point to the drawing
if (polyline != NULL) {
polyline->add_point(event.xmotion.x,
event.xmotion.y);
}
repaint( dList, xinfo );
break;
/*
* Exit when 'q' is typed.
* Arguments for XLookupString :
* event - the keyboard event
* text - buffer into which text will be written
* BufferSize - size of text buffer
* key - workstation independent key symbol
* 0 - pointer to a composeStatus structure
*/
case KeyPress:
int i = XLookupString(
(XKeyEvent*)&event, text, BufferSize, &key, 0 );
cout << "KeySym " << key
<< " text='" << text << "'"
<< " at " << event.xkey.time
<< endl;
if ( i == 1 && text[0] == 'q' ) {
cout << "Terminated normally." << endl;
XCloseDisplay(xinfo.display);
return;
}
switch(key){
case XK_Up:
cout << "Up" << endl;
break;
case XK_Down:
cout << "Down" << endl;
break;
case XK_Left:
cout << "Left" << endl;
break;
case XK_Right:
cout << "Right" << endl;
break;
}
break;
}
}
}
// Create the window; initialize X.
void initX(int argc, char* argv[], XInfo& xinfo) {
xinfo.display = XOpenDisplay( "" );
if ( !xinfo.display ) {
error( "Can't open display." );
}
int screen = DefaultScreen( xinfo.display );
unsigned long background = WhitePixel( xinfo.display, screen );
unsigned long foreground = BlackPixel( xinfo.display, screen );
XSizeHints hints;
hints.x = 100;
hints.y = 100;
hints.width = 400;
hints.height = 300;
hints.flags = PPosition | PSize;
xinfo.window = XCreateSimpleWindow( xinfo.display, DefaultRootWindow( xinfo.display ),
hints.x, hints.y, hints.width, hints.height,
Border, foreground, background );
XSetStandardProperties( xinfo.display, xinfo.window, "eventloop", "eventloop", None,
argv, argc, &hints );
xinfo.gc = XCreateGC (xinfo.display, xinfo.window, 0, 0 );
XSetBackground( xinfo.display, xinfo.gc, background );
XSetForeground( xinfo.display, xinfo.gc, foreground );
// Tell the window manager what input events you want.
// ButtomMotionMask: The client application receives MotionNotify events only when at least one button is pressed.
XSelectInput( xinfo.display, xinfo.window,
ButtonPressMask | KeyPressMask | ButtonMotionMask );
XMapRaised( xinfo.display, xinfo.window );
}
int main ( int argc, char* argv[] ) {
XInfo xinfo;
initX(argc, argv, xinfo);
eventloop(xinfo);
}
/*
CS 349 Code Examples: X Windows and XLib
eventloop.min.cpp Demos events by displaying mouse motion events
to console (minimal version)
- - - - - - - - - - - - - - - - - - - - - -
See associated makefile for compiling instructions
*/
#include <cstdlib>
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
Display* display;
Window window;
int main( int argc, char *argv[] ) {
display = XOpenDisplay("");
if (display == NULL) exit (-1);
int screennum = DefaultScreen(display);
long background = WhitePixel(display, screennum);
long foreground = BlackPixel(display, screennum);
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
10, 10, 300, 200, 2, foreground, background);
XSelectInput(display, window,
PointerMotionMask | KeyPressMask); // select events
XMapRaised(display, window);
XFlush(display);
XEvent event; // save the event here
while ( true ) { // event loop until 'exit'
XNextEvent( display, &event ); // wait for next event
cout << event.type << " ";
switch ( event.type ) {
case MotionNotify: // mouse movement
cout << event.xmotion.x << ","
<< event.xmotion.y << endl;
break;
case KeyPress: // any keypress
exit(0);
break;
}
}
XCloseDisplay(display);
}
# super simple makefile
# call it using 'make NAME=name_of_code_file_without_extension'
# (assumes a .cpp extension)
NAME = "eventloop.min"
# Add $(MAC_OPT) to the compile line for macOS
# (should be ignored by Linux, set to nothing if causing problems)
MAC_OPT = -I/opt/X11/include
all:
@echo "Compiling..."
g++ -o $(NAME) $(NAME).cpp -L/opt/X11/lib -lX11 -lstdc++ $(MAC_OPT)
run: all
@echo "Running..."
./$(NAME)
clean:
-rm *o
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment