]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/x11/display.cpp
Use mspio rather than iostreams for printing errors
[libs/gui.git] / source / graphics / x11 / display.cpp
1 #include <iostream>
2 #include <X11/Xlib.h>
3 #ifdef WITH_XF86VIDMODE
4 #include <X11/extensions/xf86vmode.h>
5 #endif
6 #include <msp/io/print.h>
7 #include <msp/strings/format.h>
8 #include <msp/strings/lexicalcast.h>
9 #include "display.h"
10 #include "display_private.h"
11
12 using namespace std;
13
14 namespace {
15
16 bool error_flag = false;
17 std::string error_msg;
18
19 int x_error_handler(Display *display, XErrorEvent *event)
20 {
21         char err[128];
22         XGetErrorText(display, event->error_code, err, sizeof(err));
23
24         string request_code = Msp::lexical_cast<string, int>(event->request_code);
25         char req[128];
26         XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
27
28         string msg = Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
29         if(error_flag)
30                 Msp::IO::print(Msp::IO::cerr, "Discarding error: %s\n", msg);
31         else
32         {
33                 Msp::IO::print(Msp::IO::cerr, "%s\n", msg);
34                 error_msg = msg;
35                 error_flag = true;
36         }
37
38         return 0;
39 }
40
41 }
42
43
44 namespace Msp {
45 namespace Graphics {
46
47 Display::Display(const string &disp_name):
48         priv(new Private)
49 {
50         if(disp_name.empty())
51                 priv->display = XOpenDisplay(0);
52         else
53                 priv->display = XOpenDisplay(disp_name.c_str());
54         if(!priv->display)
55                 throw runtime_error("XOpenDisplay");
56
57         XSetErrorHandler(x_error_handler);
58
59 #ifdef WITH_XF86VIDMODE
60         int screen = DefaultScreen(priv->display);
61
62         int nmodes;
63         XF86VidModeModeInfo **infos;
64         XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
65         for(int i=0; i<nmodes; ++i)
66         {
67                 XF86VidModeModeInfo &info = *infos[i];
68         
69                 VideoMode mode(info.hdisplay, info.vdisplay);
70                 if(info.htotal && info.vtotal)
71                         mode.rate = info.dotclock/(info.htotal*info.vtotal);
72                 modes.push_back(mode);
73         }
74
75         XFree(infos);
76
77         XF86VidModeModeLine modeline;
78         int dotclock;
79         XF86VidModeGetModeLine(priv->display, screen, &dotclock, &modeline);
80         orig_mode = VideoMode(modeline.hdisplay, modeline.vdisplay);
81         if(modeline.htotal && modeline.vtotal)
82                 orig_mode.rate = dotclock/(modeline.htotal*modeline.vtotal);
83 #endif
84 }
85
86 Display::~Display()
87 {
88         XCloseDisplay(priv->display);
89         delete priv;
90 }
91
92 void Display::set_mode(const VideoMode &mode)
93 {
94 #ifdef WITH_XF86VIDMODE
95         int screen = DefaultScreen(priv->display);
96
97         int nmodes;
98         XF86VidModeModeInfo **infos;
99         XF86VidModeGetAllModeLines(priv->display, screen, &nmodes, &infos);
100         for(int i=0; i<nmodes; ++i)
101         {
102                 XF86VidModeModeInfo &info = *infos[i];
103
104                 unsigned rate = 0;
105                 if(info.htotal && info.vtotal)
106                         rate = info.dotclock/(info.htotal*info.vtotal);
107                 if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
108                 {
109                         XF86VidModeSwitchToMode(priv->display, screen, &info);
110                         XF86VidModeSetViewPort(priv->display, screen, 0, 0);
111                         return;
112                 }
113         }
114
115         throw unsupported_video_mode(mode);
116 #else
117         (void)mode;
118         throw runtime_error("no xf86vidmode support");
119 #endif
120 }
121
122 bool Display::process_events()
123 {
124         int pending = XPending(priv->display);
125         if(pending==0)
126                 return false;
127
128         for(; pending--;)
129         {
130                 Window::Event event;
131                 XNextEvent(priv->display, &event.xevent);
132
133                 check_error();
134
135                 map<WindowHandle, Window *>::iterator j = priv->windows.find(event.xevent.xany.window);
136                 if(j!=priv->windows.end())
137                 {
138                         /* Filter keyboard autorepeat.  If this packet is a KeyRelease and
139                         the next one is a KeyPress with the exact same parameters, they
140                         indicate autorepeat and must be dropped. */
141                         if(event.xevent.type==KeyRelease && !j->second->get_keyboard_autorepeat() && pending>0)
142                         {
143                                 XKeyEvent &kev = event.xevent.xkey;
144                                 XEvent ev2;
145                                 XPeekEvent(priv->display, &ev2);
146                                 if(ev2.type==KeyPress)
147                                 {
148                                         XKeyEvent &kev2 = ev2.xkey;
149                                         if(kev2.window==kev.window && kev2.time==kev.time && kev2.keycode==kev.keycode)
150                                         {
151                                                 XNextEvent(priv->display, &ev2);
152                                                 --pending;
153                                                 continue;
154                                         }
155                                 }
156                         }
157
158                         j->second->event(event);
159                 }
160         }
161
162         return true;
163 }
164
165 void Display::check_error()
166 {
167         if(error_flag)
168         {
169                 error_flag = false;
170                 throw runtime_error(error_msg);
171         }
172 }
173
174 } // namespace Msp
175 } // namespace Graphics