Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/freeglut/src/mswin/fg_main_mswin.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * fg_main_mswin.c | |
| 3 * | |
| 4 * The Windows-specific mouse cursor related stuff. | |
| 5 * | |
| 6 * Copyright (c) 2012 Stephen J. Baker. All Rights Reserved. | |
| 7 * Written by John F. Fay, <fayjf@sourceforge.net> | |
| 8 * Creation date: Sat Jan 21, 2012 | |
| 9 * | |
| 10 * Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 * copy of this software and associated documentation files (the "Software"), | |
| 12 * to deal in the Software without restriction, including without limitation | |
| 13 * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 * and/or sell copies of the Software, and to permit persons to whom the | |
| 15 * Software is furnished to do so, subject to the following conditions: | |
| 16 * | |
| 17 * The above copyright notice and this permission notice shall be included | |
| 18 * in all copies or substantial portions of the Software. | |
| 19 * | |
| 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
| 21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| 24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 26 */ | |
| 27 | |
| 28 #include <GL/freeglut.h> | |
| 29 #include "../fg_internal.h" | |
| 30 | |
| 31 #ifndef MAPVK_VK_TO_CHAR | |
| 32 #define MAPVK_VK_TO_CHAR 2 | |
| 33 #endif | |
| 34 | |
| 35 extern void fghRedrawWindow ( SFG_Window *window ); | |
| 36 extern void fghRedrawWindowAndChildren ( SFG_Window *window ); | |
| 37 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify); | |
| 38 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify); | |
| 39 extern void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ); | |
| 40 extern void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ); | |
| 41 | |
| 42 extern void fgNewWGLCreateContext( SFG_Window* window ); | |
| 43 extern GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, | |
| 44 unsigned char layer_type ); | |
| 45 | |
| 46 extern void fgPlatformCheckMenuDeactivate(HWND newFocusWnd); | |
| 47 | |
| 48 #ifdef WM_TOUCH | |
| 49 typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); | |
| 50 typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT); | |
| 51 static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF; | |
| 52 static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF; | |
| 53 #endif | |
| 54 | |
| 55 #ifdef _WIN32_WCE | |
| 56 typedef struct GXDisplayProperties GXDisplayProperties; | |
| 57 typedef struct GXKeyList GXKeyList; | |
| 58 #include <gx.h> | |
| 59 | |
| 60 typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); | |
| 61 typedef int (*GXOPENINPUT)(); | |
| 62 | |
| 63 GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; | |
| 64 GXOPENINPUT GXOpenInput_ = NULL; | |
| 65 | |
| 66 struct GXKeyList gxKeyList; | |
| 67 #endif /* _WIN32_WCE */ | |
| 68 | |
| 69 #ifdef _DEBUG | |
| 70 /* | |
| 71 * WM_ message to string, for debugging | |
| 72 * This is taken from the 8.0 SDK, so Windows 8 API and everything earlier is included | |
| 73 */ | |
| 74 struct WM_MESSAGE_MAP | |
| 75 { | |
| 76 UINT nMsg; | |
| 77 LPCSTR lpszMsg; | |
| 78 }; | |
| 79 #define DEFINE_MESSAGE(wm){ wm, #wm } | |
| 80 static struct WM_MESSAGE_MAP allMessages[] = | |
| 81 { | |
| 82 DEFINE_MESSAGE(WM_NULL), | |
| 83 DEFINE_MESSAGE(WM_CREATE), | |
| 84 DEFINE_MESSAGE(WM_DESTROY), | |
| 85 DEFINE_MESSAGE(WM_MOVE), | |
| 86 DEFINE_MESSAGE(WM_SIZE), | |
| 87 | |
| 88 DEFINE_MESSAGE(WM_ACTIVATE), | |
| 89 DEFINE_MESSAGE(WM_SETFOCUS), | |
| 90 DEFINE_MESSAGE(WM_KILLFOCUS), | |
| 91 DEFINE_MESSAGE(WM_ENABLE), | |
| 92 DEFINE_MESSAGE(WM_SETREDRAW), | |
| 93 DEFINE_MESSAGE(WM_SETTEXT), | |
| 94 DEFINE_MESSAGE(WM_GETTEXT), | |
| 95 DEFINE_MESSAGE(WM_GETTEXTLENGTH), | |
| 96 DEFINE_MESSAGE(WM_PAINT), | |
| 97 DEFINE_MESSAGE(WM_CLOSE), | |
| 98 # ifndef _WIN32_WCE | |
| 99 DEFINE_MESSAGE(WM_QUERYENDSESSION), | |
| 100 DEFINE_MESSAGE(WM_QUERYOPEN), | |
| 101 DEFINE_MESSAGE(WM_ENDSESSION), | |
| 102 # endif | |
| 103 DEFINE_MESSAGE(WM_QUIT), | |
| 104 DEFINE_MESSAGE(WM_ERASEBKGND), | |
| 105 DEFINE_MESSAGE(WM_SYSCOLORCHANGE), | |
| 106 DEFINE_MESSAGE(WM_SHOWWINDOW), | |
| 107 DEFINE_MESSAGE(WM_WININICHANGE), | |
| 108 | |
| 109 DEFINE_MESSAGE(WM_DEVMODECHANGE), | |
| 110 DEFINE_MESSAGE(WM_ACTIVATEAPP), | |
| 111 DEFINE_MESSAGE(WM_FONTCHANGE), | |
| 112 DEFINE_MESSAGE(WM_TIMECHANGE), | |
| 113 DEFINE_MESSAGE(WM_CANCELMODE), | |
| 114 DEFINE_MESSAGE(WM_SETCURSOR), | |
| 115 DEFINE_MESSAGE(WM_MOUSEACTIVATE), | |
| 116 DEFINE_MESSAGE(WM_CHILDACTIVATE), | |
| 117 DEFINE_MESSAGE(WM_QUEUESYNC), | |
| 118 | |
| 119 DEFINE_MESSAGE(WM_GETMINMAXINFO), | |
| 120 | |
| 121 DEFINE_MESSAGE(WM_PAINTICON), | |
| 122 DEFINE_MESSAGE(WM_ICONERASEBKGND), | |
| 123 DEFINE_MESSAGE(WM_NEXTDLGCTL), | |
| 124 DEFINE_MESSAGE(WM_SPOOLERSTATUS), | |
| 125 DEFINE_MESSAGE(WM_DRAWITEM), | |
| 126 DEFINE_MESSAGE(WM_MEASUREITEM), | |
| 127 DEFINE_MESSAGE(WM_DELETEITEM), | |
| 128 DEFINE_MESSAGE(WM_VKEYTOITEM), | |
| 129 DEFINE_MESSAGE(WM_CHARTOITEM), | |
| 130 DEFINE_MESSAGE(WM_SETFONT), | |
| 131 DEFINE_MESSAGE(WM_GETFONT), | |
| 132 DEFINE_MESSAGE(WM_SETHOTKEY), | |
| 133 DEFINE_MESSAGE(WM_GETHOTKEY), | |
| 134 DEFINE_MESSAGE(WM_QUERYDRAGICON), | |
| 135 DEFINE_MESSAGE(WM_COMPAREITEM), | |
| 136 # if(WINVER >= 0x0500) | |
| 137 # ifndef _WIN32_WCE | |
| 138 DEFINE_MESSAGE(WM_GETOBJECT), | |
| 139 # endif | |
| 140 # endif /* WINVER >= 0x0500 */ | |
| 141 DEFINE_MESSAGE(WM_COMPACTING), | |
| 142 DEFINE_MESSAGE(WM_COMMNOTIFY), | |
| 143 DEFINE_MESSAGE(WM_WINDOWPOSCHANGING), | |
| 144 DEFINE_MESSAGE(WM_WINDOWPOSCHANGED), | |
| 145 | |
| 146 DEFINE_MESSAGE(WM_POWER), | |
| 147 | |
| 148 DEFINE_MESSAGE(WM_COPYDATA), | |
| 149 DEFINE_MESSAGE(WM_CANCELJOURNAL), | |
| 150 | |
| 151 # if(WINVER >= 0x0400) | |
| 152 DEFINE_MESSAGE(WM_NOTIFY), | |
| 153 DEFINE_MESSAGE(WM_INPUTLANGCHANGEREQUEST), | |
| 154 DEFINE_MESSAGE(WM_INPUTLANGCHANGE), | |
| 155 DEFINE_MESSAGE(WM_TCARD), | |
| 156 DEFINE_MESSAGE(WM_HELP), | |
| 157 DEFINE_MESSAGE(WM_USERCHANGED), | |
| 158 DEFINE_MESSAGE(WM_NOTIFYFORMAT), | |
| 159 | |
| 160 DEFINE_MESSAGE(WM_CONTEXTMENU), | |
| 161 DEFINE_MESSAGE(WM_STYLECHANGING), | |
| 162 DEFINE_MESSAGE(WM_STYLECHANGED), | |
| 163 DEFINE_MESSAGE(WM_DISPLAYCHANGE), | |
| 164 DEFINE_MESSAGE(WM_GETICON), | |
| 165 DEFINE_MESSAGE(WM_SETICON), | |
| 166 # endif /* WINVER >= 0x0400 */ | |
| 167 | |
| 168 DEFINE_MESSAGE(WM_NCCREATE), | |
| 169 DEFINE_MESSAGE(WM_NCDESTROY), | |
| 170 DEFINE_MESSAGE(WM_NCCALCSIZE), | |
| 171 DEFINE_MESSAGE(WM_NCHITTEST), | |
| 172 DEFINE_MESSAGE(WM_NCPAINT), | |
| 173 DEFINE_MESSAGE(WM_NCACTIVATE), | |
| 174 DEFINE_MESSAGE(WM_GETDLGCODE), | |
| 175 # ifndef _WIN32_WCE | |
| 176 DEFINE_MESSAGE(WM_SYNCPAINT), | |
| 177 # endif | |
| 178 DEFINE_MESSAGE(WM_NCMOUSEMOVE), | |
| 179 DEFINE_MESSAGE(WM_NCLBUTTONDOWN), | |
| 180 DEFINE_MESSAGE(WM_NCLBUTTONUP), | |
| 181 DEFINE_MESSAGE(WM_NCLBUTTONDBLCLK), | |
| 182 DEFINE_MESSAGE(WM_NCRBUTTONDOWN), | |
| 183 DEFINE_MESSAGE(WM_NCRBUTTONUP), | |
| 184 DEFINE_MESSAGE(WM_NCRBUTTONDBLCLK), | |
| 185 DEFINE_MESSAGE(WM_NCMBUTTONDOWN), | |
| 186 DEFINE_MESSAGE(WM_NCMBUTTONUP), | |
| 187 DEFINE_MESSAGE(WM_NCMBUTTONDBLCLK), | |
| 188 | |
| 189 | |
| 190 | |
| 191 # if(_WIN32_WINNT >= 0x0500) && defined(WM_NCXBUTTONDOWN) | |
| 192 DEFINE_MESSAGE(WM_NCXBUTTONDOWN), | |
| 193 DEFINE_MESSAGE(WM_NCXBUTTONUP), | |
| 194 DEFINE_MESSAGE(WM_NCXBUTTONDBLCLK), | |
| 195 # endif /* _WIN32_WINNT >= 0x0500 */ | |
| 196 | |
| 197 | |
| 198 # if(_WIN32_WINNT >= 0x0501) | |
| 199 DEFINE_MESSAGE(WM_INPUT_DEVICE_CHANGE), | |
| 200 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 201 | |
| 202 # if(_WIN32_WINNT >= 0x0501) | |
| 203 DEFINE_MESSAGE(WM_INPUT), | |
| 204 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 205 | |
| 206 DEFINE_MESSAGE(WM_KEYDOWN), | |
| 207 DEFINE_MESSAGE(WM_KEYUP), | |
| 208 DEFINE_MESSAGE(WM_CHAR), | |
| 209 DEFINE_MESSAGE(WM_DEADCHAR), | |
| 210 DEFINE_MESSAGE(WM_SYSKEYDOWN), | |
| 211 DEFINE_MESSAGE(WM_SYSKEYUP), | |
| 212 DEFINE_MESSAGE(WM_SYSCHAR), | |
| 213 DEFINE_MESSAGE(WM_SYSDEADCHAR), | |
| 214 # if(_WIN32_WINNT >= 0x0501) | |
| 215 DEFINE_MESSAGE(WM_UNICHAR), | |
| 216 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 217 | |
| 218 # if(WINVER >= 0x0400) | |
| 219 DEFINE_MESSAGE(WM_IME_STARTCOMPOSITION), | |
| 220 DEFINE_MESSAGE(WM_IME_ENDCOMPOSITION), | |
| 221 DEFINE_MESSAGE(WM_IME_COMPOSITION), | |
| 222 DEFINE_MESSAGE(WM_IME_KEYLAST), | |
| 223 # endif /* WINVER >= 0x0400 */ | |
| 224 | |
| 225 DEFINE_MESSAGE(WM_INITDIALOG), | |
| 226 DEFINE_MESSAGE(WM_COMMAND), | |
| 227 DEFINE_MESSAGE(WM_SYSCOMMAND), | |
| 228 DEFINE_MESSAGE(WM_TIMER), | |
| 229 DEFINE_MESSAGE(WM_HSCROLL), | |
| 230 DEFINE_MESSAGE(WM_VSCROLL), | |
| 231 DEFINE_MESSAGE(WM_INITMENU), | |
| 232 DEFINE_MESSAGE(WM_INITMENUPOPUP), | |
| 233 # if(WINVER >= 0x0601) | |
| 234 DEFINE_MESSAGE(WM_GESTURE), | |
| 235 DEFINE_MESSAGE(WM_GESTURENOTIFY), | |
| 236 # endif /* WINVER >= 0x0601 */ | |
| 237 DEFINE_MESSAGE(WM_MENUSELECT), | |
| 238 DEFINE_MESSAGE(WM_MENUCHAR), | |
| 239 DEFINE_MESSAGE(WM_ENTERIDLE), | |
| 240 # if(WINVER >= 0x0500) | |
| 241 # ifndef _WIN32_WCE | |
| 242 DEFINE_MESSAGE(WM_MENURBUTTONUP), | |
| 243 DEFINE_MESSAGE(WM_MENUDRAG), | |
| 244 DEFINE_MESSAGE(WM_MENUGETOBJECT), | |
| 245 DEFINE_MESSAGE(WM_UNINITMENUPOPUP), | |
| 246 DEFINE_MESSAGE(WM_MENUCOMMAND), | |
| 247 | |
| 248 # if(_WIN32_WINNT >= 0x0500) && defined(WM_CHANGEUISTATE) | |
| 249 DEFINE_MESSAGE(WM_CHANGEUISTATE), | |
| 250 DEFINE_MESSAGE(WM_UPDATEUISTATE), | |
| 251 DEFINE_MESSAGE(WM_QUERYUISTATE), | |
| 252 # endif /* _WIN32_WINNT >= 0x0500 */ | |
| 253 | |
| 254 # endif | |
| 255 # endif /* WINVER >= 0x0500 */ | |
| 256 | |
| 257 DEFINE_MESSAGE(WM_CTLCOLORMSGBOX), | |
| 258 DEFINE_MESSAGE(WM_CTLCOLOREDIT), | |
| 259 DEFINE_MESSAGE(WM_CTLCOLORLISTBOX), | |
| 260 DEFINE_MESSAGE(WM_CTLCOLORBTN), | |
| 261 DEFINE_MESSAGE(WM_CTLCOLORDLG), | |
| 262 DEFINE_MESSAGE(WM_CTLCOLORSCROLLBAR), | |
| 263 DEFINE_MESSAGE(WM_CTLCOLORSTATIC), | |
| 264 # define MN_GETHMENU 0x01E1 | |
| 265 | |
| 266 DEFINE_MESSAGE(WM_MOUSEMOVE), | |
| 267 DEFINE_MESSAGE(WM_LBUTTONDOWN), | |
| 268 DEFINE_MESSAGE(WM_LBUTTONUP), | |
| 269 DEFINE_MESSAGE(WM_LBUTTONDBLCLK), | |
| 270 DEFINE_MESSAGE(WM_RBUTTONDOWN), | |
| 271 DEFINE_MESSAGE(WM_RBUTTONUP), | |
| 272 DEFINE_MESSAGE(WM_RBUTTONDBLCLK), | |
| 273 DEFINE_MESSAGE(WM_MBUTTONDOWN), | |
| 274 DEFINE_MESSAGE(WM_MBUTTONUP), | |
| 275 DEFINE_MESSAGE(WM_MBUTTONDBLCLK), | |
| 276 # if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) | |
| 277 DEFINE_MESSAGE(WM_MOUSEWHEEL), | |
| 278 # endif | |
| 279 # if (_WIN32_WINNT >= 0x0500) && defined(WM_XBUTTONDOWN) | |
| 280 DEFINE_MESSAGE(WM_XBUTTONDOWN), | |
| 281 DEFINE_MESSAGE(WM_XBUTTONUP), | |
| 282 DEFINE_MESSAGE(WM_XBUTTONDBLCLK), | |
| 283 # endif | |
| 284 # if (_WIN32_WINNT >= 0x0600) | |
| 285 DEFINE_MESSAGE(WM_MOUSEHWHEEL), | |
| 286 # endif | |
| 287 | |
| 288 | |
| 289 | |
| 290 DEFINE_MESSAGE(WM_PARENTNOTIFY), | |
| 291 DEFINE_MESSAGE(WM_ENTERMENULOOP), | |
| 292 DEFINE_MESSAGE(WM_EXITMENULOOP), | |
| 293 | |
| 294 # if(WINVER >= 0x0400) | |
| 295 DEFINE_MESSAGE(WM_NEXTMENU), | |
| 296 DEFINE_MESSAGE(WM_SIZING), | |
| 297 DEFINE_MESSAGE(WM_CAPTURECHANGED), | |
| 298 DEFINE_MESSAGE(WM_MOVING), | |
| 299 # endif /* WINVER >= 0x0400 */ | |
| 300 | |
| 301 # if(WINVER >= 0x0400) | |
| 302 DEFINE_MESSAGE(WM_POWERBROADCAST), | |
| 303 DEFINE_MESSAGE(WM_DEVICECHANGE), | |
| 304 # endif /* WINVER >= 0x0400 */ | |
| 305 | |
| 306 DEFINE_MESSAGE(WM_MDICREATE), | |
| 307 DEFINE_MESSAGE(WM_MDIDESTROY), | |
| 308 DEFINE_MESSAGE(WM_MDIACTIVATE), | |
| 309 DEFINE_MESSAGE(WM_MDIRESTORE), | |
| 310 DEFINE_MESSAGE(WM_MDINEXT), | |
| 311 DEFINE_MESSAGE(WM_MDIMAXIMIZE), | |
| 312 DEFINE_MESSAGE(WM_MDITILE), | |
| 313 DEFINE_MESSAGE(WM_MDICASCADE), | |
| 314 DEFINE_MESSAGE(WM_MDIICONARRANGE), | |
| 315 DEFINE_MESSAGE(WM_MDIGETACTIVE), | |
| 316 | |
| 317 | |
| 318 DEFINE_MESSAGE(WM_MDISETMENU), | |
| 319 DEFINE_MESSAGE(WM_ENTERSIZEMOVE), | |
| 320 DEFINE_MESSAGE(WM_EXITSIZEMOVE), | |
| 321 DEFINE_MESSAGE(WM_DROPFILES), | |
| 322 DEFINE_MESSAGE(WM_MDIREFRESHMENU), | |
| 323 | |
| 324 # if(WINVER >= 0x0602) | |
| 325 DEFINE_MESSAGE(WM_POINTERDEVICECHANGE), | |
| 326 DEFINE_MESSAGE(WM_POINTERDEVICEINRANGE), | |
| 327 DEFINE_MESSAGE(WM_POINTERDEVICEOUTOFRANGE), | |
| 328 # endif /* WINVER >= 0x0602 */ | |
| 329 | |
| 330 # if(WINVER >= 0x0601) | |
| 331 DEFINE_MESSAGE(WM_TOUCH), | |
| 332 # endif /* WINVER >= 0x0601 */ | |
| 333 | |
| 334 # if(WINVER >= 0x0602) | |
| 335 DEFINE_MESSAGE(WM_NCPOINTERUPDATE), | |
| 336 DEFINE_MESSAGE(WM_NCPOINTERDOWN), | |
| 337 DEFINE_MESSAGE(WM_NCPOINTERUP), | |
| 338 DEFINE_MESSAGE(WM_POINTERUPDATE), | |
| 339 DEFINE_MESSAGE(WM_POINTERDOWN), | |
| 340 DEFINE_MESSAGE(WM_POINTERUP), | |
| 341 DEFINE_MESSAGE(WM_POINTERENTER), | |
| 342 DEFINE_MESSAGE(WM_POINTERLEAVE), | |
| 343 DEFINE_MESSAGE(WM_POINTERACTIVATE), | |
| 344 DEFINE_MESSAGE(WM_POINTERCAPTURECHANGED), | |
| 345 DEFINE_MESSAGE(WM_TOUCHHITTESTING), | |
| 346 DEFINE_MESSAGE(WM_POINTERWHEEL), | |
| 347 DEFINE_MESSAGE(WM_POINTERHWHEEL), | |
| 348 # endif /* WINVER >= 0x0602 */ | |
| 349 | |
| 350 | |
| 351 # if(WINVER >= 0x0400) | |
| 352 DEFINE_MESSAGE(WM_IME_SETCONTEXT), | |
| 353 DEFINE_MESSAGE(WM_IME_NOTIFY), | |
| 354 DEFINE_MESSAGE(WM_IME_CONTROL), | |
| 355 DEFINE_MESSAGE(WM_IME_COMPOSITIONFULL), | |
| 356 DEFINE_MESSAGE(WM_IME_SELECT), | |
| 357 DEFINE_MESSAGE(WM_IME_CHAR), | |
| 358 # endif /* WINVER >= 0x0400 */ | |
| 359 # if(WINVER >= 0x0500) | |
| 360 DEFINE_MESSAGE(WM_IME_REQUEST), | |
| 361 # endif /* WINVER >= 0x0500 */ | |
| 362 # if(WINVER >= 0x0400) | |
| 363 DEFINE_MESSAGE(WM_IME_KEYDOWN), | |
| 364 DEFINE_MESSAGE(WM_IME_KEYUP), | |
| 365 # endif /* WINVER >= 0x0400 */ | |
| 366 | |
| 367 # if((_WIN32_WINNT >= 0x0400) || (WINVER >= 0x0500)) | |
| 368 DEFINE_MESSAGE(WM_MOUSEHOVER), | |
| 369 DEFINE_MESSAGE(WM_MOUSELEAVE), | |
| 370 # endif | |
| 371 # if(WINVER >= 0x0500) && defined(WM_NCMOUSEHOVER) | |
| 372 DEFINE_MESSAGE(WM_NCMOUSEHOVER), | |
| 373 DEFINE_MESSAGE(WM_NCMOUSELEAVE), | |
| 374 # endif /* WINVER >= 0x0500 */ | |
| 375 | |
| 376 # if(_WIN32_WINNT >= 0x0501) | |
| 377 DEFINE_MESSAGE(WM_WTSSESSION_CHANGE), | |
| 378 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 379 | |
| 380 DEFINE_MESSAGE(WM_CUT), | |
| 381 DEFINE_MESSAGE(WM_COPY), | |
| 382 DEFINE_MESSAGE(WM_PASTE), | |
| 383 DEFINE_MESSAGE(WM_CLEAR), | |
| 384 DEFINE_MESSAGE(WM_UNDO), | |
| 385 DEFINE_MESSAGE(WM_RENDERFORMAT), | |
| 386 DEFINE_MESSAGE(WM_RENDERALLFORMATS), | |
| 387 DEFINE_MESSAGE(WM_DESTROYCLIPBOARD), | |
| 388 DEFINE_MESSAGE(WM_DRAWCLIPBOARD), | |
| 389 DEFINE_MESSAGE(WM_PAINTCLIPBOARD), | |
| 390 DEFINE_MESSAGE(WM_VSCROLLCLIPBOARD), | |
| 391 DEFINE_MESSAGE(WM_SIZECLIPBOARD), | |
| 392 DEFINE_MESSAGE(WM_ASKCBFORMATNAME), | |
| 393 DEFINE_MESSAGE(WM_CHANGECBCHAIN), | |
| 394 DEFINE_MESSAGE(WM_HSCROLLCLIPBOARD), | |
| 395 DEFINE_MESSAGE(WM_QUERYNEWPALETTE), | |
| 396 DEFINE_MESSAGE(WM_PALETTEISCHANGING), | |
| 397 DEFINE_MESSAGE(WM_PALETTECHANGED), | |
| 398 DEFINE_MESSAGE(WM_HOTKEY), | |
| 399 | |
| 400 # if(WINVER >= 0x0400) | |
| 401 DEFINE_MESSAGE(WM_PRINT), | |
| 402 DEFINE_MESSAGE(WM_PRINTCLIENT), | |
| 403 # endif /* WINVER >= 0x0400 */ | |
| 404 | |
| 405 # if(_WIN32_WINNT >= 0x0500) && defined(WM_APPCOMMAND) | |
| 406 DEFINE_MESSAGE(WM_APPCOMMAND), | |
| 407 # endif /* _WIN32_WINNT >= 0x0500 */ | |
| 408 | |
| 409 # if(_WIN32_WINNT >= 0x0501) | |
| 410 DEFINE_MESSAGE(WM_THEMECHANGED), | |
| 411 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 412 | |
| 413 | |
| 414 # if(_WIN32_WINNT >= 0x0501) | |
| 415 DEFINE_MESSAGE(WM_CLIPBOARDUPDATE), | |
| 416 # endif /* _WIN32_WINNT >= 0x0501 */ | |
| 417 | |
| 418 # if(_WIN32_WINNT >= 0x0600) | |
| 419 DEFINE_MESSAGE(WM_DWMCOMPOSITIONCHANGED), | |
| 420 DEFINE_MESSAGE(WM_DWMNCRENDERINGCHANGED), | |
| 421 DEFINE_MESSAGE(WM_DWMCOLORIZATIONCOLORCHANGED), | |
| 422 DEFINE_MESSAGE(WM_DWMWINDOWMAXIMIZEDCHANGE), | |
| 423 # endif /* _WIN32_WINNT >= 0x0600 */ | |
| 424 | |
| 425 # if(_WIN32_WINNT >= 0x0601) | |
| 426 DEFINE_MESSAGE(WM_DWMSENDICONICTHUMBNAIL), | |
| 427 DEFINE_MESSAGE(WM_DWMSENDICONICLIVEPREVIEWBITMAP), | |
| 428 # endif /* _WIN32_WINNT >= 0x0601 */ | |
| 429 | |
| 430 | |
| 431 # if(WINVER >= 0x0600) | |
| 432 DEFINE_MESSAGE(WM_GETTITLEBARINFOEX), | |
| 433 # endif /* WINVER >= 0x0600 */ | |
| 434 { 0, NULL, } /* end of message list */ | |
| 435 }; | |
| 436 #undef DEFINE_MESSAGE | |
| 437 | |
| 438 char* WMMsg2Str(DWORD dwMessage) | |
| 439 { | |
| 440 struct WM_MESSAGE_MAP* pMapMsg = allMessages; | |
| 441 for (/*null*/; pMapMsg->lpszMsg != NULL; pMapMsg++) | |
| 442 { | |
| 443 if (pMapMsg->nMsg == dwMessage ) | |
| 444 { | |
| 445 return (char *)pMapMsg->lpszMsg; | |
| 446 } | |
| 447 } | |
| 448 return ""; | |
| 449 } | |
| 450 #endif /* _DEBUG */ | |
| 451 | |
| 452 | |
| 453 /* Get system time, taking special precautions against 32bit timer wrap. | |
| 454 We use timeGetTime and not GetTickCount because of its better stability, | |
| 455 and because we can increase its granularity (to 1 ms in | |
| 456 fgPlatformInitialize). For that reason we can't use GetTickCount64 which | |
| 457 wouldn't have the wrap issue. | |
| 458 Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html) | |
| 459 */ | |
| 460 static fg_time_t lastTime32 = 0; | |
| 461 static fg_time_t timeEpoch = 0; | |
| 462 void fgPlatformInitSystemTime() | |
| 463 { | |
| 464 #if defined(_WIN32_WCE) | |
| 465 lastTime32 = GetTickCount(); | |
| 466 #else | |
| 467 lastTime32 = timeGetTime(); | |
| 468 #endif | |
| 469 } | |
| 470 fg_time_t fgPlatformSystemTime ( void ) | |
| 471 { | |
| 472 fg_time_t currTime32; | |
| 473 #if defined(_WIN32_WCE) | |
| 474 currTime32 = GetTickCount(); | |
| 475 #else | |
| 476 currTime32 = timeGetTime(); | |
| 477 #endif | |
| 478 /* Check if we just wrapped */ | |
| 479 if (currTime32 < lastTime32) | |
| 480 timeEpoch++; | |
| 481 | |
| 482 lastTime32 = currTime32; | |
| 483 | |
| 484 return currTime32 | timeEpoch << 32; | |
| 485 } | |
| 486 | |
| 487 extern char *fgClipboardBuffer[3]; | |
| 488 | |
| 489 void fgPlatformSetClipboard(int selection, const char *text) | |
| 490 { | |
| 491 if (selection == GLUT_PRIMARY) | |
| 492 { | |
| 493 free(fgClipboardBuffer[GLUT_PRIMARY]); | |
| 494 fgClipboardBuffer[GLUT_PRIMARY] = strdup(text); | |
| 495 } | |
| 496 else if (selection == GLUT_SECONDARY) | |
| 497 { | |
| 498 free(fgClipboardBuffer[GLUT_SECONDARY]); | |
| 499 fgClipboardBuffer[GLUT_SECONDARY] = strdup(text); | |
| 500 } | |
| 501 else if (selection == GLUT_CLIPBOARD && text) | |
| 502 { | |
| 503 int n = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); | |
| 504 if (n > 0) | |
| 505 { | |
| 506 HANDLE object = GlobalAlloc(0, n * sizeof(WCHAR)); | |
| 507 if (object) | |
| 508 { | |
| 509 WCHAR *wtext = GlobalLock(object); | |
| 510 if (wtext) | |
| 511 { | |
| 512 MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, n); | |
| 513 GlobalUnlock(object); | |
| 514 if (OpenClipboard(NULL)) | |
| 515 { | |
| 516 EmptyClipboard(); | |
| 517 SetClipboardData(CF_UNICODETEXT, object); | |
| 518 CloseClipboard(); | |
| 519 object = NULL; /* it is now owned by the system */ | |
| 520 } | |
| 521 } | |
| 522 GlobalFree(object); | |
| 523 } | |
| 524 } | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 const char *fgPlatformGetClipboard(int selection) | |
| 529 { | |
| 530 if (selection == GLUT_PRIMARY) | |
| 531 return fgClipboardBuffer[GLUT_PRIMARY]; | |
| 532 if (selection == GLUT_SECONDARY) | |
| 533 return fgClipboardBuffer[GLUT_SECONDARY]; | |
| 534 if (selection == GLUT_CLIPBOARD) | |
| 535 { | |
| 536 free(fgClipboardBuffer[GLUT_CLIPBOARD]); | |
| 537 fgClipboardBuffer[GLUT_CLIPBOARD] = NULL; | |
| 538 if (OpenClipboard(NULL)) | |
| 539 { | |
| 540 HANDLE object = GetClipboardData(CF_UNICODETEXT); | |
| 541 if (object) | |
| 542 { | |
| 543 WCHAR *wtext = GlobalLock(object); | |
| 544 if (wtext) | |
| 545 { | |
| 546 int n = WideCharToMultiByte(CP_UTF8, 0, wtext, -1, NULL, 0, NULL, NULL); | |
| 547 if (n > 0) | |
| 548 { | |
| 549 char *text = malloc(n); | |
| 550 fgClipboardBuffer[GLUT_CLIPBOARD] = text; | |
| 551 WideCharToMultiByte(CP_UTF8, 0, wtext, -1, text, n, NULL, NULL); | |
| 552 } | |
| 553 GlobalUnlock(object); | |
| 554 } | |
| 555 } | |
| 556 CloseClipboard(); | |
| 557 } | |
| 558 return fgClipboardBuffer[GLUT_CLIPBOARD]; | |
| 559 } | |
| 560 return NULL; | |
| 561 } | |
| 562 | |
| 563 void fgPlatformSleepForEvents( fg_time_t msec ) | |
| 564 { | |
| 565 MsgWaitForMultipleObjects( 0, NULL, FALSE, (DWORD) msec, QS_ALLINPUT ); | |
| 566 } | |
| 567 | |
| 568 | |
| 569 void fgPlatformProcessSingleEvent ( void ) | |
| 570 { | |
| 571 MSG stMsg; | |
| 572 | |
| 573 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); | |
| 574 | |
| 575 while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) | |
| 576 { | |
| 577 if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) | |
| 578 { | |
| 579 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) | |
| 580 { | |
| 581 fgDeinitialize( ); | |
| 582 exit( 0 ); | |
| 583 } | |
| 584 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) | |
| 585 fgState.ExecState = GLUT_EXEC_STATE_STOP; | |
| 586 | |
| 587 return; | |
| 588 } | |
| 589 | |
| 590 TranslateMessage( &stMsg ); | |
| 591 DispatchMessage( &stMsg ); | |
| 592 } | |
| 593 } | |
| 594 | |
| 595 | |
| 596 | |
| 597 static void fghPlatformOnWindowStatusNotify(SFG_Window *window, GLboolean visState, GLboolean forceNotify) | |
| 598 { | |
| 599 GLboolean notify = GL_FALSE; | |
| 600 SFG_Window* child; | |
| 601 | |
| 602 if (window->State.Visible != visState) | |
| 603 { | |
| 604 window->State.Visible = visState; | |
| 605 | |
| 606 /* If top level window (not a subwindow/child), and icon title text available, switch titles based on visibility state */ | |
| 607 if (!window->Parent && window->State.pWState.IconTitle) | |
| 608 { | |
| 609 if (visState) | |
| 610 /* visible, set window title */ | |
| 611 SetWindowText( window->Window.Handle, window->State.pWState.WindowTitle ); | |
| 612 else | |
| 613 /* not visible, set icon title */ | |
| 614 SetWindowText( window->Window.Handle, window->State.pWState.IconTitle ); | |
| 615 } | |
| 616 | |
| 617 notify = GL_TRUE; | |
| 618 } | |
| 619 | |
| 620 if (notify || forceNotify) | |
| 621 { | |
| 622 SFG_Window *saved_window = fgStructure.CurrentWindow; | |
| 623 | |
| 624 /* On win32 we only have two states, window displayed and window not displayed (iconified) | |
| 625 * We map these to GLUT_FULLY_RETAINED and GLUT_HIDDEN respectively. | |
| 626 */ | |
| 627 INVOKE_WCB( *window, WindowStatus, ( visState ? GLUT_FULLY_RETAINED:GLUT_HIDDEN ) ); | |
| 628 fgSetWindow( saved_window ); | |
| 629 } | |
| 630 | |
| 631 /* Also set windowStatus/visibility state for children */ | |
| 632 for( child = ( SFG_Window * )window->Children.First; | |
| 633 child; | |
| 634 child = ( SFG_Window * )child->Node.Next ) | |
| 635 { | |
| 636 fghPlatformOnWindowStatusNotify(child, visState, GL_FALSE); /* No need to propagate forceNotify. Childs get this from their own INIT_WORK */ | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 void fgPlatformMainLoopPreliminaryWork ( void ) | |
| 641 { | |
| 642 /* no-op */ | |
| 643 } | |
| 644 | |
| 645 | |
| 646 /* | |
| 647 * Determine a GLUT modifier mask based on MS-WINDOWS system info. | |
| 648 */ | |
| 649 static int fgPlatformGetModifiers (void) | |
| 650 { | |
| 651 return | |
| 652 ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || | |
| 653 ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | | |
| 654 ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || | |
| 655 ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | | |
| 656 ( ( ( GetKeyState( VK_LMENU ) < 0 ) || | |
| 657 ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); | |
| 658 } | |
| 659 | |
| 660 /* Check whether a button (VK_*BUTTON) is currently depressed. Returns | |
| 661 * non-zero (not necessarily 1) if yes. */ | |
| 662 static SHORT fgGetKeyState(int vKey) | |
| 663 { | |
| 664 /* MSDN says: "If the high-order bit is 1, the key is down; otherwise, it is up". */ | |
| 665 return GetKeyState(vKey) & 0xFF00; | |
| 666 } | |
| 667 | |
| 668 static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean keydown, WPARAM wParam, LPARAM lParam) | |
| 669 { | |
| 670 static unsigned char lControl = 0, lShift = 0, lAlt = 0, | |
| 671 rControl = 0, rShift = 0, rAlt = 0; | |
| 672 | |
| 673 int keypress = -1; | |
| 674 | |
| 675 /* if keydown, check for repeat */ | |
| 676 /* If repeat is globally switched off, it cannot be switched back on per window. | |
| 677 * But if it is globally switched on, it can be switched off per window. This matches | |
| 678 * GLUT's behavior on X11, but not Nate Robbins' win32 GLUT, as he didn't implement the | |
| 679 * global state switch. | |
| 680 */ | |
| 681 if( keydown && ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) | |
| 682 return 1; | |
| 683 | |
| 684 /* Remember the current modifiers state so user can query it from their callback */ | |
| 685 fgState.Modifiers = fgPlatformGetModifiers( ); | |
| 686 | |
| 687 /* Convert the Win32 keystroke codes to GLUTtish way */ | |
| 688 # define FG_KEY(a,b) case a: keypress = b; break; | |
| 689 | |
| 690 switch( wParam ) | |
| 691 { | |
| 692 FG_KEY( VK_F1, GLUT_KEY_F1 ); | |
| 693 FG_KEY( VK_F2, GLUT_KEY_F2 ); | |
| 694 FG_KEY( VK_F3, GLUT_KEY_F3 ); | |
| 695 FG_KEY( VK_F4, GLUT_KEY_F4 ); | |
| 696 FG_KEY( VK_F5, GLUT_KEY_F5 ); | |
| 697 FG_KEY( VK_F6, GLUT_KEY_F6 ); | |
| 698 FG_KEY( VK_F7, GLUT_KEY_F7 ); | |
| 699 FG_KEY( VK_F8, GLUT_KEY_F8 ); | |
| 700 FG_KEY( VK_F9, GLUT_KEY_F9 ); | |
| 701 FG_KEY( VK_F10, GLUT_KEY_F10 ); | |
| 702 FG_KEY( VK_F11, GLUT_KEY_F11 ); | |
| 703 FG_KEY( VK_F12, GLUT_KEY_F12 ); | |
| 704 FG_KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); | |
| 705 FG_KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); | |
| 706 FG_KEY( VK_HOME, GLUT_KEY_HOME ); | |
| 707 FG_KEY( VK_END, GLUT_KEY_END ); | |
| 708 FG_KEY( VK_LEFT, GLUT_KEY_LEFT ); | |
| 709 FG_KEY( VK_UP, GLUT_KEY_UP ); | |
| 710 FG_KEY( VK_RIGHT, GLUT_KEY_RIGHT ); | |
| 711 FG_KEY( VK_DOWN, GLUT_KEY_DOWN ); | |
| 712 FG_KEY( VK_INSERT, GLUT_KEY_INSERT ); | |
| 713 | |
| 714 /* handle control, alt and shift. For GLUT, we want to distinguish between left and right presses. | |
| 715 * The VK_L* & VK_R* left and right Alt, Ctrl and Shift virtual keys are however only used as parameters to GetAsyncKeyState() and GetKeyState() | |
| 716 * so when we get an alt, shift or control keypress here, we manually check whether it was the left or the right | |
| 717 */ | |
| 718 #define FG_KEY_EVENT(winKey,glutKey,keyStateVar)\ | |
| 719 if (!keyStateVar && fgGetKeyState ( winKey ))\ | |
| 720 {\ | |
| 721 keypress = glutKey;\ | |
| 722 keyStateVar = 1;\ | |
| 723 }\ | |
| 724 else if (keyStateVar && !fgGetKeyState ( winKey ))\ | |
| 725 {\ | |
| 726 keypress = glutKey;\ | |
| 727 keyStateVar = 0;\ | |
| 728 } | |
| 729 case VK_CONTROL: | |
| 730 FG_KEY_EVENT(VK_LCONTROL,GLUT_KEY_CTRL_L,lControl); | |
| 731 FG_KEY_EVENT(VK_RCONTROL,GLUT_KEY_CTRL_R,rControl); | |
| 732 break; | |
| 733 case VK_SHIFT: | |
| 734 FG_KEY_EVENT(VK_LSHIFT,GLUT_KEY_SHIFT_L,lShift); | |
| 735 FG_KEY_EVENT(VK_RSHIFT,GLUT_KEY_SHIFT_R,rShift); | |
| 736 break; | |
| 737 case VK_MENU: | |
| 738 FG_KEY_EVENT(VK_LMENU,GLUT_KEY_ALT_L,lAlt); | |
| 739 FG_KEY_EVENT(VK_RMENU,GLUT_KEY_ALT_R,rAlt); | |
| 740 break; | |
| 741 #undef KEY_EVENT | |
| 742 | |
| 743 case VK_DELETE: | |
| 744 /* The delete key should be treated as an ASCII keypress: */ | |
| 745 if (keydown) | |
| 746 { | |
| 747 INVOKE_WCB( *window, KeyboardDown, | |
| 748 ( 127, window->State.MouseX, window->State.MouseY ) | |
| 749 ); | |
| 750 INVOKE_WCB( *window, KeyboardExt, | |
| 751 ( 127, window->State.MouseX, window->State.MouseY ) | |
| 752 ); | |
| 753 INVOKE_WCB( *window, Keyboard, | |
| 754 ( 127, window->State.MouseX, window->State.MouseY ) | |
| 755 ); | |
| 756 } | |
| 757 else | |
| 758 INVOKE_WCB( *window, KeyboardUp, | |
| 759 ( 127, window->State.MouseX, window->State.MouseY ) | |
| 760 ); | |
| 761 break; | |
| 762 | |
| 763 #if !defined(_WIN32_WCE) | |
| 764 default: | |
| 765 /* Mapped characters are handled with the WM_CHAR message. Handle low-level ASCII press/release callbacks here. */ | |
| 766 { | |
| 767 UINT ascii = (UINT)MapVirtualKey((UINT)wParam, MAPVK_VK_TO_CHAR); | |
| 768 if (ascii >= 32 && ascii < 256) | |
| 769 { | |
| 770 /* Always send lowercase (unshifted) values */ | |
| 771 if (ascii >= 'A' && ascii <= 'Z') | |
| 772 ascii = ascii - 'A' + 'a'; | |
| 773 if (keydown) | |
| 774 INVOKE_WCB(*window, KeyboardDown, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) ); | |
| 775 else | |
| 776 INVOKE_WCB(*window, KeyboardUp, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) ); | |
| 777 } | |
| 778 } | |
| 779 #endif | |
| 780 } | |
| 781 | |
| 782 #if defined(_WIN32_WCE) | |
| 783 if(keydown && !(lParam & 0x40000000)) /* Prevent auto-repeat */ | |
| 784 { | |
| 785 if(wParam==(unsigned)gxKeyList.vkRight) | |
| 786 keypress = GLUT_KEY_RIGHT; | |
| 787 else if(wParam==(unsigned)gxKeyList.vkLeft) | |
| 788 keypress = GLUT_KEY_LEFT; | |
| 789 else if(wParam==(unsigned)gxKeyList.vkUp) | |
| 790 keypress = GLUT_KEY_UP; | |
| 791 else if(wParam==(unsigned)gxKeyList.vkDown) | |
| 792 keypress = GLUT_KEY_DOWN; | |
| 793 else if(wParam==(unsigned)gxKeyList.vkA) | |
| 794 keypress = GLUT_KEY_F1; | |
| 795 else if(wParam==(unsigned)gxKeyList.vkB) | |
| 796 keypress = GLUT_KEY_F2; | |
| 797 else if(wParam==(unsigned)gxKeyList.vkC) | |
| 798 keypress = GLUT_KEY_F3; | |
| 799 else if(wParam==(unsigned)gxKeyList.vkStart) | |
| 800 keypress = GLUT_KEY_F4; | |
| 801 } | |
| 802 #endif | |
| 803 | |
| 804 if( keypress != -1 ) | |
| 805 if (keydown) | |
| 806 INVOKE_WCB( *window, Special, | |
| 807 ( keypress, | |
| 808 window->State.MouseX, window->State.MouseY ) | |
| 809 ); | |
| 810 else | |
| 811 INVOKE_WCB( *window, SpecialUp, | |
| 812 ( keypress, | |
| 813 window->State.MouseX, window->State.MouseY ) | |
| 814 ); | |
| 815 | |
| 816 fgState.Modifiers = INVALID_MODIFIERS; | |
| 817 | |
| 818 /* SYSKEY events should be sent to default window proc for system to handle them */ | |
| 819 if (uMsg==WM_SYSKEYDOWN || uMsg==WM_SYSKEYUP) | |
| 820 return DefWindowProc( window->Window.Handle, uMsg, wParam, lParam ); | |
| 821 else | |
| 822 return 1; | |
| 823 } | |
| 824 | |
| 825 SFG_Window* fghWindowUnderCursor(SFG_Window *window) | |
| 826 { | |
| 827 /* Check if the current window that the mouse is over is a child window | |
| 828 * of the window the message was sent to. Some events only sent to main window, | |
| 829 * and when handling some messages, we need to make sure that we process | |
| 830 * callbacks on the child window instead. This mirrors how GLUT does things. | |
| 831 * returns either the original window or the found child. | |
| 832 */ | |
| 833 if (window && window->Children.First) /* This window has childs */ | |
| 834 { | |
| 835 HWND hwnd; | |
| 836 SFG_Window* child_window; | |
| 837 | |
| 838 /* Get mouse position at time of message */ | |
| 839 DWORD mouse_pos_dw = GetMessagePos(); | |
| 840 POINT mouse_pos; | |
| 841 mouse_pos.x = GET_X_LPARAM(mouse_pos_dw); | |
| 842 mouse_pos.y = GET_Y_LPARAM(mouse_pos_dw); | |
| 843 ScreenToClient( window->Window.Handle, &mouse_pos ); | |
| 844 | |
| 845 hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos); | |
| 846 if (hwnd && hwnd!=window->Window.Handle) /* can be NULL if mouse outside parent by the time we get here, or can be same as parent if we didn't find a child */ | |
| 847 { | |
| 848 child_window = fgWindowByHandle(hwnd); | |
| 849 if (child_window) /* Verify we got a FreeGLUT window */ | |
| 850 { | |
| 851 /* ChildWindowFromPoint only searches immediate children, so search again to see if actually in grandchild or further descendant */ | |
| 852 window = fghWindowUnderCursor(child_window); | |
| 853 } | |
| 854 } | |
| 855 } | |
| 856 | |
| 857 return window; | |
| 858 } | |
| 859 | |
| 860 /* | |
| 861 * The window procedure for handling Win32 events | |
| 862 */ | |
| 863 LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) | |
| 864 { | |
| 865 SFG_Window *window; | |
| 866 LRESULT lRet = 1; | |
| 867 static int setCaptureActive = 0; | |
| 868 | |
| 869 FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; | |
| 870 | |
| 871 window = fgWindowByHandle( hWnd ); | |
| 872 | |
| 873 if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) | |
| 874 return DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 875 | |
| 876 /* printf ( "Window %3d message %s (<%04x>) %12d %12d\n", window?window->ID:0, | |
| 877 WMMsg2Str(uMsg), uMsg, wParam, lParam ); */ | |
| 878 | |
| 879 switch( uMsg ) | |
| 880 { | |
| 881 case WM_CREATE: | |
| 882 /* The window structure is passed as the creation structure parameter... */ | |
| 883 window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); | |
| 884 FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", | |
| 885 "fgPlatformWindowProc" ); | |
| 886 | |
| 887 window->Window.Handle = hWnd; | |
| 888 window->Window.pContext.Device = GetDC( hWnd ); | |
| 889 if( window->IsMenu ) | |
| 890 { | |
| 891 unsigned int current_DisplayMode = fgState.DisplayMode; | |
| 892 fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; | |
| 893 #if !defined(_WIN32_WCE) | |
| 894 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); | |
| 895 #endif | |
| 896 fgState.DisplayMode = current_DisplayMode; | |
| 897 | |
| 898 if( fgStructure.MenuContext ) | |
| 899 wglMakeCurrent( window->Window.pContext.Device, | |
| 900 fgStructure.MenuContext->MContext | |
| 901 ); | |
| 902 else | |
| 903 { | |
| 904 fgStructure.MenuContext = | |
| 905 (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); | |
| 906 fgStructure.MenuContext->MContext = | |
| 907 wglCreateContext( window->Window.pContext.Device ); | |
| 908 } | |
| 909 | |
| 910 /* window->Window.Context = wglGetCurrentContext (); */ | |
| 911 window->Window.Context = wglCreateContext( window->Window.pContext.Device ); | |
| 912 } | |
| 913 else | |
| 914 { | |
| 915 #if !defined(_WIN32_WCE) | |
| 916 fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); | |
| 917 #endif | |
| 918 | |
| 919 if( ! fgState.UseCurrentContext ) | |
| 920 window->Window.Context = | |
| 921 wglCreateContext( window->Window.pContext.Device ); | |
| 922 else | |
| 923 { | |
| 924 window->Window.Context = wglGetCurrentContext( ); | |
| 925 if( ! window->Window.Context ) | |
| 926 window->Window.Context = | |
| 927 wglCreateContext( window->Window.pContext.Device ); | |
| 928 } | |
| 929 | |
| 930 #if !defined(_WIN32_WCE) | |
| 931 fgNewWGLCreateContext( window ); | |
| 932 #endif | |
| 933 } | |
| 934 | |
| 935 ReleaseDC( window->Window.Handle, window->Window.pContext.Device ); | |
| 936 | |
| 937 #if defined(_WIN32_WCE) | |
| 938 /* Take over button handling */ | |
| 939 { | |
| 940 HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); | |
| 941 if (dxDllLib) | |
| 942 { | |
| 943 GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); | |
| 944 GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); | |
| 945 } | |
| 946 | |
| 947 if(GXOpenInput_) | |
| 948 (*GXOpenInput_)(); | |
| 949 if(GXGetDefaultKeys_) | |
| 950 gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); | |
| 951 } | |
| 952 | |
| 953 #endif /* defined(_WIN32_WCE) */ | |
| 954 break; | |
| 955 | |
| 956 case WM_SIZE: | |
| 957 /* printf("WM_SIZE (ID: %i): wParam: %i, new size: %ix%i \n",window->ID,wParam,LOWORD(lParam),HIWORD(lParam)); */ | |
| 958 | |
| 959 /* Update visibility state of the window */ | |
| 960 if (wParam==SIZE_MINIMIZED) | |
| 961 fghPlatformOnWindowStatusNotify(window,GL_FALSE,GL_FALSE); | |
| 962 else if (wParam==SIZE_RESTORED && !window->State.Visible) | |
| 963 fghPlatformOnWindowStatusNotify(window,GL_TRUE,GL_FALSE); | |
| 964 | |
| 965 /* Check window visible, we don't want do anything when we get a WM_SIZE because the user or glutIconifyWindow minimized the window */ | |
| 966 if( window->State.Visible ) | |
| 967 { | |
| 968 int width, height; | |
| 969 #if defined(_WIN32_WCE) | |
| 970 width = HIWORD(lParam); | |
| 971 height = LOWORD(lParam); | |
| 972 #else | |
| 973 width = LOWORD(lParam); | |
| 974 height = HIWORD(lParam); | |
| 975 #endif /* defined(_WIN32_WCE) */ | |
| 976 | |
| 977 /* Update state and call callback, if there was a change */ | |
| 978 fghOnReshapeNotify(window, width, height, GL_FALSE); | |
| 979 } | |
| 980 | |
| 981 /* according to docs, should return 0 */ | |
| 982 lRet = 0; | |
| 983 break; | |
| 984 | |
| 985 case WM_SIZING: | |
| 986 { | |
| 987 /* User resize-dragging the window, call reshape callback and | |
| 988 * force redisplay so display keeps running during dragging. | |
| 989 * Screen still wont update when not moving the cursor though... | |
| 990 */ | |
| 991 RECT rect; | |
| 992 /* PRECT prect = (PRECT) lParam; | |
| 993 printf("WM_SIZING: nc-area: %i,%i\n",prect->right-prect->left,prect->bottom-prect->top); */ | |
| 994 /* Get client area, the rect in lParam is including non-client area. */ | |
| 995 fghGetClientArea(&rect,window,FALSE); | |
| 996 | |
| 997 /* We'll get a WM_SIZE as well, but as state has | |
| 998 * already been updated here, the fghOnReshapeNotify | |
| 999 * in the handler for that message doesn't do anything. | |
| 1000 */ | |
| 1001 fghOnReshapeNotify(window, rect.right-rect.left, rect.bottom-rect.top, GL_FALSE); | |
| 1002 | |
| 1003 /* Now directly call the drawing function to update | |
| 1004 * window and window's childs. | |
| 1005 * This mimics the WM_PAINT messages that are received during | |
| 1006 * resizing. Note that we don't have a WM_MOVING handler | |
| 1007 * as move-dragging doesn't generate WM_MOVE or WM_PAINT | |
| 1008 * messages until the mouse is released. | |
| 1009 */ | |
| 1010 fghRedrawWindowAndChildren(window); | |
| 1011 } | |
| 1012 | |
| 1013 /* according to docs, should return TRUE */ | |
| 1014 lRet = TRUE; | |
| 1015 break; | |
| 1016 | |
| 1017 case WM_MOVE: | |
| 1018 { | |
| 1019 /* Check window is minimized, we don't want to call the position callback when the user or glutIconifyWindow minimized the window */ | |
| 1020 if (!IsIconic(window->Window.Handle)) | |
| 1021 { | |
| 1022 RECT windowRect; | |
| 1023 | |
| 1024 /* lParam contains coordinates of top-left of client area. | |
| 1025 * Get top-left of non-client area of window, matching coordinates of | |
| 1026 * glutInitPosition and glutPositionWindow, but not those of | |
| 1027 * glutGet(GLUT_WINDOW_X) and glutGet(GLUT_WINDOW_Y), which return | |
| 1028 * top-left of client area. | |
| 1029 */ | |
| 1030 GetWindowRect( window->Window.Handle, &windowRect ); | |
| 1031 | |
| 1032 if (window->Parent) | |
| 1033 { | |
| 1034 /* For child window, we should return relative to upper-left | |
| 1035 * of parent's client area. | |
| 1036 */ | |
| 1037 POINT topleft; | |
| 1038 topleft.x = windowRect.left; | |
| 1039 topleft.y = windowRect.top; | |
| 1040 | |
| 1041 ScreenToClient(window->Parent->Window.Handle,&topleft); | |
| 1042 windowRect.left = topleft.x; | |
| 1043 windowRect.top = topleft.y; | |
| 1044 } | |
| 1045 | |
| 1046 /* Update state and call callback, if there was a change */ | |
| 1047 fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_FALSE); | |
| 1048 } | |
| 1049 } | |
| 1050 | |
| 1051 /* according to docs, should return 0 */ | |
| 1052 lRet = 0; | |
| 1053 break; | |
| 1054 | |
| 1055 case WM_SETFOCUS: | |
| 1056 /*printf("WM_SETFOCUS: %p\n", window );*/ | |
| 1057 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1058 | |
| 1059 SetActiveWindow( window->Window.Handle ); | |
| 1060 UpdateWindow ( hWnd ); | |
| 1061 | |
| 1062 break; | |
| 1063 | |
| 1064 case WM_KILLFOCUS: | |
| 1065 /*printf("WM_KILLFOCUS: %p\n", window ); */ | |
| 1066 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1067 | |
| 1068 /* Check if there are any open menus that need to be closed */ | |
| 1069 fgPlatformCheckMenuDeactivate((HWND)wParam); | |
| 1070 break; | |
| 1071 | |
| 1072 case WM_MOUSEACTIVATE: | |
| 1073 /* Clicks should not activate the menu. | |
| 1074 * Especially important when clicking on a menu's submenu item which has no effect. | |
| 1075 */ | |
| 1076 /*printf("WM_MOUSEACTIVATE\n");*/ | |
| 1077 if (window->IsMenu) | |
| 1078 lRet = MA_NOACTIVATEANDEAT; | |
| 1079 else | |
| 1080 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1081 break; | |
| 1082 | |
| 1083 case WM_NCLBUTTONDOWN: | |
| 1084 case WM_NCMBUTTONDOWN: | |
| 1085 case WM_NCRBUTTONDOWN: | |
| 1086 { | |
| 1087 SFG_Menu *menu; | |
| 1088 if (fgState.ActiveMenus && (menu = fgGetActiveMenu())) | |
| 1089 /* user clicked non-client area of window while a menu is open. Close menu */ | |
| 1090 fgDeactivateMenu(menu->ParentWindow); | |
| 1091 | |
| 1092 /* and always pass to DefWindowProc */ | |
| 1093 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1094 } | |
| 1095 break; | |
| 1096 | |
| 1097 #if 0 | |
| 1098 case WM_ACTIVATE: | |
| 1099 /* printf("WM_ACTIVATE: %x (ID: %i) %d %d\n",lParam, window->ID, HIWORD(wParam), LOWORD(wParam)); */ | |
| 1100 if (LOWORD(wParam) != WA_INACTIVE) | |
| 1101 { | |
| 1102 /* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, | |
| 1103 window->State.Cursor ); */ | |
| 1104 fgSetCursor( window, window->State.Cursor ); | |
| 1105 } | |
| 1106 | |
| 1107 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1108 break; | |
| 1109 #endif | |
| 1110 | |
| 1111 #if _MSC_VER > 1400 | |
| 1112 case WM_SETCURSOR: | |
| 1113 /* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ | |
| 1114 if( LOWORD( lParam ) == HTCLIENT ) | |
| 1115 { | |
| 1116 if (!window->State.pWState.MouseTracking) | |
| 1117 { | |
| 1118 TRACKMOUSEEVENT tme; | |
| 1119 | |
| 1120 /* Cursor just entered window, set cursor look */ | |
| 1121 fgSetCursor ( window, window->State.Cursor ) ; | |
| 1122 | |
| 1123 /* If an EntryFunc callback is specified by the user, also | |
| 1124 * invoke that callback and start mouse tracking so that | |
| 1125 * we get a WM_MOUSELEAVE message | |
| 1126 */ | |
| 1127 if (FETCH_WCB( *window, Entry )) | |
| 1128 { | |
| 1129 SFG_Window* saved_window = fgStructure.CurrentWindow; | |
| 1130 INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); | |
| 1131 fgSetWindow(saved_window); | |
| 1132 | |
| 1133 tme.cbSize = sizeof(TRACKMOUSEEVENT); | |
| 1134 tme.dwFlags = TME_LEAVE; | |
| 1135 tme.hwndTrack = window->Window.Handle; | |
| 1136 TrackMouseEvent(&tme); | |
| 1137 | |
| 1138 window->State.pWState.MouseTracking = TRUE; | |
| 1139 } | |
| 1140 } | |
| 1141 } | |
| 1142 else | |
| 1143 /* Only pass non-client WM_SETCURSOR to DefWindowProc, or we get WM_SETCURSOR on parents of children as well */ | |
| 1144 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1145 break; | |
| 1146 #endif | |
| 1147 | |
| 1148 case WM_MOUSELEAVE: | |
| 1149 { | |
| 1150 /* NB: This message is only received when a EntryFunc callback | |
| 1151 * is specified by the user, as that is the only condition under | |
| 1152 * which mouse tracking is setup in WM_SETCURSOR handler above | |
| 1153 */ | |
| 1154 SFG_Window* saved_window = fgStructure.CurrentWindow; | |
| 1155 INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); | |
| 1156 fgSetWindow(saved_window); | |
| 1157 | |
| 1158 window->State.pWState.MouseTracking = FALSE; | |
| 1159 lRet = 0; /* As per docs, must return zero */ | |
| 1160 } | |
| 1161 break; | |
| 1162 | |
| 1163 case WM_SHOWWINDOW: | |
| 1164 /* printf("WM_SHOWWINDOW, shown? %i, source: %i\n",wParam,lParam); */ | |
| 1165 if (wParam) | |
| 1166 { | |
| 1167 fghPlatformOnWindowStatusNotify(window, GL_TRUE, GL_FALSE); | |
| 1168 window->State.WorkMask |= GLUT_DISPLAY_WORK; | |
| 1169 } | |
| 1170 else | |
| 1171 { | |
| 1172 fghPlatformOnWindowStatusNotify(window, GL_FALSE, GL_FALSE); | |
| 1173 window->State.WorkMask &= ~GLUT_DISPLAY_WORK; | |
| 1174 } | |
| 1175 break; | |
| 1176 | |
| 1177 case WM_PAINT: | |
| 1178 { | |
| 1179 RECT rect; | |
| 1180 | |
| 1181 /* As per docs, upon receiving WM_PAINT, first check if the update region is not empty before you call BeginPaint */ | |
| 1182 if (GetUpdateRect(hWnd,&rect,FALSE)) | |
| 1183 { | |
| 1184 /* Dummy begin/end paint to validate rect that needs | |
| 1185 * redrawing, then signal that a redisplay is needed. | |
| 1186 * This allows us full control about when we do any | |
| 1187 * redrawing, and is the same as what original GLUT | |
| 1188 * does. | |
| 1189 */ | |
| 1190 PAINTSTRUCT ps; | |
| 1191 BeginPaint( hWnd, &ps ); | |
| 1192 EndPaint( hWnd, &ps ); | |
| 1193 | |
| 1194 window->State.WorkMask |= GLUT_DISPLAY_WORK; | |
| 1195 } | |
| 1196 lRet = 0; /* As per docs, should return 0 */ | |
| 1197 } | |
| 1198 break; | |
| 1199 | |
| 1200 case WM_CLOSE: | |
| 1201 fgDestroyWindow ( window ); | |
| 1202 if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) | |
| 1203 PostQuitMessage(0); | |
| 1204 break; | |
| 1205 | |
| 1206 case WM_DESTROY: | |
| 1207 /* | |
| 1208 * The window already got destroyed, so don't bother with it. | |
| 1209 */ | |
| 1210 return 0; | |
| 1211 | |
| 1212 case WM_MOUSEMOVE: | |
| 1213 { | |
| 1214 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */ | |
| 1215 #if defined(_WIN32_WCE) | |
| 1216 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */ | |
| 1217 window->State.MouseY = LOWORD( lParam ); | |
| 1218 #else | |
| 1219 window->State.MouseX = GET_X_LPARAM( lParam ); | |
| 1220 window->State.MouseY = GET_Y_LPARAM( lParam ); | |
| 1221 #endif /* defined(_WIN32_WCE) */ | |
| 1222 /* Restrict to [-32768, 32767] to match X11 behaviour */ | |
| 1223 /* See comment in "freeglut_developer" mailing list 10/4/04 */ | |
| 1224 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; | |
| 1225 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; | |
| 1226 | |
| 1227 if ( window->ActiveMenu ) | |
| 1228 { | |
| 1229 fgUpdateMenuHighlight( window->ActiveMenu ); | |
| 1230 break; | |
| 1231 } | |
| 1232 | |
| 1233 fgState.Modifiers = fgPlatformGetModifiers( ); | |
| 1234 | |
| 1235 if( ( wParam & MK_LBUTTON ) || | |
| 1236 ( wParam & MK_MBUTTON ) || | |
| 1237 ( wParam & MK_RBUTTON ) ) | |
| 1238 INVOKE_WCB( *window, Motion, ( window->State.MouseX, | |
| 1239 window->State.MouseY ) ); | |
| 1240 else | |
| 1241 INVOKE_WCB( *window, Passive, ( window->State.MouseX, | |
| 1242 window->State.MouseY ) ); | |
| 1243 | |
| 1244 fgState.Modifiers = INVALID_MODIFIERS; | |
| 1245 } | |
| 1246 break; | |
| 1247 | |
| 1248 case WM_LBUTTONDOWN: | |
| 1249 case WM_MBUTTONDOWN: | |
| 1250 case WM_RBUTTONDOWN: | |
| 1251 case WM_LBUTTONUP: | |
| 1252 case WM_MBUTTONUP: | |
| 1253 case WM_RBUTTONUP: | |
| 1254 { | |
| 1255 GLboolean pressed = GL_TRUE; | |
| 1256 int button; | |
| 1257 | |
| 1258 /* Per docs, use LOWORD/HIWORD for WinCE and GET_X_LPARAM/GET_Y_LPARAM for desktop windows */ | |
| 1259 #if defined(_WIN32_WCE) | |
| 1260 window->State.MouseX = 320-HIWORD( lParam ); /* XXX: Docs say x should be loword and y hiword? */ | |
| 1261 window->State.MouseY = LOWORD( lParam ); | |
| 1262 #else | |
| 1263 window->State.MouseX = GET_X_LPARAM( lParam ); | |
| 1264 window->State.MouseY = GET_Y_LPARAM( lParam ); | |
| 1265 #endif /* defined(_WIN32_WCE) */ | |
| 1266 | |
| 1267 /* Restrict to [-32768, 32767] to match X11 behaviour */ | |
| 1268 /* See comment in "freeglut_developer" mailing list 10/4/04 */ | |
| 1269 if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; | |
| 1270 if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; | |
| 1271 | |
| 1272 switch( uMsg ) | |
| 1273 { | |
| 1274 case WM_LBUTTONDOWN: | |
| 1275 pressed = GL_TRUE; | |
| 1276 button = GLUT_LEFT_BUTTON; | |
| 1277 break; | |
| 1278 case WM_MBUTTONDOWN: | |
| 1279 pressed = GL_TRUE; | |
| 1280 button = GLUT_MIDDLE_BUTTON; | |
| 1281 break; | |
| 1282 case WM_RBUTTONDOWN: | |
| 1283 pressed = GL_TRUE; | |
| 1284 button = GLUT_RIGHT_BUTTON; | |
| 1285 break; | |
| 1286 case WM_LBUTTONUP: | |
| 1287 pressed = GL_FALSE; | |
| 1288 button = GLUT_LEFT_BUTTON; | |
| 1289 break; | |
| 1290 case WM_MBUTTONUP: | |
| 1291 pressed = GL_FALSE; | |
| 1292 button = GLUT_MIDDLE_BUTTON; | |
| 1293 break; | |
| 1294 case WM_RBUTTONUP: | |
| 1295 pressed = GL_FALSE; | |
| 1296 button = GLUT_RIGHT_BUTTON; | |
| 1297 break; | |
| 1298 default: | |
| 1299 pressed = GL_FALSE; | |
| 1300 button = -1; | |
| 1301 break; | |
| 1302 } | |
| 1303 | |
| 1304 #if !defined(_WIN32_WCE) | |
| 1305 if( GetSystemMetrics( SM_SWAPBUTTON ) ) | |
| 1306 { | |
| 1307 if( button == GLUT_LEFT_BUTTON ) | |
| 1308 button = GLUT_RIGHT_BUTTON; | |
| 1309 else | |
| 1310 if( button == GLUT_RIGHT_BUTTON ) | |
| 1311 button = GLUT_LEFT_BUTTON; | |
| 1312 } | |
| 1313 #endif /* !defined(_WIN32_WCE) */ | |
| 1314 | |
| 1315 if( button == -1 ) | |
| 1316 return DefWindowProc( hWnd, uMsg, lParam, wParam ); | |
| 1317 | |
| 1318 /* | |
| 1319 * Do not execute the application's mouse callback if a menu | |
| 1320 * is hooked to this button. In that case an appropriate | |
| 1321 * private call should be generated. | |
| 1322 */ | |
| 1323 if( fgCheckActiveMenu( window, button, pressed, | |
| 1324 window->State.MouseX, window->State.MouseY ) ) | |
| 1325 break; | |
| 1326 | |
| 1327 /* Set capture so that the window captures all the mouse messages | |
| 1328 * | |
| 1329 * The mouse is not released from the window until all buttons have | |
| 1330 * been released, even if the user presses a button in another window. | |
| 1331 * This is consistent with the behavior on X11. | |
| 1332 */ | |
| 1333 if ( pressed == GL_TRUE ) | |
| 1334 { | |
| 1335 if (!setCaptureActive) | |
| 1336 SetCapture ( window->Window.Handle ) ; | |
| 1337 setCaptureActive = 1; /* Set to false in WM_CAPTURECHANGED handler */ | |
| 1338 } | |
| 1339 else if (!fgGetKeyState(VK_LBUTTON) && !fgGetKeyState(VK_MBUTTON) && !fgGetKeyState(VK_RBUTTON)) | |
| 1340 /* Make sure all mouse buttons are released before releasing capture */ | |
| 1341 ReleaseCapture () ; | |
| 1342 | |
| 1343 if( ! FETCH_WCB( *window, Mouse ) ) | |
| 1344 break; | |
| 1345 | |
| 1346 fgSetWindow( window ); | |
| 1347 fgState.Modifiers = fgPlatformGetModifiers( ); | |
| 1348 | |
| 1349 INVOKE_WCB( | |
| 1350 *window, Mouse, | |
| 1351 ( button, | |
| 1352 pressed ? GLUT_DOWN : GLUT_UP, | |
| 1353 window->State.MouseX, | |
| 1354 window->State.MouseY | |
| 1355 ) | |
| 1356 ); | |
| 1357 | |
| 1358 fgState.Modifiers = INVALID_MODIFIERS; | |
| 1359 | |
| 1360 /* As per docs, should return zero */ | |
| 1361 lRet = 0; | |
| 1362 } | |
| 1363 break; | |
| 1364 | |
| 1365 case WM_MOUSEWHEEL: | |
| 1366 { | |
| 1367 int wheel_number = 0; /* Only one scroll wheel on windows */ | |
| 1368 #if defined(_WIN32_WCE) | |
| 1369 int modkeys = LOWORD(wParam); | |
| 1370 short ticks = (short)HIWORD(wParam); | |
| 1371 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first: | |
| 1372 xPos = LOWORD(lParam); -- straight from docs, not consistent with mouse nutton and mouse motion above (which i think is wrong) | |
| 1373 yPos = HIWORD(lParam); | |
| 1374 */ | |
| 1375 #else | |
| 1376 /* int modkeys = GET_KEYSTATE_WPARAM( wParam ); */ | |
| 1377 short ticks = HIWORD( wParam ); | |
| 1378 /* commented out as should not be needed here, mouse motion is processed in WM_MOUSEMOVE first: | |
| 1379 window->State.MouseX = GET_X_LPARAM( lParam ); | |
| 1380 window->State.MouseY = GET_Y_LPARAM( lParam ); | |
| 1381 */ | |
| 1382 #endif /* defined(_WIN32_WCE) */ | |
| 1383 | |
| 1384 window = fghWindowUnderCursor(window); | |
| 1385 | |
| 1386 fgState.MouseWheelTicks += ticks; | |
| 1387 if ( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) | |
| 1388 { | |
| 1389 int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; | |
| 1390 | |
| 1391 if( ! FETCH_WCB( *window, MouseWheel ) && | |
| 1392 ! FETCH_WCB( *window, Mouse ) ) | |
| 1393 break; | |
| 1394 | |
| 1395 fgSetWindow( window ); | |
| 1396 fgState.Modifiers = fgPlatformGetModifiers( ); | |
| 1397 | |
| 1398 while( abs ( fgState.MouseWheelTicks ) >= WHEEL_DELTA ) | |
| 1399 { | |
| 1400 if( FETCH_WCB( *window, MouseWheel ) ) | |
| 1401 INVOKE_WCB( *window, MouseWheel, | |
| 1402 ( wheel_number, | |
| 1403 direction, | |
| 1404 window->State.MouseX, | |
| 1405 window->State.MouseY | |
| 1406 ) | |
| 1407 ); | |
| 1408 else /* No mouse wheel, call the mouse button callback twice */ | |
| 1409 { | |
| 1410 /* | |
| 1411 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 | |
| 1412 * " " one +1 to 5, -1 to 6, ... | |
| 1413 * | |
| 1414 * XXX The below assumes that you have no more than 3 mouse | |
| 1415 * XXX buttons. Sorry. | |
| 1416 */ | |
| 1417 int button = wheel_number * 2 + 3; | |
| 1418 if( direction < 0 ) | |
| 1419 ++button; | |
| 1420 INVOKE_WCB( *window, Mouse, | |
| 1421 ( button, GLUT_DOWN, | |
| 1422 window->State.MouseX, window->State.MouseY ) | |
| 1423 ); | |
| 1424 INVOKE_WCB( *window, Mouse, | |
| 1425 ( button, GLUT_UP, | |
| 1426 window->State.MouseX, window->State.MouseY ) | |
| 1427 ); | |
| 1428 } | |
| 1429 | |
| 1430 fgState.MouseWheelTicks -= WHEEL_DELTA * direction; | |
| 1431 } | |
| 1432 | |
| 1433 fgState.Modifiers = INVALID_MODIFIERS; | |
| 1434 } | |
| 1435 /* Per docs, should return zero */ | |
| 1436 lRet = 0; | |
| 1437 } | |
| 1438 break ; | |
| 1439 | |
| 1440 case WM_SYSKEYDOWN: | |
| 1441 case WM_KEYDOWN: | |
| 1442 { | |
| 1443 window = fghWindowUnderCursor(window); | |
| 1444 lRet = fghWindowProcKeyPress(window,uMsg,GL_TRUE,wParam,lParam); | |
| 1445 } | |
| 1446 break; | |
| 1447 | |
| 1448 case WM_SYSKEYUP: | |
| 1449 case WM_KEYUP: | |
| 1450 { | |
| 1451 window = fghWindowUnderCursor(window); | |
| 1452 lRet = fghWindowProcKeyPress(window,uMsg,GL_FALSE,wParam,lParam); | |
| 1453 } | |
| 1454 break; | |
| 1455 | |
| 1456 case WM_SYSCHAR: | |
| 1457 case WM_CHAR: | |
| 1458 { | |
| 1459 window = fghWindowUnderCursor(window); | |
| 1460 | |
| 1461 if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) | |
| 1462 break; | |
| 1463 | |
| 1464 fgState.Modifiers = fgPlatformGetModifiers( ); | |
| 1465 INVOKE_WCB( *window, KeyboardExt, | |
| 1466 ( (int)wParam, window->State.MouseX, window->State.MouseY ) | |
| 1467 ); | |
| 1468 if (wParam < 256) | |
| 1469 INVOKE_WCB( *window, Keyboard, | |
| 1470 ( (unsigned char)wParam, window->State.MouseX, window->State.MouseY ) | |
| 1471 ); | |
| 1472 fgState.Modifiers = INVALID_MODIFIERS; | |
| 1473 } | |
| 1474 break; | |
| 1475 | |
| 1476 case WM_CAPTURECHANGED: | |
| 1477 if (!lParam || !fgWindowByHandle((HWND)lParam)) | |
| 1478 /* Capture released or capture taken by non-FreeGLUT window */ | |
| 1479 setCaptureActive = 0; | |
| 1480 /* Docs advise a redraw */ | |
| 1481 InvalidateRect( hWnd, NULL, GL_FALSE ); | |
| 1482 UpdateWindow(hWnd); | |
| 1483 lRet = 0; /* Per docs, should return zero */ | |
| 1484 break; | |
| 1485 | |
| 1486 #if !defined(_WIN32_WCE) | |
| 1487 case WM_SYNCPAINT: /* 0x0088 */ | |
| 1488 /* Another window has moved, need to update this one */ | |
| 1489 window->State.WorkMask |= GLUT_DISPLAY_WORK; | |
| 1490 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1491 /* Help screen says this message must be passed to "DefWindowProc" */ | |
| 1492 break; | |
| 1493 | |
| 1494 case WM_DISPLAYCHANGE: /* 0x007E */ | |
| 1495 /* The system display resolution/depth has changed */ | |
| 1496 fgDisplay.ScreenWidth = LOWORD(lParam); | |
| 1497 fgDisplay.ScreenHeight = HIWORD(lParam); | |
| 1498 break; | |
| 1499 | |
| 1500 case WM_SYSCOMMAND : /* 0x0112 */ | |
| 1501 { | |
| 1502 /* | |
| 1503 * We have received a system command message. Try to act on it. | |
| 1504 * The commands are passed in through the "wParam" parameter: | |
| 1505 * The least significant digit seems to be which edge of the window | |
| 1506 * is being used for a resize event: | |
| 1507 * 4 3 5 | |
| 1508 * 1 2 | |
| 1509 * 7 6 8 | |
| 1510 * Congratulations and thanks to Richard Rauch for figuring this out.. | |
| 1511 */ | |
| 1512 switch ( wParam & 0xfff0 ) | |
| 1513 { | |
| 1514 case SC_SIZE : | |
| 1515 break ; | |
| 1516 | |
| 1517 case SC_MOVE : | |
| 1518 break ; | |
| 1519 | |
| 1520 case SC_MINIMIZE : | |
| 1521 /* User has clicked on the "-" to minimize the window */ | |
| 1522 /* Turning off the visibility is handled in WM_SIZE handler */ | |
| 1523 | |
| 1524 break ; | |
| 1525 | |
| 1526 case SC_MAXIMIZE : | |
| 1527 break ; | |
| 1528 | |
| 1529 case SC_NEXTWINDOW : | |
| 1530 break ; | |
| 1531 | |
| 1532 case SC_PREVWINDOW : | |
| 1533 break ; | |
| 1534 | |
| 1535 case SC_CLOSE : | |
| 1536 /* Followed very closely by a WM_CLOSE message */ | |
| 1537 break ; | |
| 1538 | |
| 1539 case SC_VSCROLL : | |
| 1540 break ; | |
| 1541 | |
| 1542 case SC_HSCROLL : | |
| 1543 break ; | |
| 1544 | |
| 1545 case SC_MOUSEMENU : | |
| 1546 break ; | |
| 1547 | |
| 1548 case SC_KEYMENU : | |
| 1549 break ; | |
| 1550 | |
| 1551 case SC_ARRANGE : | |
| 1552 break ; | |
| 1553 | |
| 1554 case SC_RESTORE : | |
| 1555 break ; | |
| 1556 | |
| 1557 case SC_TASKLIST : | |
| 1558 break ; | |
| 1559 | |
| 1560 case SC_SCREENSAVE : | |
| 1561 break ; | |
| 1562 | |
| 1563 case SC_HOTKEY : | |
| 1564 break ; | |
| 1565 | |
| 1566 #if(WINVER >= 0x0400) | |
| 1567 case SC_DEFAULT : | |
| 1568 break ; | |
| 1569 | |
| 1570 case SC_MONITORPOWER : | |
| 1571 break ; | |
| 1572 | |
| 1573 case SC_CONTEXTHELP : | |
| 1574 break ; | |
| 1575 #endif /* WINVER >= 0x0400 */ | |
| 1576 | |
| 1577 default: | |
| 1578 #if _DEBUG | |
| 1579 fgWarning( "Unknown wParam type 0x%x", wParam ); | |
| 1580 #endif | |
| 1581 break; | |
| 1582 } | |
| 1583 } | |
| 1584 #endif /* !defined(_WIN32_WCE) */ | |
| 1585 | |
| 1586 /* We need to pass the message on to the operating system as well */ | |
| 1587 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1588 break; | |
| 1589 | |
| 1590 #ifdef WM_TOUCH | |
| 1591 /* handle multi-touch messages */ | |
| 1592 case WM_TOUCH: | |
| 1593 { | |
| 1594 unsigned int numInputs = (unsigned int)wParam; | |
| 1595 unsigned int i = 0; | |
| 1596 TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs); | |
| 1597 | |
| 1598 if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) { | |
| 1599 fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo"); | |
| 1600 fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle"); | |
| 1601 } | |
| 1602 | |
| 1603 if (!fghGetTouchInputInfo) { | |
| 1604 free( (void*)ti ); | |
| 1605 break; | |
| 1606 } | |
| 1607 | |
| 1608 if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) { | |
| 1609 /* Handle each contact point */ | |
| 1610 for (i = 0; i < numInputs; ++i ) { | |
| 1611 | |
| 1612 POINT tp; | |
| 1613 tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x); | |
| 1614 tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y); | |
| 1615 ScreenToClient( hWnd, &tp ); | |
| 1616 | |
| 1617 ti[i].dwID = ti[i].dwID * 2; | |
| 1618 | |
| 1619 if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { | |
| 1620 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) ); | |
| 1621 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) ); | |
| 1622 } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { | |
| 1623 INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) ); | |
| 1624 } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { | |
| 1625 INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) ); | |
| 1626 INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) ); | |
| 1627 } | |
| 1628 } | |
| 1629 } | |
| 1630 fghCloseTouchInputHandle((HTOUCHINPUT)lParam); | |
| 1631 free( (void*)ti ); | |
| 1632 lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/ | |
| 1633 break; | |
| 1634 } | |
| 1635 #endif | |
| 1636 default: | |
| 1637 /* Handle unhandled messages */ | |
| 1638 lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); | |
| 1639 break; | |
| 1640 } | |
| 1641 | |
| 1642 return lRet; | |
| 1643 } | |
| 1644 | |
| 1645 | |
| 1646 /* deal with work list items */ | |
| 1647 void fgPlatformInitWork(SFG_Window* window) | |
| 1648 { | |
| 1649 RECT windowRect; | |
| 1650 | |
| 1651 /* Notify windowStatus/visibility */ | |
| 1652 fghPlatformOnWindowStatusNotify(window, window->State.Visible, GL_TRUE); | |
| 1653 | |
| 1654 /* get and notify window's position */ | |
| 1655 GetWindowRect(window->Window.Handle,&windowRect); | |
| 1656 fghOnPositionNotify(window, windowRect.left, windowRect.top, GL_TRUE); | |
| 1657 | |
| 1658 /* get and notify window's size */ | |
| 1659 GetClientRect(window->Window.Handle,&windowRect); | |
| 1660 fghOnReshapeNotify(window, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, GL_TRUE); | |
| 1661 } | |
| 1662 | |
| 1663 /* On windows we can position, resize and change z order at the same time */ | |
| 1664 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask) | |
| 1665 { | |
| 1666 UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER; | |
| 1667 HWND insertAfter = HWND_TOP; | |
| 1668 RECT clientRect; | |
| 1669 | |
| 1670 #if !defined(_WIN32_WCE) /* FIXME: what about WinCE */ | |
| 1671 if (workMask & GLUT_FULL_SCREEN_WORK) | |
| 1672 { | |
| 1673 /* This asks us to toggle fullscreen mode */ | |
| 1674 flags |= SWP_FRAMECHANGED; | |
| 1675 | |
| 1676 if (window->State.IsFullscreen) | |
| 1677 { | |
| 1678 /* If we are fullscreen, resize the current window back to its original size */ | |
| 1679 /* printf("OldRect %i,%i to %i,%i\n",window->State.pWState.OldRect.left,window->State.pWState.OldRect.top,window->State.pWState.OldRect.right,window->State.pWState.OldRect.bottom); */ | |
| 1680 | |
| 1681 /* restore style of window before making it fullscreen */ | |
| 1682 SetWindowLong(window->Window.Handle, GWL_STYLE, window->State.pWState.OldStyle); | |
| 1683 SetWindowLong(window->Window.Handle, GWL_EXSTYLE, window->State.pWState.OldStyleEx); | |
| 1684 | |
| 1685 /* Then set up resize/reposition, unless user already queued up reshape/position work */ | |
| 1686 if (!(workMask & GLUT_POSITION_WORK)) | |
| 1687 { | |
| 1688 workMask |= GLUT_POSITION_WORK; | |
| 1689 window->State.DesiredXpos = window->State.pWState.OldRect.left; | |
| 1690 window->State.DesiredYpos = window->State.pWState.OldRect.top; | |
| 1691 } | |
| 1692 if (!(workMask & GLUT_SIZE_WORK)) | |
| 1693 { | |
| 1694 workMask |= GLUT_SIZE_WORK; | |
| 1695 window->State.DesiredWidth = window->State.pWState.OldRect.right - window->State.pWState.OldRect.left; | |
| 1696 window->State.DesiredHeight = window->State.pWState.OldRect.bottom - window->State.pWState.OldRect.top; | |
| 1697 } | |
| 1698 | |
| 1699 /* We'll finish off the fullscreen operation below after the other GLUT_POSITION_WORK|GLUT_SIZE_WORK|GLUT_ZORDER_WORK */ | |
| 1700 } | |
| 1701 else | |
| 1702 { | |
| 1703 /* we are currently not fullscreen, go to fullscreen: | |
| 1704 * remove window decoration and then maximize | |
| 1705 */ | |
| 1706 RECT rect; | |
| 1707 HMONITOR hMonitor; | |
| 1708 MONITORINFO mi; | |
| 1709 | |
| 1710 /* save current window rect, style, exstyle and maximized state */ | |
| 1711 window->State.pWState.OldMaximized = !!IsZoomed(window->Window.Handle); | |
| 1712 if (window->State.pWState.OldMaximized) | |
| 1713 /* We force the window into restored mode before going | |
| 1714 * fullscreen because Windows doesn't seem to hide the | |
| 1715 * taskbar if the window is in the maximized state. | |
| 1716 */ | |
| 1717 SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_RESTORE, 0); | |
| 1718 | |
| 1719 fghGetClientArea( &window->State.pWState.OldRect, window, GL_TRUE ); | |
| 1720 window->State.pWState.OldStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); | |
| 1721 window->State.pWState.OldStyleEx = GetWindowLong(window->Window.Handle, GWL_EXSTYLE); | |
| 1722 | |
| 1723 /* remove decorations from style */ | |
| 1724 SetWindowLong(window->Window.Handle, GWL_STYLE, | |
| 1725 window->State.pWState.OldStyle & ~(WS_CAPTION | WS_THICKFRAME)); | |
| 1726 SetWindowLong(window->Window.Handle, GWL_EXSTYLE, | |
| 1727 window->State.pWState.OldStyleEx & ~(WS_EX_DLGMODALFRAME | | |
| 1728 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); | |
| 1729 | |
| 1730 /* For fullscreen mode, find the monitor that is covered the most | |
| 1731 * by the window and get its rect as the resize target. | |
| 1732 */ | |
| 1733 hMonitor= MonitorFromWindow(window->Window.Handle, MONITOR_DEFAULTTONEAREST); | |
| 1734 mi.cbSize = sizeof(mi); | |
| 1735 GetMonitorInfo(hMonitor, &mi); | |
| 1736 rect = mi.rcMonitor; | |
| 1737 | |
| 1738 /* then setup window resize, overwriting other work queued on the window */ | |
| 1739 window->State.WorkMask |= GLUT_POSITION_WORK | GLUT_SIZE_WORK; | |
| 1740 window->State.WorkMask &= ~GLUT_ZORDER_WORK; | |
| 1741 window->State.DesiredXpos = rect.left; | |
| 1742 window->State.DesiredYpos = rect.top; | |
| 1743 window->State.DesiredWidth = rect.right - rect.left; | |
| 1744 window->State.DesiredHeight = rect.bottom - rect.top; | |
| 1745 } | |
| 1746 } | |
| 1747 #endif /*!defined(_WIN32_WCE) */ | |
| 1748 | |
| 1749 /* Now deal with normal position, reshape and z order requests (some might have been set when handling GLUT_FULLSCREEN_WORK above */ | |
| 1750 { | |
| 1751 /* get rect describing window's current position and size, | |
| 1752 * in screen coordinates and in FreeGLUT format | |
| 1753 * (size (right-left, bottom-top) is client area size, top and left | |
| 1754 * are outside of window including decorations). | |
| 1755 */ | |
| 1756 fghGetClientArea( &clientRect, window, TRUE ); | |
| 1757 | |
| 1758 if (workMask & GLUT_POSITION_WORK) | |
| 1759 { | |
| 1760 flags &= ~SWP_NOMOVE; | |
| 1761 | |
| 1762 /* Move rect so that top-left is at requested position */ | |
| 1763 /* This also automatically makes sure that child window requested coordinates are relative | |
| 1764 * to top-left of parent's client area (needed input for SetWindowPos on child windows), | |
| 1765 * so no need to further correct rect for child windows below (childs don't have decorations either). | |
| 1766 */ | |
| 1767 OffsetRect(&clientRect,window->State.DesiredXpos-clientRect.left,window->State.DesiredYpos-clientRect.top); | |
| 1768 } | |
| 1769 if (workMask & GLUT_SIZE_WORK) | |
| 1770 { | |
| 1771 flags &= ~SWP_NOSIZE; | |
| 1772 | |
| 1773 /* Note on maximizing behavior of Windows: the resize borders are off | |
| 1774 * the screen such that the client area extends all the way from the | |
| 1775 * leftmost corner to the rightmost corner to maximize screen real | |
| 1776 * estate. A caption is still shown however to allow interaction with | |
| 1777 * the window controls. This is default behavior of Windows that | |
| 1778 * FreeGLUT sticks with. To alter, one would have to check if | |
| 1779 * WS_MAXIMIZE style is set when a resize event is triggered, and | |
| 1780 * then manually correct the windowRect to put the borders back on | |
| 1781 * screen. | |
| 1782 */ | |
| 1783 | |
| 1784 /* Set new size of window, WxH specify client area */ | |
| 1785 clientRect.right = clientRect.left + window->State.DesiredWidth; | |
| 1786 clientRect.bottom = clientRect.top + window->State.DesiredHeight; | |
| 1787 } | |
| 1788 if (workMask & GLUT_ZORDER_WORK) | |
| 1789 { | |
| 1790 flags &= ~SWP_NOZORDER; | |
| 1791 | |
| 1792 /* Could change this to push it down or up one window at a time with some | |
| 1793 * more code using GetWindow with GW_HWNDPREV and GW_HWNDNEXT. | |
| 1794 * What would be consistent with X11? Win32 GLUT does what we do here... | |
| 1795 */ | |
| 1796 if (window->State.DesiredZOrder < 0) | |
| 1797 insertAfter = HWND_BOTTOM; | |
| 1798 } | |
| 1799 } | |
| 1800 | |
| 1801 /* Adjust for window decorations | |
| 1802 * Child windows don't have decoration, so no need to correct | |
| 1803 */ | |
| 1804 if (!window->Parent) | |
| 1805 /* get the window rect from this to feed to SetWindowPos, correct for window decorations */ | |
| 1806 fghComputeWindowRectFromClientArea_QueryWindow(&clientRect,window,TRUE); | |
| 1807 | |
| 1808 /* Do the requested positioning, moving, and z order push/pop. */ | |
| 1809 SetWindowPos( window->Window.Handle, | |
| 1810 insertAfter, | |
| 1811 clientRect.left, clientRect.top, | |
| 1812 clientRect.right - clientRect.left, | |
| 1813 clientRect.bottom- clientRect.top, | |
| 1814 flags | |
| 1815 ); | |
| 1816 | |
| 1817 /* Finish off the fullscreen operation we were doing, if any */ | |
| 1818 if (workMask & GLUT_FULL_SCREEN_WORK) | |
| 1819 { | |
| 1820 if (window->State.IsFullscreen) | |
| 1821 { | |
| 1822 /* leaving fullscreen, restore maximized state, if any */ | |
| 1823 if (window->State.pWState.OldMaximized) | |
| 1824 SendMessage(window->Window.Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0); | |
| 1825 | |
| 1826 window->State.IsFullscreen = GL_FALSE; | |
| 1827 } | |
| 1828 else | |
| 1829 window->State.IsFullscreen = GL_TRUE; | |
| 1830 } | |
| 1831 } | |
| 1832 | |
| 1833 | |
| 1834 void fgPlatformVisibilityWork(SFG_Window* window) | |
| 1835 { | |
| 1836 /* Visibility status of window gets updated in the WM_SHOWWINDOW and WM_SIZE handlers */ | |
| 1837 int cmdShow = 0; | |
| 1838 SFG_Window *win = window; | |
| 1839 switch (window->State.DesiredVisibility) | |
| 1840 { | |
| 1841 case DesireHiddenState: | |
| 1842 cmdShow = SW_HIDE; | |
| 1843 break; | |
| 1844 case DesireIconicState: | |
| 1845 cmdShow = SW_MINIMIZE; | |
| 1846 /* Call on top-level window */ | |
| 1847 while (win->Parent) | |
| 1848 win = win->Parent; | |
| 1849 break; | |
| 1850 case DesireNormalState: | |
| 1851 if (win->IsMenu && !fgStructure.GameModeWindow) | |
| 1852 cmdShow = SW_SHOWNA; /* Just show, don't activate window if its a menu. Only exception is when there is a gamemode window as the menu would pop under it when we do this... */ | |
| 1853 else | |
| 1854 cmdShow = SW_SHOW; | |
| 1855 break; | |
| 1856 } | |
| 1857 | |
| 1858 ShowWindow( win->Window.Handle, cmdShow ); | |
| 1859 } |
