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