]> git.tdb.fi Git - libs/gui.git/blob - source/window.cpp
Convert GLWindow to use GLX 1.3
[libs/gui.git] / source / window.cpp
1 /* $Id$
2
3 This file is part of libmspgbase
4 Copyright © 2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <vector>
9 #include <X11/Xutil.h>
10 #include <msp/core/error.h>
11 #include "window.h"
12
13 using namespace std;
14
15 namespace Msp {
16
17 DisplayOptions::DisplayOptions():
18         width(640),
19         height(480),
20         fullscreen(false)
21 { }
22
23
24 /**
25 Initializes the class but does not open the window.  Intended for use by
26 derived classes.
27 */
28 Window::Window():
29         display(0),
30         window(0)
31 { }
32
33 Window::Window(unsigned w, unsigned h)
34 {
35         options.width=w;
36         options.height=h;
37
38         init();
39 }
40
41 Window::Window(const DisplayOptions &dopt):
42         options(dopt)
43 {
44         init();
45 }
46
47 Window::~Window()
48 {
49         if(window)
50                 XDestroyWindow(display, window);
51         if(display)
52                 XCloseDisplay(display);
53 }
54
55 void Window::show()
56 {
57         XMapRaised(display, window);
58 }
59
60 void Window::hide()
61 {
62         XUnmapWindow(display, window);
63 }
64
65 void Window::tick()
66 {
67         while(1)
68         {
69                 int pending=XPending(display);
70                 if(pending==0)
71                         break;
72
73                 for(int i=0; i<pending; ++i)
74                 {
75                         XEvent event;
76                         XNextEvent(display, &event);
77                         process_event(event);
78                 }
79         }
80 }
81
82 void Window::prepare()
83 {
84         if(options.display.empty())
85                 display=XOpenDisplay(0);
86         else
87                 display=XOpenDisplay(options.display.c_str());
88         if(!display)
89                 throw Exception("Couldn't open X display");
90
91         wm_delete_window=XInternAtom(display, "WM_DELETE_WINDOW", true);
92
93         /* Throwing from the error handler doesn't work too well and I don't know
94            how to dig up all the information that Xlib gives by default, so disable
95                 custom error handling for now. */
96         //XSetErrorHandler(x_error_handler);
97 }
98
99 void Window::set_window(Handle wnd)
100 {
101         window=wnd;
102
103         XSelectInput(display, window, ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask);
104
105         XSetWMProtocols(display, window, &wm_delete_window, 1);
106 }
107
108 void Window::init()
109 {
110         prepare();
111
112         Handle wnd=XCreateWindow(display, DefaultRootWindow(display), 0, 0, options.width, options.height, 0, CopyFromParent, InputOutput, CopyFromParent, 0, 0);
113         set_window(wnd);
114 }
115
116 void Window::process_event(const XEvent &event)
117 {
118         switch(event.type)
119         {
120         case ButtonPress:
121                 signal_button_press.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
122                 break;
123         case ButtonRelease:
124                 signal_button_release.emit(event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state);
125                 break;
126         case MotionNotify:
127                 signal_pointer_motion.emit(event.xmotion.x, event.xmotion.y);
128                 break;
129         case KeyPress:
130                 {
131                         char buf[16];
132                         XLookupString(const_cast<XKeyEvent *>(&event.xkey), buf, sizeof(buf), 0, 0);
133                         // XXX Handle the result according to locale
134                         signal_key_press.emit(event.xkey.keycode, event.xkey.state, buf[0]);
135                 }
136                 break;
137         case KeyRelease:
138                 signal_key_release.emit(event.xkey.keycode, event.xkey.state);
139                 break;
140         case ConfigureNotify:
141                 options.width=event.xconfigure.width;
142                 options.height=event.xconfigure.height;
143                 signal_resize.emit(options.width, options.height);
144                 break;
145         case ClientMessage:
146                 if(event.xclient.data.l[0]==static_cast<long>(wm_delete_window))
147                         signal_close.emit();
148                 break;
149         default:;
150         }
151
152         on_event(event);
153 }
154
155 int Window::x_error_handler(Display *display, XErrorEvent *error)
156 {
157         char buf[128];
158         XGetErrorText(display, error->error_code, buf, sizeof(buf));
159         /*string request_code=lexical_cast(error->request_code);
160         char buf2[1024];
161         XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), buf, buf2, sizeof(buf2));*/
162         throw Exception(buf);
163 }
164
165 } // namespace Msp