gosu 0.7.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }