gosu 0.7.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. data/COPYING.txt +29 -0
  2. data/Gosu/Async.hpp +48 -0
  3. data/Gosu/Audio.hpp +145 -0
  4. data/Gosu/AutoLink.hpp +16 -0
  5. data/Gosu/Bitmap.hpp +85 -0
  6. data/Gosu/ButtonsMac.hpp +114 -0
  7. data/Gosu/ButtonsWin.hpp +111 -0
  8. data/Gosu/ButtonsX.hpp +115 -0
  9. data/Gosu/Color.hpp +172 -0
  10. data/Gosu/Directories.hpp +36 -0
  11. data/Gosu/Font.hpp +59 -0
  12. data/Gosu/Fwd.hpp +31 -0
  13. data/Gosu/Gosu.hpp +26 -0
  14. data/Gosu/Graphics.hpp +86 -0
  15. data/Gosu/GraphicsBase.hpp +45 -0
  16. data/Gosu/IO.hpp +255 -0
  17. data/Gosu/Image.hpp +148 -0
  18. data/Gosu/ImageData.hpp +45 -0
  19. data/Gosu/Input.hpp +116 -0
  20. data/Gosu/Math.hpp +95 -0
  21. data/Gosu/Platform.hpp +61 -0
  22. data/Gosu/RotFlip.hpp +116 -0
  23. data/Gosu/Sockets.hpp +129 -0
  24. data/Gosu/Text.hpp +47 -0
  25. data/Gosu/TextInput.hpp +57 -0
  26. data/Gosu/Timing.hpp +16 -0
  27. data/Gosu/Utility.hpp +24 -0
  28. data/Gosu/WinUtility.hpp +76 -0
  29. data/Gosu/Window.hpp +84 -0
  30. data/GosuImpl/Async.cpp +37 -0
  31. data/GosuImpl/AudioFmod.cpp +417 -0
  32. data/GosuImpl/AudioSDL.cpp +255 -0
  33. data/GosuImpl/DirectoriesMac.mm +38 -0
  34. data/GosuImpl/DirectoriesUnix.cpp +48 -0
  35. data/GosuImpl/DirectoriesWin.cpp +42 -0
  36. data/GosuImpl/FileUnix.cpp +100 -0
  37. data/GosuImpl/FileWin.cpp +83 -0
  38. data/GosuImpl/Graphics/Bitmap.cpp +116 -0
  39. data/GosuImpl/Graphics/BitmapBMP.cpp +232 -0
  40. data/GosuImpl/Graphics/BitmapColorKey.cpp +39 -0
  41. data/GosuImpl/Graphics/BitmapPNG.cpp +276 -0
  42. data/GosuImpl/Graphics/BitmapUtils.cpp +67 -0
  43. data/GosuImpl/Graphics/BlockAllocator.cpp +127 -0
  44. data/GosuImpl/Graphics/BlockAllocator.hpp +34 -0
  45. data/GosuImpl/Graphics/Color.cpp +126 -0
  46. data/GosuImpl/Graphics/Common.hpp +21 -0
  47. data/GosuImpl/Graphics/DrawOp.hpp +154 -0
  48. data/GosuImpl/Graphics/Font.cpp +110 -0
  49. data/GosuImpl/Graphics/Graphics.cpp +295 -0
  50. data/GosuImpl/Graphics/Image.cpp +159 -0
  51. data/GosuImpl/Graphics/LargeImageData.cpp +115 -0
  52. data/GosuImpl/Graphics/LargeImageData.hpp +37 -0
  53. data/GosuImpl/Graphics/RotFlip.cpp +184 -0
  54. data/GosuImpl/Graphics/TexChunk.cpp +77 -0
  55. data/GosuImpl/Graphics/TexChunk.hpp +40 -0
  56. data/GosuImpl/Graphics/Text.cpp +223 -0
  57. data/GosuImpl/Graphics/TextMac.cpp +242 -0
  58. data/GosuImpl/Graphics/TextPangoFT.cpp +186 -0
  59. data/GosuImpl/Graphics/TextWin.cpp +172 -0
  60. data/GosuImpl/Graphics/Texture.cpp +104 -0
  61. data/GosuImpl/Graphics/Texture.hpp +34 -0
  62. data/GosuImpl/IO.cpp +48 -0
  63. data/GosuImpl/InputMac.mm +677 -0
  64. data/GosuImpl/InputWin.cpp +444 -0
  65. data/GosuImpl/InputX.cpp +158 -0
  66. data/GosuImpl/MacUtility.hpp +48 -0
  67. data/GosuImpl/Math.cpp +49 -0
  68. data/GosuImpl/RubyGosu.swg +474 -0
  69. data/GosuImpl/RubyGosuStub.mm +17 -0
  70. data/GosuImpl/RubyGosu_DllMain.cxx +30 -0
  71. data/GosuImpl/RubyGosu_wrap.cxx +8521 -0
  72. data/GosuImpl/RubyGosu_wrap.h +31 -0
  73. data/GosuImpl/Sockets/CommSocket.cpp +304 -0
  74. data/GosuImpl/Sockets/ListenerSocket.cpp +60 -0
  75. data/GosuImpl/Sockets/MessageSocket.cpp +136 -0
  76. data/GosuImpl/Sockets/Socket.cpp +145 -0
  77. data/GosuImpl/Sockets/Sockets.hpp +66 -0
  78. data/GosuImpl/TextInputMac.mm +207 -0
  79. data/GosuImpl/TextInputWin.cpp +197 -0
  80. data/GosuImpl/TextInputX.cpp +201 -0
  81. data/GosuImpl/TextTTFWin.cpp +247 -0
  82. data/GosuImpl/TimingUnix.cpp +17 -0
  83. data/GosuImpl/TimingWin.cpp +28 -0
  84. data/GosuImpl/Utility.cpp +140 -0
  85. data/GosuImpl/WinMain.cpp +69 -0
  86. data/GosuImpl/WinUtility.cpp +137 -0
  87. data/GosuImpl/WindowMac.mm +466 -0
  88. data/GosuImpl/WindowWin.cpp +447 -0
  89. data/GosuImpl/WindowX.cpp +392 -0
  90. data/GosuImpl/X11vroot.h +118 -0
  91. data/README.txt +13 -0
  92. data/Rakefile +178 -0
  93. data/examples/ChipmunkIntegration.rb +275 -0
  94. data/examples/CptnRuby.rb +231 -0
  95. data/examples/MoreChipmunkAndRMagick.rb +155 -0
  96. data/examples/OpenGLIntegration.rb +232 -0
  97. data/examples/RMagickIntegration.rb +449 -0
  98. data/examples/TextInput.cpp +170 -0
  99. data/examples/TextInput.rb +139 -0
  100. data/examples/Tutorial.cpp +215 -0
  101. data/examples/Tutorial.rb +137 -0
  102. data/examples/media/Beep.wav +0 -0
  103. data/examples/media/CptnRuby Gem.png +0 -0
  104. data/examples/media/CptnRuby Map.txt +25 -0
  105. data/examples/media/CptnRuby Tileset.png +0 -0
  106. data/examples/media/CptnRuby.png +0 -0
  107. data/examples/media/Cursor.png +0 -0
  108. data/examples/media/Earth.png +0 -0
  109. data/examples/media/Explosion.wav +0 -0
  110. data/examples/media/LargeStar.png +0 -0
  111. data/examples/media/Sky.jpg +0 -0
  112. data/examples/media/Smoke.png +0 -0
  113. data/examples/media/Soldier.png +0 -0
  114. data/examples/media/Space.png +0 -0
  115. data/examples/media/Star.png +0 -0
  116. data/examples/media/Starfighter.bmp +0 -0
  117. data/linux/Makefile.in +98 -0
  118. data/linux/configure +5658 -0
  119. data/linux/configure.ac +126 -0
  120. data/linux/extconf.rb +11 -0
  121. data/mac/English.lproj/InfoPlist.strings +0 -0
  122. data/mac/Gosu-Info.plist +26 -0
  123. data/mac/Gosu.xcodeproj/project.pbxproj +1194 -0
  124. data/mac/RubyGosu Template-Info.plist +26 -0
  125. data/mac/libboost_thread_1_34_1_universal.a +0 -0
  126. data/mac/libboost_thread_d_1_34_1_universal.a +0 -0
  127. data/mac/libfmod_universal.a +0 -0
  128. data/mac/libpng_universal.a +0 -0
  129. data/mac/libz_universal.a +0 -0
  130. data/reference/Async_8hpp-source.html +70 -0
  131. data/reference/Audio_8hpp-source.html +114 -0
  132. data/reference/Audio_8hpp.html +50 -0
  133. data/reference/AutoLink_8hpp-source.html +38 -0
  134. data/reference/AutoLink_8hpp.html +34 -0
  135. data/reference/Bitmap_8hpp-source.html +85 -0
  136. data/reference/Bitmap_8hpp.html +58 -0
  137. data/reference/ButtonsMac_8hpp-source.html +133 -0
  138. data/reference/ButtonsWin_8hpp-source.html +133 -0
  139. data/reference/ButtonsX_8hpp-source.html +134 -0
  140. data/reference/Color_8hpp-source.html +169 -0
  141. data/reference/Color_8hpp.html +85 -0
  142. data/reference/Directories_8hpp-source.html +42 -0
  143. data/reference/Directories_8hpp.html +46 -0
  144. data/reference/Font_8hpp-source.html +65 -0
  145. data/reference/Font_8hpp.html +41 -0
  146. data/reference/Fwd_8hpp-source.html +52 -0
  147. data/reference/Fwd_8hpp.html +37 -0
  148. data/reference/Gosu_8hpp-source.html +48 -0
  149. data/reference/Gosu_8hpp.html +34 -0
  150. data/reference/GraphicsBase_8hpp-source.html +57 -0
  151. data/reference/GraphicsBase_8hpp.html +56 -0
  152. data/reference/Graphics_8hpp-source.html +96 -0
  153. data/reference/Graphics_8hpp.html +53 -0
  154. data/reference/IO_8hpp-source.html +255 -0
  155. data/reference/IO_8hpp.html +74 -0
  156. data/reference/ImageData_8hpp-source.html +62 -0
  157. data/reference/ImageData_8hpp.html +43 -0
  158. data/reference/Image_8hpp-source.html +126 -0
  159. data/reference/Image_8hpp.html +48 -0
  160. data/reference/Input_8hpp-source.html +118 -0
  161. data/reference/Input_8hpp.html +50 -0
  162. data/reference/Math_8hpp-source.html +92 -0
  163. data/reference/Math_8hpp.html +74 -0
  164. data/reference/Platform_8hpp-source.html +83 -0
  165. data/reference/Platform_8hpp.html +73 -0
  166. data/reference/RotFlip_8hpp-source.html +138 -0
  167. data/reference/RotFlip_8hpp.html +77 -0
  168. data/reference/Sockets_8hpp-source.html +130 -0
  169. data/reference/Sockets_8hpp.html +66 -0
  170. data/reference/TextInput_8hpp-source.html +64 -0
  171. data/reference/TextInput_8hpp.html +41 -0
  172. data/reference/Text_8hpp-source.html +51 -0
  173. data/reference/Text_8hpp.html +46 -0
  174. data/reference/Timing_8hpp-source.html +36 -0
  175. data/reference/Timing_8hpp.html +42 -0
  176. data/reference/Utility_8hpp-source.html +44 -0
  177. data/reference/Utility_8hpp.html +48 -0
  178. data/reference/WinUtility_8hpp-source.html +79 -0
  179. data/reference/WinUtility_8hpp.html +64 -0
  180. data/reference/Window_8hpp-source.html +91 -0
  181. data/reference/Window_8hpp.html +41 -0
  182. data/reference/annotated.html +51 -0
  183. data/reference/classGosu_1_1Audio-members.html +34 -0
  184. data/reference/classGosu_1_1Audio.html +46 -0
  185. data/reference/classGosu_1_1Bitmap-members.html +44 -0
  186. data/reference/classGosu_1_1Bitmap.html +263 -0
  187. data/reference/classGosu_1_1Buffer-members.html +44 -0
  188. data/reference/classGosu_1_1Buffer.html +78 -0
  189. data/reference/classGosu_1_1Buffer.png +0 -0
  190. data/reference/classGosu_1_1Button-members.html +36 -0
  191. data/reference/classGosu_1_1Button.html +143 -0
  192. data/reference/classGosu_1_1Color-members.html +56 -0
  193. data/reference/classGosu_1_1Color.html +387 -0
  194. data/reference/classGosu_1_1File-members.html +41 -0
  195. data/reference/classGosu_1_1File.html +69 -0
  196. data/reference/classGosu_1_1File.png +0 -0
  197. data/reference/classGosu_1_1Font-members.html +39 -0
  198. data/reference/classGosu_1_1Font.html +309 -0
  199. data/reference/classGosu_1_1Graphics-members.html +50 -0
  200. data/reference/classGosu_1_1Graphics.html +234 -0
  201. data/reference/classGosu_1_1Image-members.html +45 -0
  202. data/reference/classGosu_1_1Image.html +518 -0
  203. data/reference/classGosu_1_1ImageData-members.html +37 -0
  204. data/reference/classGosu_1_1ImageData.html +60 -0
  205. data/reference/classGosu_1_1Input-members.html +44 -0
  206. data/reference/classGosu_1_1Input.html +223 -0
  207. data/reference/classGosu_1_1MessageSocket-members.html +40 -0
  208. data/reference/classGosu_1_1MessageSocket.html +233 -0
  209. data/reference/classGosu_1_1Resource-members.html +39 -0
  210. data/reference/classGosu_1_1Resource.html +116 -0
  211. data/reference/classGosu_1_1Resource.png +0 -0
  212. data/reference/classGosu_1_1Sample-members.html +37 -0
  213. data/reference/classGosu_1_1Sample.html +200 -0
  214. data/reference/classGosu_1_1SampleInstance-members.html +38 -0
  215. data/reference/classGosu_1_1SampleInstance.html +169 -0
  216. data/reference/classGosu_1_1Song-members.html +43 -0
  217. data/reference/classGosu_1_1Song.html +260 -0
  218. data/reference/classGosu_1_1TextInput-members.html +38 -0
  219. data/reference/classGosu_1_1TextInput.html +121 -0
  220. data/reference/classGosu_1_1Window-members.html +50 -0
  221. data/reference/classGosu_1_1Window.html +271 -0
  222. data/reference/doxyfile +233 -0
  223. data/reference/doxygen.css +433 -0
  224. data/reference/doxygen.png +0 -0
  225. data/reference/files.html +54 -0
  226. data/reference/functions.html +236 -0
  227. data/reference/functions_enum.html +45 -0
  228. data/reference/functions_func.html +227 -0
  229. data/reference/functions_vars.html +47 -0
  230. data/reference/hierarchy.html +53 -0
  231. data/reference/index.html +26 -0
  232. data/reference/namespaceGosu.html +2890 -0
  233. data/reference/namespaceGosu_1_1Colors.html +70 -0
  234. data/reference/namespaceGosu_1_1Win.html +275 -0
  235. data/reference/namespacemembers.html +216 -0
  236. data/reference/namespacemembers_enum.html +52 -0
  237. data/reference/namespacemembers_eval.html +54 -0
  238. data/reference/namespacemembers_func.html +185 -0
  239. data/reference/namespacemembers_type.html +46 -0
  240. data/reference/namespacemembers_vars.html +46 -0
  241. data/reference/namespaces.html +35 -0
  242. data/reference/tab_b.gif +0 -0
  243. data/reference/tab_l.gif +0 -0
  244. data/reference/tab_r.gif +0 -0
  245. data/reference/tabs.css +102 -0
  246. data/windows/Gosu.sln +29 -0
  247. data/windows/Gosu.vcproj +553 -0
  248. data/windows/RubyGosu.vcproj +138 -0
  249. metadata +305 -0
@@ -0,0 +1,447 @@
1
+ #include <Gosu/Window.hpp>
2
+ #include <Gosu/WinUtility.hpp>
3
+ #include <Gosu/Timing.hpp>
4
+ #include <Gosu/Graphics.hpp>
5
+ #include <Gosu/Audio.hpp>
6
+ #include <Gosu/Input.hpp>
7
+ #include <Gosu/TextInput.hpp>
8
+ #include <GosuImpl/Graphics/Common.hpp>
9
+ #include <boost/bind.hpp>
10
+ #include <cassert>
11
+ #include <stdexcept>
12
+ #include <vector>
13
+
14
+ // TODO: Put fullscreen logic in different file, track fullscreen state and
15
+ // enable dynamic toggling between fullscreen and window.
16
+
17
+ namespace Gosu
18
+ {
19
+ namespace
20
+ {
21
+ // Mode guessing experimentally adapted from GLFW library.
22
+ // http://glfw.sourceforge.net/
23
+
24
+ int findClosestVideoMode(int *w, int *h, int *bpp, int *refresh)
25
+ {
26
+ int mode, bestmode, match, bestmatch, rr, bestrr, success;
27
+ DEVMODE dm;
28
+
29
+ // Find best match
30
+ bestmatch = 0x7fffffff;
31
+ bestrr = 0x7fffffff;
32
+ mode = bestmode = 0;
33
+ do
34
+ {
35
+ dm.dmSize = sizeof(DEVMODE);
36
+ success = EnumDisplaySettings(NULL, mode, &dm);
37
+ if( success )
38
+ {
39
+ match = dm.dmBitsPerPel - *bpp;
40
+ if( match < 0 ) match = -match;
41
+ match = (match << 25) |
42
+ ((dm.dmPelsWidth - *w) * (dm.dmPelsWidth - *w) +
43
+ (dm.dmPelsHeight - *h) * (dm.dmPelsHeight - *h));
44
+ if( match < bestmatch )
45
+ {
46
+ bestmatch = match;
47
+ bestmode = mode;
48
+ bestrr = (dm.dmDisplayFrequency - *refresh) *
49
+ (dm.dmDisplayFrequency - *refresh);
50
+ }
51
+ else if( match == bestmatch && *refresh > 0 )
52
+ {
53
+ rr = (dm.dmDisplayFrequency - *refresh) *
54
+ (dm.dmDisplayFrequency - *refresh);
55
+ if( rr < bestrr )
56
+ {
57
+ bestmatch = match;
58
+ bestmode = mode;
59
+ bestrr = rr;
60
+ }
61
+ }
62
+ }
63
+ ++mode;
64
+ }
65
+ while (success);
66
+
67
+ // Get the parameters for the best matching display mode
68
+ dm.dmSize = sizeof(DEVMODE);
69
+ EnumDisplaySettings( NULL, bestmode, &dm );
70
+
71
+ *w = dm.dmPelsWidth;
72
+ *h = dm.dmPelsHeight;
73
+ *bpp = dm.dmBitsPerPel;
74
+ *refresh = dm.dmDisplayFrequency;
75
+
76
+ return bestmode;
77
+ }
78
+
79
+ void setVideoMode(int mode)
80
+ {
81
+ // Get the parameters for the best matching display mode
82
+ DEVMODE dm;
83
+ dm.dmSize = sizeof(DEVMODE);
84
+ EnumDisplaySettings(NULL, mode, &dm);
85
+
86
+ // Set which fields we want to specify
87
+ dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
88
+
89
+ // Change display setting
90
+ dm.dmSize = sizeof(DEVMODE);
91
+ if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
92
+ throw std::runtime_error("Could not set fullscreen mode");
93
+ }
94
+
95
+ void setupVSync()
96
+ {
97
+ char* extensions = (char*)glGetString(GL_EXTENSIONS);
98
+ if (!strstr(extensions, "WGL_EXT_swap_control"))
99
+ return;
100
+ typedef void (APIENTRY *PFNWGLEXTSWAPCONTROLPROC) (int);
101
+ PFNWGLEXTSWAPCONTROLPROC wglSwapIntervalEXT =
102
+ (PFNWGLEXTSWAPCONTROLPROC) wglGetProcAddress("wglSwapIntervalEXT");
103
+ if (!wglSwapIntervalEXT)
104
+ return;
105
+ wglSwapIntervalEXT(1);
106
+ }
107
+
108
+ LRESULT CALLBACK windowProc(HWND wnd, UINT message, WPARAM wparam,
109
+ LPARAM lparam)
110
+ {
111
+ LONG_PTR lptr = GetWindowLongPtr(wnd, GWLP_USERDATA);
112
+
113
+ if (lptr)
114
+ {
115
+ Window* obj = reinterpret_cast<Window*>(lptr);
116
+ return obj->handleMessage(message, wparam, lparam);
117
+ }
118
+ else
119
+ return DefWindowProc(wnd, message, wparam, lparam);
120
+ }
121
+
122
+ LPCTSTR windowClass()
123
+ {
124
+ static LPCTSTR name = 0;
125
+ if (name)
126
+ return name;
127
+
128
+ WNDCLASS wc;
129
+ wc.lpszClassName = L"Gosu::Window";
130
+ wc.style = CS_OWNDC;
131
+ wc.lpfnWndProc = windowProc;
132
+ wc.cbClsExtra = 0;
133
+ wc.cbWndExtra = 0;
134
+ wc.hInstance = Win::instance();
135
+ wc.hIcon = 0;
136
+ wc.hCursor = 0;
137
+ wc.hbrBackground = 0;
138
+ wc.lpszMenuName = 0;
139
+
140
+ name = reinterpret_cast<LPCTSTR>(::RegisterClass(&wc));
141
+ Win::check(name, "registering a window class");
142
+ return name;
143
+ }
144
+ }
145
+ }
146
+
147
+ struct Gosu::Window::Impl
148
+ {
149
+ HWND handle;
150
+ HDC hdc;
151
+ boost::scoped_ptr<Graphics> graphics;
152
+ boost::scoped_ptr<Audio> audio;
153
+ boost::scoped_ptr<Input> input;
154
+ double updateInterval;
155
+ bool iconified;
156
+
157
+ Impl()
158
+ : handle(0), hdc(0), iconified(false)
159
+ {
160
+ }
161
+
162
+ ~Impl()
163
+ {
164
+ if (hdc)
165
+ ReleaseDC(handle, hdc);
166
+ if (handle)
167
+ DestroyWindow(handle);
168
+ }
169
+ };
170
+
171
+ Gosu::Window::Window(unsigned width, unsigned height, bool fullscreen,
172
+ double updateInterval)
173
+ : pimpl(new Impl)
174
+ {
175
+ // Select window styles depending on mode.fullscreen.
176
+ DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
177
+ DWORD styleEx = WS_EX_APPWINDOW;
178
+ if (fullscreen)
179
+ {
180
+ style |= WS_POPUP;
181
+ styleEx |= WS_EX_TOPMOST;
182
+ }
183
+ else
184
+ {
185
+ style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
186
+ styleEx |= WS_EX_WINDOWEDGE;
187
+ }
188
+
189
+ pimpl->handle = CreateWindowEx(styleEx, windowClass(), 0, style,
190
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
191
+ Win::instance(), 0);
192
+ Win::check(pimpl->handle);
193
+
194
+ pimpl->hdc = GetDC(handle());
195
+ Win::check(pimpl->hdc);
196
+
197
+ PIXELFORMATDESCRIPTOR pfd;
198
+ ZeroMemory(&pfd, sizeof pfd);
199
+ pfd.nSize = sizeof pfd;
200
+ pfd.nVersion = 1;
201
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
202
+ pfd.iLayerType = PFD_MAIN_PLANE;
203
+ pfd.iPixelType = PFD_TYPE_RGBA;
204
+ pfd.cColorBits = 32;
205
+ int pf = ChoosePixelFormat(pimpl->hdc, &pfd);
206
+ Win::check(pf);
207
+ Win::check(SetPixelFormat(pimpl->hdc, pf, &pfd));
208
+
209
+ HGLRC hrc = Win::check(wglCreateContext(pimpl->hdc), "creating rendering context");
210
+ Win::check(wglMakeCurrent(pimpl->hdc, hrc), "selecting the rendering context");
211
+
212
+ setupVSync();
213
+
214
+ SetLastError(0);
215
+ SetWindowLongPtr(handle(), GWLP_USERDATA,
216
+ reinterpret_cast<LONG_PTR>(this));
217
+ if (GetLastError() != 0)
218
+ Win::throwLastError("setting the window's GWLP_USERDATA pointer");
219
+
220
+ // Determine the size the window needs to have.
221
+ RECT rc = { 0, 0, width, height };
222
+ AdjustWindowRectEx(&rc, style, FALSE, styleEx);
223
+ unsigned windowW = rc.right - rc.left;
224
+ unsigned windowH = rc.bottom - rc.top;
225
+
226
+ int windowX = 0;
227
+ int windowY = 0;
228
+
229
+ if (!fullscreen)
230
+ {
231
+ // Center the window.
232
+ HWND desktopWindow = GetDesktopWindow();
233
+ RECT desktopRect;
234
+ GetClientRect(desktopWindow, &desktopRect);
235
+ int desktopW = desktopRect.right - desktopRect.left;
236
+ int desktopH = desktopRect.bottom - desktopRect.top;
237
+ windowX = (desktopW - windowW) / 2;
238
+ windowY = (desktopH - windowH) / 2;
239
+ }
240
+
241
+ MoveWindow(handle(), windowX, windowY, windowW, windowH, false);
242
+
243
+ pimpl->graphics.reset(new Gosu::Graphics(width, height, fullscreen));
244
+ pimpl->input.reset(new Gosu::Input(handle()));
245
+ input().onButtonDown = boost::bind(&Window::buttonDown, this, _1);
246
+ input().onButtonUp = boost::bind(&Window::buttonUp, this, _1);
247
+
248
+ pimpl->updateInterval = updateInterval;
249
+ }
250
+
251
+ Gosu::Window::~Window()
252
+ {
253
+ wglMakeCurrent(0, 0);
254
+ }
255
+
256
+ std::wstring Gosu::Window::caption() const
257
+ {
258
+ int bufLen = GetWindowTextLength(handle()) + 1;
259
+
260
+ if (bufLen < 2)
261
+ return L"";
262
+
263
+ std::vector<TCHAR> buf(bufLen);
264
+ GetWindowText(handle(), &buf.front(), bufLen);
265
+ return &buf.front();
266
+ }
267
+
268
+ void Gosu::Window::setCaption(const std::wstring& value)
269
+ {
270
+ SetWindowText(handle(), value.c_str());
271
+ }
272
+
273
+ namespace GosusDarkSide
274
+ {
275
+ // TODO: Find a way for this to fit into Gosu's design.
276
+ // This can point to a function that wants to be called every
277
+ // frame, e.g. rb_thread_schedule.
278
+ typedef void (*HookOfHorror)();
279
+ HookOfHorror oncePerTick = 0;
280
+ }
281
+
282
+ void Gosu::Window::show()
283
+ {
284
+ int w = graphics().width(), h = graphics().height(), bpp = 32, rr = 60;
285
+ if (pimpl->graphics->fullscreen())
286
+ setVideoMode(findClosestVideoMode(&w, &h, &bpp, &rr));
287
+ ShowWindow(handle(), SW_SHOW);
288
+ try
289
+ {
290
+ Win::processMessages();
291
+
292
+ unsigned lastTick = 0;
293
+ bool lastFrameSkipped = false;
294
+
295
+ for (;;)
296
+ {
297
+ Win::processMessages();
298
+
299
+ if (GosusDarkSide::oncePerTick) GosusDarkSide::oncePerTick();
300
+
301
+ if (!::IsWindowVisible(handle()))
302
+ return;
303
+
304
+ unsigned ms = milliseconds();
305
+
306
+ if (ms < lastTick || ms - lastTick >= pimpl->updateInterval)
307
+ {
308
+ lastTick = ms;
309
+ input().update();
310
+ update();
311
+ ::InvalidateRect(handle(), 0, FALSE);
312
+ lastFrameSkipped = false;
313
+ }
314
+ }
315
+ }
316
+ catch (...)
317
+ {
318
+ close();
319
+ throw;
320
+ }
321
+ }
322
+
323
+ void Gosu::Window::close()
324
+ {
325
+ ShowWindow(handle(), SW_HIDE);
326
+ if (graphics().fullscreen())
327
+ ChangeDisplaySettings(NULL, CDS_FULLSCREEN);
328
+ }
329
+
330
+ const Gosu::Graphics& Gosu::Window::graphics() const
331
+ {
332
+ return *pimpl->graphics;
333
+ }
334
+
335
+ Gosu::Graphics& Gosu::Window::graphics()
336
+ {
337
+ return *pimpl->graphics;
338
+ }
339
+
340
+ const Gosu::Audio& Gosu::Window::audio() const
341
+ {
342
+ if (!pimpl->audio)
343
+ pimpl->audio.reset(new Gosu::Audio(handle()));
344
+ return *pimpl->audio;
345
+ }
346
+
347
+ Gosu::Audio& Gosu::Window::audio()
348
+ {
349
+ if (!pimpl->audio)
350
+ pimpl->audio.reset(new Gosu::Audio(handle()));
351
+ return *pimpl->audio;
352
+ }
353
+
354
+ const Gosu::Input& Gosu::Window::input() const
355
+ {
356
+ return *pimpl->input;
357
+ }
358
+
359
+ Gosu::Input& Gosu::Window::input()
360
+ {
361
+ return *pimpl->input;
362
+ }
363
+
364
+ HWND Gosu::Window::handle() const
365
+ {
366
+ return pimpl->handle;
367
+ }
368
+
369
+ LRESULT Gosu::Window::handleMessage(UINT message, WPARAM wparam, LPARAM lparam)
370
+ {
371
+ if (message == WM_SETFOCUS && graphics().fullscreen() && IsWindowVisible(pimpl->handle))
372
+ {
373
+ if (pimpl->iconified)
374
+ {
375
+ OpenIcon(pimpl->handle);
376
+ int w = graphics().width(), h = graphics().height(), bpp = 32, rr = 60;
377
+ setVideoMode(findClosestVideoMode(&w, &h, &bpp, &rr));
378
+ pimpl->iconified = false;
379
+ }
380
+ return 0;
381
+ }
382
+
383
+ if (message == WM_KILLFOCUS && graphics().fullscreen() && IsWindowVisible(pimpl->handle))
384
+ {
385
+ if (!pimpl->iconified)
386
+ {
387
+ ChangeDisplaySettings(NULL, CDS_FULLSCREEN);
388
+ CloseWindow(pimpl->handle);
389
+ pimpl->iconified = true;
390
+ }
391
+ return 0;
392
+ }
393
+
394
+ if (message == WM_CLOSE)
395
+ {
396
+ close();
397
+ return 0;
398
+ }
399
+
400
+ if (message == WM_PAINT)
401
+ {
402
+ if (pimpl->graphics && graphics().begin())
403
+ {
404
+ try
405
+ {
406
+ draw();
407
+ }
408
+ catch (...)
409
+ {
410
+ graphics().end();
411
+ throw;
412
+ }
413
+ graphics().end();
414
+ }
415
+ SwapBuffers(pimpl->hdc);
416
+ ValidateRect(handle(), 0);
417
+ return 0;
418
+ }
419
+
420
+ if (message == WM_SETCURSOR && LOWORD(lparam) == HTCLIENT)
421
+ {
422
+ SetCursor(0);
423
+ return TRUE;
424
+ }
425
+
426
+ if (message == WM_SYSCOMMAND)
427
+ {
428
+ switch(wparam)
429
+ {
430
+ case SC_SCREENSAVE:
431
+ case SC_MONITORPOWER:
432
+ if (graphics().fullscreen())
433
+ return 0;
434
+ else
435
+ break;
436
+ case SC_KEYMENU:
437
+ return 0;
438
+ }
439
+ }
440
+
441
+ if (pimpl->input && input().textInput() && input().textInput()->feedMessage(message, wparam, lparam))
442
+ {
443
+ return 0;
444
+ }
445
+
446
+ return DefWindowProc(handle(), message, wparam, lparam);
447
+ }
@@ -0,0 +1,392 @@
1
+ // While (re)writing this file, I have been looking at many other libraries since all the
2
+ // "official" documentation was horrible, at least those parts that I was able to find.
3
+ // Kudos to the Pyglet folks (http://www.pyglet.org/) who wrote code that was much easier to
4
+ // understand than that!
5
+
6
+ #include <Gosu/Window.hpp>
7
+ #include <Gosu/Timing.hpp>
8
+ #include <Gosu/Utility.hpp>
9
+ #include <Gosu/Input.hpp>
10
+ #include <Gosu/Graphics.hpp>
11
+ #include <Gosu/Audio.hpp>
12
+ #include <boost/bind.hpp>
13
+ #include <stdexcept>
14
+ #include <algorithm>
15
+ #include <vector>
16
+
17
+ #include <GL/glx.h>
18
+ #include <X11/Xlib.h>
19
+ #include <X11/Xutil.h>
20
+ #include "X11vroot.h"
21
+
22
+ namespace
23
+ {
24
+ template<typename T>
25
+ class scoped_resource
26
+ {
27
+ T* pointer;
28
+ typedef boost::function<void(T*)> Deleter;
29
+ Deleter deleter;
30
+
31
+ public:
32
+ scoped_resource(T* pointer, const Deleter& deleter)
33
+ : pointer(pointer), deleter(deleter)
34
+ {
35
+ }
36
+
37
+ void reset(T* newPointer = 0)
38
+ {
39
+ if (pointer)
40
+ deleter(pointer);
41
+ pointer = newPointer;
42
+ }
43
+
44
+ T* get() const
45
+ {
46
+ return pointer;
47
+ }
48
+
49
+ T* operator->() const
50
+ {
51
+ return get();
52
+ }
53
+
54
+ ~scoped_resource()
55
+ {
56
+ reset(0);
57
+ }
58
+ };
59
+ }
60
+
61
+ struct Gosu::Window::Impl
62
+ {
63
+ boost::scoped_ptr<Graphics> graphics;
64
+ boost::scoped_ptr<Input> input;
65
+ boost::scoped_ptr<Audio> audio;
66
+
67
+ ::Display* display;
68
+
69
+ bool mapped, showing, active;
70
+
71
+ ::GLXContext context;
72
+ ::Window window;
73
+ ::XVisualInfo* visual;
74
+
75
+ // Last set title
76
+ std::wstring title;
77
+ // Last known position
78
+ int x, y;
79
+ // Last known size
80
+ int width, height;
81
+
82
+
83
+ double updateInterval;
84
+ bool fullscreen;
85
+
86
+ Impl(unsigned width, unsigned height, unsigned fullscreen, double updateInterval)
87
+ : mapped(false), showing(false), active(true),
88
+ x(0), y(0), width(width), height(height),
89
+ updateInterval(updateInterval), fullscreen(fullscreen)
90
+ {
91
+
92
+ }
93
+
94
+ void executeAndWait(boost::function<void(Display*, ::Window)> function, int forMessage)
95
+ {
96
+ XSelectInput(display, window, StructureNotifyMask);
97
+ function(display, window);
98
+ while (true)
99
+ {
100
+ ::XEvent event;
101
+ XNextEvent(display, &event);
102
+ if (event.type == forMessage)
103
+ break;
104
+ }
105
+ XSelectInput(display, window, 0x1ffffff & ~PointerMotionHintMask & ~ResizeRedirectMask);
106
+ }
107
+
108
+ void doTick(Window* window)
109
+ {
110
+ while (::XPending(display))
111
+ {
112
+ ::XEvent event;
113
+ XNextEvent(display, &event);
114
+
115
+ // Override redirect fix (thanks for Pyglet folks again):
116
+ if (event.type == ButtonPress && fullscreen && !active)
117
+ XSetInputFocus(display, this->window, RevertToParent, CurrentTime);
118
+
119
+ if (!window->input().feedXEvent(event, window))
120
+ {
121
+ if (event.type == ConfigureNotify)
122
+ {
123
+ // Only boring stuff to do? Let's do something random:
124
+ glXMakeCurrent(display, this->window, context);
125
+ }
126
+ else if (event.type == ClientMessage)
127
+ {
128
+ if (static_cast<unsigned>(event.xclient.data.l[0]) ==
129
+ XInternAtom(display, "WM_DELETE_WINDOW", false))
130
+ window->close();
131
+ }
132
+ else if (event.type == FocusIn)
133
+ active = true;
134
+ else if (event.type == FocusOut)
135
+ active = false;
136
+ }
137
+ }
138
+
139
+ if (window->graphics().begin(Colors::black))
140
+ {
141
+ window->draw();
142
+ window->graphics().end();
143
+ glXSwapBuffers(display, this->window);
144
+ }
145
+
146
+ window->input().update();
147
+ window->update();
148
+ }
149
+ };
150
+
151
+ Gosu::Window::Window(unsigned width, unsigned height, bool fullscreen,
152
+ double updateInterval)
153
+ : pimpl(new Impl(width, height, fullscreen, updateInterval))
154
+ {
155
+ pimpl->display = XOpenDisplay(NULL);
156
+ if (!pimpl->display)
157
+ throw std::runtime_error("Cannot find display");
158
+
159
+ ::Window root = DefaultRootWindow(pimpl->display);
160
+
161
+ // Setup GLX visual
162
+ static int glxAttributes[] =
163
+ {
164
+ GLX_RGBA,
165
+ GLX_DOUBLEBUFFER,
166
+ GLX_RED_SIZE, 1,
167
+ GLX_GREEN_SIZE, 1,
168
+ GLX_BLUE_SIZE, 1,
169
+ GLX_DEPTH_SIZE, 1,
170
+ None
171
+ };
172
+ pimpl->visual = glXChooseVisual(pimpl->display, DefaultScreen(pimpl->display), glxAttributes);
173
+
174
+ // Create GLX context
175
+ pimpl->context = glXCreateContext(pimpl->display, pimpl->visual, 0, GL_TRUE);
176
+
177
+ // Set up window attributes (& mask)
178
+ XSetWindowAttributes windowAttributes;
179
+ windowAttributes.colormap = XCreateColormap(pimpl->display, root, pimpl->visual->visual, AllocNone);
180
+ windowAttributes.bit_gravity = NorthWestGravity;
181
+ windowAttributes.background_pixel = 0;
182
+ unsigned mask = CWColormap | CWBitGravity | CWBackPixel;
183
+
184
+ // Create window
185
+ pimpl->window = XCreateWindow(pimpl->display, root, 0, 0, width, height, 0,
186
+ pimpl->visual->depth, InputOutput, pimpl->visual->visual,
187
+ mask, &windowAttributes);
188
+
189
+ // Request a close button for the window
190
+ Atom atoms[] = { XInternAtom(pimpl->display, "WM_DELETE_WINDOW", false) };
191
+ XSetWMProtocols(pimpl->display, pimpl->window, atoms, 1);
192
+
193
+ Screen* screen = XScreenOfDisplay(pimpl->display,
194
+ DefaultScreen(pimpl->display));
195
+
196
+ if (fullscreen)
197
+ {
198
+ pimpl->width = screen->width;
199
+ pimpl->height = screen->height;
200
+ XMoveResizeWindow(pimpl->display, pimpl->window, 0, 0,
201
+ screen->width, screen->height);
202
+
203
+ XSetWindowAttributes windowAttributes;
204
+ windowAttributes.override_redirect = true;
205
+ unsigned mask = CWOverrideRedirect;
206
+ XChangeWindowAttributes(pimpl->display, pimpl->window, mask, &windowAttributes);
207
+ }
208
+ else
209
+ ; // Window already has requested size
210
+
211
+ // Set window to be non resizable
212
+ scoped_resource<XSizeHints> sizeHints(XAllocSizeHints(), XFree);
213
+ sizeHints->flags = PMinSize | PMaxSize;
214
+ sizeHints->min_width = sizeHints->max_width = pimpl->width;
215
+ sizeHints->min_height = sizeHints->max_height = pimpl->height;
216
+ XSetWMNormalHints(pimpl->display, pimpl->window, sizeHints.get());
217
+ sizeHints.reset();
218
+
219
+ // TODO: Window style (_MOTIF_WM_HINTS)?
220
+
221
+ XColor black, dummy;
222
+ XAllocNamedColor(pimpl->display, screen->cmap, "black", &black, &dummy);
223
+ char emptyData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
224
+ Pixmap emptyBitmap =
225
+ XCreateBitmapFromData(pimpl->display, pimpl->window, emptyData, 8, 8);
226
+ Cursor emptyCursor = XCreatePixmapCursor(pimpl->display, emptyBitmap,
227
+ emptyBitmap, &black, &black, 0, 0);
228
+ XDefineCursor(pimpl->display, pimpl->window, emptyCursor);
229
+ XFreeCursor(pimpl->display, emptyCursor);
230
+
231
+ // Must be current already so that Graphics' constructor can set up things
232
+ glXMakeCurrent(pimpl->display, pimpl->window, pimpl->context);
233
+
234
+ // Now set up major Gosu components
235
+ pimpl->graphics.reset(new Gosu::Graphics(pimpl->width, pimpl->height, fullscreen));
236
+ pimpl->input.reset(new Gosu::Input(pimpl->display));
237
+ input().onButtonDown = boost::bind(&Window::buttonDown, this, _1);
238
+ input().onButtonUp = boost::bind(&Window::buttonUp, this, _1);
239
+
240
+ // Fix coordinates for fullscreen screen-scaling
241
+ if (fullscreen)
242
+ {
243
+ graphics().setResolution(width, height);
244
+ input().setMouseFactors(1.0 * width / pimpl->width,
245
+ 1.0 * height / pimpl->height);
246
+ }
247
+ }
248
+
249
+ Gosu::Window::~Window()
250
+ {
251
+ XDestroyWindow(pimpl->display, pimpl->window);
252
+ XSync(pimpl->display, false);
253
+ }
254
+
255
+ std::wstring Gosu::Window::caption() const
256
+ {
257
+ return pimpl->title;
258
+ }
259
+
260
+ void Gosu::Window::setCaption(const std::wstring& caption)
261
+ {
262
+ // TODO: Update to _NET_WM_NAME
263
+
264
+ pimpl->title = caption;
265
+
266
+ // TODO: Why?!
267
+ //if (!pimpl->showing)
268
+ // return;
269
+
270
+ std::string tmpString(pimpl->title.begin(), pimpl->title.end());
271
+ std::vector<char> title(pimpl->title.size() + 1);
272
+ std::copy(tmpString.begin(), tmpString.end(), title.begin());
273
+ title.back() = 0;
274
+
275
+ XTextProperty titleprop;
276
+ char* titlePtr = &title[0];
277
+ XStringListToTextProperty(&titlePtr, 1, &titleprop);
278
+
279
+ XSetWMName(pimpl->display, pimpl->window, &titleprop);
280
+ XFree(titleprop.value);
281
+ XSync(pimpl->display, false);
282
+ }
283
+
284
+ namespace GosusDarkSide
285
+ {
286
+ // TODO: Find a way for this to fit into Gosu's design.
287
+ // This can point to a function that wants to be called every
288
+ // frame, e.g. rb_thread_schedule.
289
+ typedef void (*HookOfHorror)();
290
+ HookOfHorror oncePerTick = 0;
291
+ }
292
+
293
+ // TODO: Some exception safety
294
+
295
+ void Gosu::Window::show()
296
+ {
297
+ // Map window
298
+ pimpl->executeAndWait(XMapRaised, MapNotify);
299
+ pimpl->mapped = true;
300
+
301
+ // Make glx current
302
+ glXMakeCurrent(pimpl->display, pimpl->window, pimpl->context);
303
+
304
+ if (pimpl->fullscreen)
305
+ XSetInputFocus(pimpl->display, pimpl->window, RevertToParent, CurrentTime);
306
+
307
+ setCaption(pimpl->title);
308
+
309
+ unsigned startTime, endTime;
310
+
311
+ pimpl->showing = true;
312
+ while (pimpl->showing)
313
+ {
314
+ startTime = milliseconds();
315
+ pimpl->doTick(this);
316
+ if (GosusDarkSide::oncePerTick) GosusDarkSide::oncePerTick();
317
+ endTime = milliseconds();
318
+
319
+ if (startTime < endTime && (endTime - startTime) < pimpl->updateInterval)
320
+ sleep(pimpl->updateInterval - (endTime - startTime));
321
+ }
322
+
323
+ glXMakeCurrent(pimpl->display, 0, 0);
324
+ pimpl->executeAndWait(XUnmapWindow, UnmapNotify);
325
+ pimpl->mapped = false;
326
+ }
327
+
328
+ void Gosu::Window::close()
329
+ {
330
+ pimpl->showing = false;
331
+ }
332
+
333
+ const Gosu::Graphics& Gosu::Window::graphics() const
334
+ {
335
+ return *pimpl->graphics;
336
+ }
337
+
338
+ Gosu::Graphics& Gosu::Window::graphics()
339
+ {
340
+ return *pimpl->graphics;
341
+ }
342
+
343
+ const Gosu::Audio& Gosu::Window::audio() const
344
+ {
345
+ if (!pimpl->audio)
346
+ pimpl->audio.reset(new Gosu::Audio());
347
+ return *pimpl->audio;
348
+ }
349
+
350
+ Gosu::Audio& Gosu::Window::audio()
351
+ {
352
+ if (!pimpl->audio)
353
+ pimpl->audio.reset(new Gosu::Audio());
354
+ return *pimpl->audio;
355
+ }
356
+
357
+ const Gosu::Input& Gosu::Window::input() const
358
+ {
359
+ return *pimpl->input;
360
+ }
361
+
362
+ Gosu::Input& Gosu::Window::input()
363
+ {
364
+ return *pimpl->input;
365
+ }
366
+
367
+ namespace
368
+ {
369
+ void makeCurrentContext(Display* dpy, GLXDrawable drawable, GLXContext context) {
370
+ if (!glXMakeCurrent(dpy, drawable, context))
371
+ printf("glXMakeCurrent failed\n");
372
+ }
373
+
374
+ void releaseContext(Display* dpy, GLXContext context) {
375
+ glXDestroyContext(dpy, context);
376
+ }
377
+ }
378
+
379
+ Gosu::Window::SharedContext Gosu::Window::createSharedContext() {
380
+ const char* displayName = DisplayString( pimpl->display );
381
+ Display* dpy2 = XOpenDisplay( displayName );
382
+ if (!dpy2)
383
+ throw std::runtime_error("Could not duplicate X display");
384
+
385
+ GLXContext ctx = glXCreateContext(dpy2, pimpl->visual, pimpl->context, True);
386
+ if (!ctx)
387
+ throw std::runtime_error("Could not create shared GLX context");
388
+
389
+ return SharedContext(
390
+ new boost::function<void()>(boost::bind(makeCurrentContext, dpy2, pimpl->window, ctx)),
391
+ boost::bind(releaseContext, dpy2, ctx));
392
+ }