]> git.tdb.fi Git - libs/gui.git/blob - source/gbase/display.cpp
Reorganize files to separate gbase and input
[libs/gui.git] / source / gbase / display.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 <iostream>
9 #ifndef WIN32
10 #include <X11/Xlib.h>
11 #include <X11/extensions/xf86vmode.h>
12 #endif
13 #include <msp/core/except.h>
14 #include <msp/strings/formatter.h>
15 #include <msp/strings/lexicalcast.h>
16 #include "display.h"
17 #include "window.h"
18
19 using namespace std;
20
21 namespace {
22
23 bool error_flag=false;
24 std::string error_msg;
25
26 #ifndef WIN32
27 int x_error_handler(Display *display, XErrorEvent *event)
28 {
29         char err[128];
30         XGetErrorText(display, event->error_code, err, sizeof(err));
31
32         string request_code=Msp::lexical_cast(static_cast<int>(event->request_code));
33         char req[128];
34         XGetErrorDatabaseText(display, "XRequest", request_code.c_str(), request_code.c_str(), req, sizeof(req));
35
36         string msg=Msp::format("Request %s failed with %s [%08X]", req, err, event->resourceid);
37         if(error_flag)
38                 cerr<<"Discarding error: "<<msg<<'\n';
39         else
40         {
41                 cerr<<msg<<'\n';
42                 error_msg=msg;
43                 error_flag=true;
44         }
45
46         return 0;
47 }
48 #endif
49
50 }
51
52 namespace Msp {
53 namespace Graphics {
54
55 Display::Display(const string &disp_name)
56 {
57 #ifndef WIN32
58         if(disp_name.empty())
59                 display=XOpenDisplay(0);
60         else
61                 display=XOpenDisplay(disp_name.c_str());
62         if(!display)
63                 throw Exception("Couldn't open X display");
64
65         XSetErrorHandler(x_error_handler);
66
67         int screen=DefaultScreen(display);
68
69         int nmodes;
70         XF86VidModeModeInfo **infos;
71         XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
72         for(int i=0; i<nmodes; ++i)
73         {
74                 XF86VidModeModeInfo &info=*infos[i];
75         
76                 VideoMode mode(info.hdisplay, info.vdisplay);
77                 mode.rate=info.dotclock/(info.htotal*info.vtotal);
78                 modes.push_back(mode);
79         }
80
81         XFree(infos);
82
83         XF86VidModeModeLine modeline;
84         int dotclock;
85         XF86VidModeGetModeLine(display, screen, &dotclock, &modeline);
86         orig_mode=VideoMode(modeline.hdisplay, modeline.vdisplay);
87         orig_mode.rate=dotclock/(modeline.htotal*modeline.vtotal);
88 #else
89         (void)disp_name;
90 #endif
91 }
92
93 Display::~Display()
94 {
95 #ifndef WIN32
96         XCloseDisplay(display);
97         display=0;
98 #endif
99 }
100
101 void Display::add_window(Window *wnd)
102 {
103         windows[wnd->get_handle()]=wnd;
104 }
105
106 void Display::remove_window(Window *wnd)
107 {
108         windows.erase(wnd->get_handle());
109 }
110
111 void Display::set_mode(const VideoMode &mode)
112 {
113 #ifndef WIN32
114         int screen=DefaultScreen(display);
115
116         int nmodes;
117         XF86VidModeModeInfo **infos;
118         XF86VidModeGetAllModeLines(display, screen, &nmodes, &infos);
119         for(int i=0; i<nmodes; ++i)
120         {
121                 XF86VidModeModeInfo &info=*infos[i];
122
123                 unsigned rate=info.dotclock/(info.htotal*info.vtotal);
124                 if(info.hdisplay==mode.width && info.vdisplay==mode.height && (mode.rate==0 || rate==mode.rate))
125                 {
126                         XF86VidModeSwitchToMode(display, screen, &info);
127                         XF86VidModeSetViewPort(display, screen, 0, 0);
128                         return;
129                 }
130         }
131
132         throw InvalidParameterValue("Requested mode not supported");
133 #else
134         (void)mode;
135 #endif
136 }
137
138 void Display::tick()
139 {
140         check_error();
141
142         while(1)
143         {
144 #ifdef WIN32
145                 MSG msg;
146                 if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
147                         DispatchMessage(&msg);
148                 else
149                         break;
150 #else
151                 int pending=XPending(display);
152                 if(pending==0)
153                         break;
154
155                 for(int i=0; i<pending; ++i)
156                 {
157                         XEvent event;
158                         XNextEvent(display, &event);
159
160                         check_error();
161
162                         map<WindowHandle, Window *>::iterator j=windows.find(event.xany.window);
163                         if(j!=windows.end())
164                                 j->second->event(event);
165                 }
166 #endif
167         }
168 }
169
170 void Display::check_error()
171 {
172         if(error_flag)
173         {
174                 error_flag=false;
175                 throw Exception(error_msg);
176         }
177 }
178
179 } // namespace Graphics
180 } // namespace Msp