Browse Source

make resizing, fullscreen more robust

cxgeorge 24 years ago
parent
commit
f102489a0a
2 changed files with 190 additions and 161 deletions
  1. 185 158
      panda/src/wgldisplay/wglGraphicsWindow.cxx
  2. 5 3
      panda/src/wgldisplay/wglGraphicsWindow.h

+ 185 - 158
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -22,6 +22,7 @@
 #include <keyboardButton.h>
 #include <mouseButton.h>
 #include <throw_event.h>
+#include <eventQueue.h>
 #include <glGraphicsStateGuardian.h>
 #include <errno.h>
 #include <time.h>
@@ -39,8 +40,6 @@
 ////////////////////////////////////////////////////////////////////
 TypeHandle wglGraphicsWindow::_type_handle;
 
-#define WGLWIN_CONFIGURE 0x4
-
 #define MOUSE_ENTERED 0
 #define MOUSE_EXITED 1
 
@@ -89,6 +88,19 @@ void wglGraphicsWindow::DestroyMe(bool bAtExitFnCalled) {
   // an atexit() fn.  Possible that GL has already unloaded itself.  So we just wont call them for now
   // for that case, we're exiting the app anyway.
   if(!bAtExitFnCalled) {
+      // to do gl releases, we need to have the context be current
+      if((_hdc!=NULL)&&(_context!=NULL)) {
+          // need to bypass make_current() since it checks _window_inactive which we need to ignore
+          HGLRC current_context = wglGetCurrentContext();
+          HDC current_dc = wglGetCurrentDC();
+
+          if ((current_context != _context) || (current_dc != _hdc)) {
+              if(!wglMakeCurrent(_hdc, _context)) {
+                  PrintErrorMessage(LAST_ERROR);
+              }
+          }
+          report_errors();
+      }
 
       if(gl_show_fps_meter)
         glDeleteLists(FONT_BITMAP_OGLDISPLAYLISTNUM, 128);
@@ -97,7 +109,10 @@ void wglGraphicsWindow::DestroyMe(bool bAtExitFnCalled) {
 
       // implicitly calls gsg destructors which release GL objects (textures, display lists, etc)
       release_gsg();
-    
+
+      report_errors();
+      // cant report errors after we set cur context to NULL
+
       HGLRC curcxt=wglGetCurrentContext();
       if(curcxt!=NULL) 
         unmake_current();
@@ -250,60 +265,39 @@ static DWORD GetAvailVidMem(void) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsWindow::config(void) {
+    
+    GraphicsWindow::config();
 
-  GraphicsWindow::config();
-
-  HINSTANCE hinstance = GetModuleHandle(NULL);
-  HWND hDesktopWindow = GetDesktopWindow();
-
-  global_wglwinptr = this;  // need this until we get an HWND from CreateWindow
-
-  _change_mask = 0;
-  _exiting_window = false;
-  _mouse_input_enabled = false;
-  _mouse_motion_enabled = false;
-  _mouse_passive_motion_enabled = false;
-  _mouse_entry_enabled = false;
-  _entry_state = -1;
-  _visual = NULL;
-  _context = NULL;
-  _hdc = NULL;
-  _window_inactive = false;
-  _pCurrent_display_settings = NULL;
-
-  _mwindow = NULL;
-  _gsg = NULL;
-
-  _hOldForegroundWindow=GetForegroundWindow();
-
-#if 0
-// bugbug need to add wdx handling routines
-    _WindowAdjustingType = NotAdjusting;
-    _hMouseCursor = NULL;
-    _bSizeIsMaximized=FALSE;
-#endif
+    HINSTANCE hinstance = GetModuleHandle(NULL);
+    HWND hDesktopWindow = GetDesktopWindow();
 
-#if 0
-   // for gl, do this after window creation
-    // Create a GSG to manage the graphics
-    make_gsg();
-    if(_gsg==NULL) {
-        wdxdisplay_cat.error() << "DXGSG creation failed!\n";
-        exit(1);
-    }
-    _dxgsg = DCAST(DXGraphicsStateGuardian, _gsg);
-#endif
+    global_wglwinptr = this;  // need this until we get an HWND from CreateWindow
 
+    _exiting_window = false;
+    _mouse_input_enabled = false;
+    _mouse_motion_enabled = false;
+    _mouse_passive_motion_enabled = false;
+    _mouse_entry_enabled = false;
+    _entry_state = -1;
+    _visual = NULL;
+    _context = NULL;
+    _hdc = NULL;
+    _window_inactive = false;
+    _pCurrent_display_settings = NULL;
+    _mwindow = NULL;
+    _gsg = NULL;
+    _hOldForegroundWindow=GetForegroundWindow();
+    
     WNDCLASS wc;
-
+    
     // Clear before filling in window structure!
     ZeroMemory(&wc, sizeof(WNDCLASS));
     wc.style      = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
     wc.lpfnWndProc = (WNDPROC) static_window_proc;
     wc.hInstance   = hinstance;
-
+    
     string windows_icon_filename = get_icon_filename_().to_os_specific();
-
+    
     if(!windows_icon_filename.empty()) {
         // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings)
         // if icon is more than 8bpp
@@ -311,17 +305,19 @@ void wglGraphicsWindow::config(void) {
     } else {
         wc.hIcon = NULL; // use default app icon
     }
-
+    
     wc.hCursor        = _hMouseCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
     wc.lpszMenuName   = NULL;
     wc.lpszClassName  = WGL_WINDOWCLASSNAME;
-
+    
     if(!RegisterClass(&wc)) {
         wgldisplay_cat.fatal() << "could not register window class!" << endl;
         exit(1);
     }
 
+    DWORD window_style = WS_POPUP | WS_MAXIMIZE | WS_SYSMENU;  // for CreateWindow
+
     // rect now contains the coords for the entire window, not the client
     if (_props._fullscreen) {
       DWORD dwWidth =  _props._xsize;
@@ -378,12 +374,10 @@ void wglGraphicsWindow::config(void) {
           exit(1);
       }
 
-      DWORD style = WS_POPUP | WS_MAXIMIZE;
-
       // I'd prefer to CreateWindow after DisplayChange in case it messes up GL somehow,
       // but I need the window's black background to cover up the desktop during the mode change
       _mwindow = CreateWindow(WGL_WINDOWCLASSNAME, _props._title.c_str(),
-                style,0,0,dwWidth,dwHeight,hDesktopWindow, NULL, hinstance, 0);
+                window_style,0,0,dwWidth,dwHeight,hDesktopWindow, NULL, hinstance, 0);
 
       // move window to top of zorder,
       SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
@@ -410,18 +404,15 @@ void wglGraphicsWindow::config(void) {
            wgldisplay_cat.debug() << "set fullscreen mode at res ( " << dwWidth << " X " << dwHeight << " X " << dwFullScreenBitDepth <<" ), " << dm.dmDisplayFrequency  << "Hz\n";
   } else {
         
-        DWORD style;
         RECT win_rect;
         SetRect(&win_rect, _props._xorg,  _props._yorg, _props._xorg + _props._xsize,
                 _props._yorg + _props._ysize);
 
-        style = WS_POPUP | WS_MAXIMIZE;
-
         if(_props._border) {
-            style |= WS_OVERLAPPEDWINDOW;
+            window_style |= WS_OVERLAPPEDWINDOW;
         }
 
-        BOOL bRes = AdjustWindowRect(&win_rect, style, FALSE);  //compute window size based on desired client area size
+        BOOL bRes = AdjustWindowRect(&win_rect, window_style, FALSE);  //compute window size based on desired client area size
 
         if(!bRes) {
             wgldisplay_cat.fatal() << "AdjustWindowRect failed!" << endl;
@@ -437,7 +428,7 @@ void wglGraphicsWindow::config(void) {
         }
 
         _mwindow = CreateWindow(WGL_WINDOWCLASSNAME, _props._title.c_str(),
-                                style, win_rect.left, win_rect.top, win_rect.right-win_rect.left,
+                                window_style, win_rect.left, win_rect.top, win_rect.right-win_rect.left,
                                 win_rect.bottom-win_rect.top,
                                 NULL, NULL, hinstance, 0);
   }
@@ -452,7 +443,7 @@ void wglGraphicsWindow::config(void) {
   global_wglwinptr = NULL;  // get rid of any reference to this obj
     
   // move window to top of zorder
-  SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
+  SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
     
   _hdc = GetDC(_mwindow);
 
@@ -1002,8 +993,9 @@ void wglGraphicsWindow::end_frame(void) {
     glPushMatrix();
     glLoadIdentity();
 
-    glOrtho(_props._xorg,_props._xorg+_props._xsize,
-        _props._yorg,_props._yorg+_props._ysize,-1.0,1.0);
+    glOrtho(0,_props._xsize,
+            0,_props._ysize,
+            -1.0,1.0);
 
     glRasterPos2f(_props._xsize-70,_props._ysize-20);  // these seem to be good for default font
 
@@ -1036,16 +1028,21 @@ void wglGraphicsWindow::end_frame(void) {
 //       Access:
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void wglGraphicsWindow::handle_reshape(int w, int h) {
-  // bugbug: this is not current working right??
-  if (_props._xsize != w || _props._ysize != h) {
-    _props._xsize = w;
-    _props._ysize = h;
-    make_current();
-    GdiFlush();
-    resized(w, h);
-    _change_mask |= WGLWIN_CONFIGURE;
-  }
+void wglGraphicsWindow::handle_reshape() {
+      RECT view_rect;
+      GetClientRect( _mwindow, &view_rect );
+      ClientToScreen( _mwindow, (POINT*)&view_rect.left );   // translates top,left pnt
+      ClientToScreen( _mwindow, (POINT*)&view_rect.right );  // translates right,bottom pnt
+
+      // change _props xsize,ysize
+      resized((view_rect.right - view_rect.left),(view_rect.bottom - view_rect.top));
+
+      _props._xorg = view_rect.left;  // _props origin should reflect upper left of view rectangle
+      _props._yorg = view_rect.top;
+
+      if(wgldisplay_cat.is_spam()) {
+          wgldisplay_cat.spam() << "reshape to origin: (" << _props._xorg << "," << _props._yorg << "), size: (" << _props._xsize << "," << _props._ysize << ")\n";
+      }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1093,34 +1090,6 @@ handle_keyrelease(ButtonHandle key) {
   }
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: handle_changes
-//       Access:
-//  Description:
-////////////////////////////////////////////////////////////////////
-void wglGraphicsWindow::handle_changes(void) {
-  // As an optimization, check to see if change is anything other than a
-  // redisplay
-  if (_change_mask & WGLWIN_CONFIGURE) {
-    RECT changes;
-    POINT point;
-    GetClientRect(_mwindow, &changes);
-    point.x = 0;
-    point.y = 0;
-    ClientToScreen(_mwindow, &point);
-    changes.left = point.x;
-    changes.top = point.y;
-    // Don't do this in full-screen mode
-    AdjustWindowRect(&changes, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |
-        WS_CLIPCHILDREN, FALSE);
-    SetWindowPos(_mwindow, HWND_TOP, changes.left, changes.top,
-        changes.right - changes.left, changes.bottom - changes.top,
-        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER |
-        SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER);
-  }
-  _change_mask = 0;
-}
-
 void INLINE wglGraphicsWindow::process_events(void) {
   MSG msg;
 
@@ -1166,14 +1135,12 @@ void wglGraphicsWindow::update(void) {
     }
 #endif
 
-  if(_change_mask)
-    handle_changes();
-
   process_events();
 
   if(_window_inactive) {
       Sleep( 500 );   // Dont consume CPU.
-      throw_event("PandaPaused");   // throw panda event to invoke network-only processing
+      if(!EventQueue::get_global_event_queue()->is_queue_full())
+          throw_event("PandaPaused");   // throw panda event to invoke network-only processing
       return;
   } else {
 
@@ -1221,7 +1188,7 @@ void wglGraphicsWindow::enable_mouse_passive_motion(bool val) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void wglGraphicsWindow::make_current(void) {
-  if((_hdc==NULL)||(_window_inactive)) {
+  if((_hdc==NULL)||(_context==NULL)||(_window_inactive)) {
       return;  // we're only allow unmake_current() to set this to NULL
   }
 
@@ -1316,6 +1283,61 @@ LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam
    }
 }
 
+void wglGraphicsWindow::deactivate_window(void) {
+    // current policy is to suspend minimized or deactivated fullscreen windows, but leave
+    // regular windows running normally
+#ifdef _DEBUG
+   wgldisplay_cat.spam()  << "deactivate_window called"  << endl;
+#endif
+
+   if((!_props._fullscreen) || _exiting_window) 
+     return;
+
+   if(_window_inactive) 
+     return;
+
+   if(wgldisplay_cat.is_spam())
+       wgldisplay_cat.spam() << "WGL window deactivated, releasing gl context and waiting...\n";
+   _window_inactive = true;
+   unmake_current();
+
+   // bugbug: this isnt working right now on many drivers.  may have to
+   // destroy window and recreate a new OGL context for this to work
+
+   // make sure window is minimized
+
+   WINDOWPLACEMENT wndpl;
+   wndpl.length=sizeof(WINDOWPLACEMENT);
+   
+   if(!GetWindowPlacement(_mwindow,&wndpl)) {
+       wgldisplay_cat.error() << "GetWindowPlacement failed!\n";
+       return;
+   }
+   if((wndpl.showCmd!=SW_MINIMIZE)&&(wndpl.showCmd!=SW_SHOWMINIMIZED)) {
+       ShowWindow(_mwindow, SW_MINIMIZE);
+   }
+
+   // revert to default display mode
+   ChangeDisplaySettings(NULL,0x0);
+}
+
+void wglGraphicsWindow::reactivate_window(void) {
+    if(_window_inactive) {
+        if(wgldisplay_cat.is_spam())
+            wgldisplay_cat.spam() << "WGL window re-activated...\n";
+
+        _window_inactive = false;
+
+        // move window to top of zorder,
+        SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
+
+        ChangeDisplaySettings(_pCurrent_display_settings,CDS_FULLSCREEN);
+        
+        GdiFlush();
+        make_current();
+    }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: window_proc
 //       Access:
@@ -1324,7 +1346,7 @@ LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam
 LONG WINAPI wglGraphicsWindow::
 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
   int button = -1;
-  int x, y, width, height;
+  int x, y;
 
   switch (msg) {
     case WM_CREATE:
@@ -1343,56 +1365,67 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
           if(hwnd_pandawin_map.size()==0) {
               exit(0);
           }
-          return 0;
-
-    case WM_ACTIVATE: {
-       if (_props._fullscreen && (!_exiting_window)) {
-           // handle switching out of fullscreen mode differently than windowed mode.
-           // here we want to suspend all gfx and execution, switch display modes and minimize ourself
-           // until we are switched back to
-
+          break;
+
+    case WM_MOVE:
+          // handle all this stuff in EXITSIZEMOVE.  will rendering work during moving?  do we care?
+          //_props._xorg = LOWORD(lparam);
+          //_props._yorg = HIWORD(lparam);
+          break;
+
+      case WM_ACTIVATE: 
+            #ifdef _DEBUG
+              wgldisplay_cat.spam()  << "WM_ACTIVATE received"  << endl;
+            #endif
            if(LOWORD(wparam)==WA_INACTIVE) {
-               if(wgldisplay_cat.is_spam())
-                   wgldisplay_cat.spam() << "WGL window deactivated, releasing gl context and waiting...\n";
-               _window_inactive = true;
-               unmake_current();
-
-               // bugbug: this isnt working right now on many drivers.  may have to
-               // destroy window and recreate a new OGL context for this to work
-#ifdef ENABLE_ALTTAB_DISPLAYCHANGE
-               // revert to default display mode
-               ChangeDisplaySettings(NULL,0x0);
-#endif
-
-               if(HIWORD(wparam)==0x0)  // otherwise window already minimized
-                   ShowWindow(_mwindow, SW_MINIMIZE);
-           } else {
-               if(_window_inactive) {
-                   if(wgldisplay_cat.is_spam())
-                      wgldisplay_cat.spam() << "WGL window re-activated...\n";
-                   _window_inactive = false;
-                   
-                   // move window to top of zorder,
-                   SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
+               deactivate_window();
+               return 0;
+           }         // dont want to reactivate until window is actually un-minimized (see WM_SIZE)
+       break;
 
-                   make_current();
+    case WM_EXITSIZEMOVE:
+            #ifdef _DEBUG
+              wgldisplay_cat.spam()  << "WM_EXITSIZEMOVE received"  << endl;
+            #endif
+            
+            if(_window_inactive)
+                 reactivate_window();
+            handle_reshape();
+            break;
 
-                   ShowWindow(_mwindow, SW_SHOWNORMAL);
+    case WM_ENTERSIZEMOVE: 
+            break;
 
-#ifdef ENABLE_ALTTAB_DISPLAYCHANGE
-                   ChangeDisplaySettings(_pCurrent_display_settings,CDS_FULLSCREEN);
-#endif
-               }
-           }
-           return 0;
-       } else break;
+    case WM_SIZE: {
+                DWORD width,height;
+
+                width = LOWORD(lparam);  height = HIWORD(lparam);
+            #ifdef _DEBUG
+                {
+                    wgldisplay_cat.spam() << "WM_SIZE received with width:" << width << "  height: " << height << " flags: " <<
+                    ((wparam == SIZE_MAXHIDE)? "SIZE_MAXHIDE " : "") << ((wparam == SIZE_MAXSHOW)? "SIZE_MAXSHOW " : "") <<
+                    ((wparam == SIZE_MINIMIZED)? "SIZE_MINIMIZED " : "") << ((wparam == SIZE_RESTORED)? "SIZE_RESTORED " : "") <<
+                    ((wparam == SIZE_MAXIMIZED)? "SIZE_MAXIMIZED " : "") << endl;
+                }
+            #endif
+                if(_mwindow==NULL)
+                    break;
+
+                if((wparam==SIZE_MAXIMIZED) || (wparam==SIZE_RESTORED)) { // old comment -- added SIZE_RESTORED to handle 3dfx case  (what does this mean?)
+                    if(_window_inactive)
+                        reactivate_window();
+
+                    if((_props._xsize != width) || (_props._ysize != height))
+                        handle_reshape();
+                }
+                break;
     }
 
     case WM_PAINT: {
           PAINTSTRUCT ps;
           BeginPaint(hwnd, &ps);
           EndPaint(hwnd, &ps);
-          return 0;
+          return 0;       
     }
 
     case WM_SYSCHAR:
@@ -1406,14 +1439,14 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
         GetCursorPos(&point);
         ScreenToClient(hwnd, &point);
         handle_keypress(lookup_key(wparam), point.x, point.y);
-        return 0;
+        break;
       }
 
     case WM_SYSKEYUP:
     case WM_KEYUP: {
         // dont need x,y for this
         handle_keyrelease(lookup_key(wparam));
-        return 0;
+        break;
     }
     case WM_LBUTTONDOWN:
       button = 0;
@@ -1434,7 +1467,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
         y -= (1 << 16);
       // make_current();  what does OGL have to do with mouse input??
       handle_keypress(MouseButton::button(button), x, y);
-      return 0;
+      break;
     case WM_LBUTTONUP:
       button = 0;
     case WM_MBUTTONUP:
@@ -1454,7 +1487,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
           // make_current();  what does OGL have to do with mouse input??
       #endif
       handle_keyrelease(MouseButton::button(button));
-      return 0;
+      break;
 
     case WM_MOUSEMOVE:
         x = LOWORD(lparam);
@@ -1472,13 +1505,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
                     // make_current();  what does OGL have to do with mouse input??
                     handle_mouse_motion(x, y);
         }
-        return 0;
-
-    case WM_SIZE:
-          width = LOWORD(lparam);
-          height = HIWORD(lparam);
-          handle_reshape(width, height);
-          return 0;
+        break;
 
     case WM_SETFOCUS:
           SetCursor(_hMouseCursor);
@@ -1486,14 +1513,14 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
                make_current();
                handle_mouse_entry(MOUSE_ENTERED);
           }
-          return 0;
+          break;
 
     case WM_KILLFOCUS:
           if (mouse_entry_enabled()) {
                //make_current();  this doesnt make any sense, we're leaving our window
                handle_mouse_entry(MOUSE_EXITED);
           }
-          return 0;
+          break;
   }
 
   return DefWindowProc(hwnd, msg, wparam, lparam);

+ 5 - 3
panda/src/wgldisplay/wglGraphicsWindow.h

@@ -79,7 +79,8 @@ public:
   INLINE bool mouse_passive_motion_enabled(void) {
     return _mouse_passive_motion_enabled;
   }
-  void handle_reshape( int w, int h );
+//  void handle_reshape( int w, int h );
+
   void handle_mouse_motion( int x, int y );
   void handle_mouse_entry( int state );
   void handle_keypress( ButtonHandle key, int x, int y );
@@ -98,11 +99,10 @@ protected:
   void enable_mouse_passive_motion(bool val);
   void enable_mouse_entry(bool val);
 
-  void handle_changes(void);
+  void handle_reshape(void);
   void process_events(void);
 
 public:
-  uint              _change_mask;
   HWND              _mwindow;
 
 private:
@@ -143,6 +143,8 @@ public:
   LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
   ButtonHandle lookup_key(WPARAM wparam) const;
   void DestroyMe(bool bAtExitFnCalled);
+  void deactivate_window(void);
+  void reactivate_window(void);
 
 protected:
   virtual void do_close_window();