core/vgui/impl/win32/vgui_win32.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/win32/vgui_win32.cxx
00002 #include "vgui_win32.h"
00003 
00004 #include <vgui/vgui_gl.h> // for glFlush()
00005 #include <vcl_iostream.h> // for vcl_cerr
00006 #include <vcl_cassert.h> // for assert
00007 #include <vcl_cstring.h> // for vcl_strlen()
00008 #include "vgui_win32_window.h"
00009 #include "vgui_win32_dialog_impl.h"
00010 
00011 vgui_win32* vgui_win32::instance_ = 0;
00012 
00013 // Return a single instance of vgui_win32.
00014 vgui_win32* vgui_win32::instance()
00015 {
00016   if ( instance_ == 0 )
00017     instance_ = new vgui_win32();
00018 
00019   return instance_;
00020 }
00021 
00022 vgui_win32::vgui_win32()
00023 {
00024   hInstance_ = GetModuleHandle(NULL);
00025   hPrevInstance_ = NULL;
00026   szCmdLine_ = NULL;
00027   iCmdShow_ = SW_SHOW;
00028 
00029   szAppName_ = NULL;
00030 
00031   windows_to_delete.clear();
00032   current_window = NULL;
00033   dialogs_to_delete.clear();
00034   current_dialog = NULL;
00035 }
00036 
00037 vgui_win32::~vgui_win32()
00038 {
00039 }
00040 
00041 
00042 // Process command line arguments
00043 BOOL vgui_win32::ProcessShellCommand(int argc, char **argv)
00044 {
00045   // We set szAppName_ to be the app name.
00046   char *p, *q = argv[0];
00047 
00048   // Skip path
00049   while ( p = vcl_strchr(q, '\\') ) q = ++p;
00050   // remove ".exe" suffix
00051   p = vcl_strstr(q, ".exe");
00052   // Now q points to the app name.
00053   if (p)
00054     szAppName_ = (char *)malloc(sizeof(char)*(p-q+1));
00055   else // .exe is not provided.
00056     szAppName_ = (char *)malloc(sizeof(char)*(1+vcl_strlen(q)));
00057 
00058   if ( szAppName_ == NULL )
00059     return FALSE;
00060   if (p) *p = 0;
00061   vcl_strcpy(szAppName_, q);
00062 
00063   // Convert argv into szCmdLine_
00064   szCmdLine_ = GetCommandLine();
00065 
00066   return TRUE;
00067 }
00068 
00069 void vgui_win32::init(int &argc, char **argv)
00070 {
00071   ProcessShellCommand(argc, argv);
00072 
00073   WNDCLASS wndclass;
00074   wndclass.style         = CS_HREDRAW | CS_VREDRAW;
00075   wndclass.lpfnWndProc   = globalWndProc;
00076   wndclass.cbClsExtra    = 0;
00077   wndclass.cbWndExtra    = 0;
00078   wndclass.hInstance     = hInstance_;
00079   wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
00080   wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
00081   wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
00082   wndclass.lpszMenuName  = szAppName_;
00083   wndclass.lpszClassName = szAppName_;
00084 
00085   if ( !RegisterClass(&wndclass) ) {
00086     vcl_cerr << "Fail to register window class for main window.\n";
00087     assert(false); // quit ugly
00088   }
00089 
00090   // Register a window class for dialog box.
00091   wndclass.style         = CS_HREDRAW | CS_VREDRAW;
00092   wndclass.lpfnWndProc   = globalDialogProc;
00093   wndclass.cbClsExtra    = 0;
00094   wndclass.cbWndExtra    = 0;
00095   wndclass.hInstance     = hInstance_;
00096   wndclass.hIcon         = LoadIcon(hInstance_, IDI_APPLICATION);
00097   wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
00098   wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
00099   wndclass.lpszMenuName  = NULL;
00100   wndclass.lpszClassName = TEXT("vgui_win32_dialog");
00101 
00102   if ( !RegisterClass(&wndclass) ) {
00103     MessageBox(NULL, TEXT("Fail to register window class for dialog box!"),
00104                NULL, MB_ICONERROR);
00105     assert(false); // quit ugly
00106   }
00107 
00108   // Register a window class for inline tableau control
00109   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
00110   wndclass.lpfnWndProc   = globalTableauProc;
00111   wndclass.cbClsExtra    = 0;
00112   wndclass.cbWndExtra    = 0;
00113   wndclass.hInstance     = hInstance_;
00114   wndclass.hIcon         = LoadIcon(hInstance_, IDI_APPLICATION);
00115   wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
00116   wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
00117   wndclass.lpszMenuName  = NULL;
00118   wndclass.lpszClassName = TEXT("vgui_win32_inline_tab");
00119 
00120   if ( !RegisterClass(&wndclass) ) {
00121     MessageBox(NULL, TEXT("Fail to register window class for inline tableau control!"),
00122                NULL, MB_ICONERROR);
00123     assert(false); // quit ugly
00124   }
00125 }
00126 
00127 void vgui_win32::uninit()
00128 {
00129   for (unsigned i=0; i<windows_to_delete.size(); i++)
00130     delete windows_to_delete[i];
00131 
00132   // dialogs are already freed at the end of scope of caller function.
00133 }
00134 
00135 vgui_window* vgui_win32::produce_window(int width, int height,
00136                                         vgui_menu const &menubar,
00137                                         char const *title)
00138 {
00139   vgui_window* a_window = new vgui_win32_window(hInstance_, szAppName_, width, height, menubar, title);
00140   windows_to_delete.push_back(a_window);
00141   current_window = a_window;
00142   return a_window;
00143 }
00144 
00145 vgui_window* vgui_win32::produce_window(int width, int height,
00146                                         char const *title)
00147 {
00148   vgui_window* a_window = new vgui_win32_window(hInstance_, szAppName_, width, height, title);
00149   windows_to_delete.push_back(a_window);
00150   current_window = a_window;
00151   return a_window;
00152 }
00153 
00154 vgui_dialog_impl* vgui_win32::produce_dialog(char const *name)
00155 {
00156   vgui_window *win = get_current_window();
00157 
00158   current_dialog = new vgui_win32_dialog_impl(name,
00159                                               win ? ((vgui_win32_window*)win)->getWindowHandle() : NULL);
00160   dialogs_to_delete.push_back(current_dialog);
00161   return current_dialog;
00162 }
00163 
00164 vgui_dialog_extensions_impl* vgui_win32::produce_dialog_extension(char const *name)
00165 {
00166   //return new vgui_win32_dialog_extension_impl(name);
00167   return 0;
00168 }
00169 
00170 // Run the event loop. Windows uses messages
00171 void vgui_win32::run()
00172 {
00173   MSG msg;
00174 
00175   while ( GetMessage(&msg, NULL, 0, 0) ) {
00176     vgui_win32_window *pwin = (vgui_win32_window*)get_current_window();
00177     if (pwin) {
00178       HWND hwnd = pwin->getWindowHandle();
00179       HACCEL hAccel = pwin->getAccelHandle();
00180       if ( !(hAccel && TranslateAccelerator(hwnd, hAccel, &msg)) ) {
00181         TranslateMessage(&msg);
00182         DispatchMessage(&msg);
00183       }
00184     }
00185     else {
00186       TranslateMessage(&msg);
00187       DispatchMessage(&msg);
00188     }
00189   }
00190 }
00191 
00192 // TODO: This function is not called yet.
00193 void vgui_win32::run_one_event()
00194 {
00195   if ( !PumpMessage() )
00196     PostQuitMessage(0);
00197 }
00198 
00199 // TODO: This function is not called yet.
00200 void vgui_win32::run_till_idle()
00201 {
00202   MSG msg;
00203 
00204   while ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
00205     if ( !PumpMessage() ) {
00206       PostQuitMessage(0);
00207       break;
00208     }
00209   }
00210 }
00211 
00212 // TODO: This function is not called yet.
00213 // Remove all events from the event queue. Copy the code from that of
00214 // counterparts such as mfc, gkt2.
00215 void vgui_win32::flush()
00216 {
00217   glFlush();
00218   run_till_idle();
00219 }
00220 
00221 // TODO: This function is not called yet.
00222 // Add event to the event queue.
00223 void vgui_win32::add_event(vgui_event const &e)
00224 {
00225   //PostMessage(); // TODO
00226 }
00227 
00228 // Quit application
00229 void vgui_win32::quit()
00230 {
00231   PostQuitMessage(0);
00232 }
00233 
00234 // TODO: This function is not called yet.
00235 // Pump a message from the thread's message queue and process it.
00236 BOOL vgui_win32::PumpMessage()
00237 {
00238   MSG msg;
00239 
00240   if ( !GetMessage(&msg, NULL, 0, 0) )
00241     return FALSE;
00242 
00243   TranslateMessage(&msg);
00244   DispatchMessage(&msg);
00245 
00246   return TRUE;
00247 }
00248 
00249 // Find the window whose handle is hwnd.
00250 inline int vgui_win32::find_window(HWND hwnd)
00251 {
00252   int i;
00253   vcl_vector<vgui_window*>::const_iterator it;
00254   for ( i = 0,  it = windows_to_delete.begin();
00255         it != windows_to_delete.end(); it++, i++ ) {
00256     HWND the_hwnd = ((vgui_win32_window*)(*it))->getWindowHandle();
00257     if ( the_hwnd == hwnd )
00258       return i;
00259   }
00260   // Not found
00261   return -1;
00262 }
00263 
00264 inline void vgui_win32::dump_window_stack()
00265 {
00266   vcl_cout << "z-top of window stack: ";
00267 
00268   vcl_vector<vgui_window*>::const_iterator it;
00269   for ( it = windows_to_delete.begin();
00270         it != windows_to_delete.end(); it++ )
00271     vcl_cout << ((vgui_win32_window*)(*it))->getWindowHandle() << ',';
00272   vcl_cout << vcl_endl;
00273 }
00274 
00275 // Set the current window as the one whose handle is "hwnd".
00276 // In other words, raise the window hwnd to the top of z-order stack
00277 // of windows.
00278 void vgui_win32::set_current_window(HWND hwnd)
00279 {
00280   int n = find_window(hwnd);
00281   if ( n == -1 || windows_to_delete[n] == current_window )
00282     return; // do nothing if hwnd is already top-most, or not found.
00283 
00284   current_window = windows_to_delete[n];
00285   windows_to_delete.erase(windows_to_delete.begin()+n);
00286   windows_to_delete.push_back(current_window);
00287   //dump_window_stack();
00288 }
00289 
00290 
00291 // Remove the current window from z-order stack of windows.
00292 void vgui_win32::remove_current_window()
00293 {
00294   windows_to_delete.pop_back();
00295   delete current_window;
00296   current_window = windows_to_delete.empty() ? NULL : windows_to_delete.back();
00297   //dump_window_stack();
00298 }
00299 
00300 void vgui_win32::remove_current_dialog()
00301 {
00302   dialogs_to_delete.pop_back();
00303   current_dialog = dialogs_to_delete.empty() ? NULL : dialogs_to_delete.back();
00304 }
00305 
00306 LRESULT CALLBACK globalWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
00307 {
00308   LRESULT lResult = 0;
00309   vgui_win32_window* pwin;
00310 
00311   // Some messages should be handled here, not in vgui_window and vgui_adaptor
00312 
00313   vgui_win32::instance()->set_current_window(hwnd);
00314 
00315   if ( message == WM_DESTROY ) {
00316      // When multiple vgui_window objects are created, a WM_DESTROY message
00317      // is sent when one of the vgui_window is closed.
00318      // In this case, two operations have to be done. First, the current
00319      // window (along with device context and OpenGL rendering context)
00320      // should be switched. Second, the WM_DESTROY message should be
00321      // blocked unless no vgui_window object exists. Otherwise, the
00322      // application will quit since function PostQuitMessage() is called
00323      // (ie. WM_QUIT is sent) in response to WM_DESTROY message.
00324 
00325      vgui_win32::instance()->remove_current_window();
00326 
00327     // Call post_redraw to switch device context and GL rendering context.
00328     pwin = (vgui_win32_window*)vgui_win32::instance()->get_current_window();
00329     if ( pwin) pwin->get_adaptor()->post_redraw();
00330 
00331      // block WM_DESTROY message
00332      return 1;
00333   }
00334 
00335   pwin = (vgui_win32_window*)vgui_win32::instance()->get_current_window();
00336   if ( pwin )
00337     lResult = pwin->WndProc(hwnd, message, wParam, lParam);
00338 
00339   return lResult ? lResult : DefWindowProc(hwnd, message, wParam, lParam);
00340 }
00341 
00342 LRESULT CALLBACK globalDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
00343 {
00344   LRESULT lResult = 0;
00345   vgui_win32_window* pwin;
00346   vgui_win32_dialog_impl *dlg;
00347 
00348 
00349   dlg = (vgui_win32_dialog_impl *)vgui_win32::instance()->get_current_dialog();
00350   if ( dlg )
00351     lResult = dlg->DialogProc(hDlg, message, wParam, lParam);
00352 
00353   if ( message == WM_DESTROY ) {
00354     // Call post_redraw to switch device context and GL rendering context.
00355     pwin = (vgui_win32_window*)vgui_win32::instance()->get_current_window();
00356     pwin->get_adaptor()->post_redraw();
00357 
00358     // Reset pointer to current dialog box.
00359     (vgui_win32::instance())->remove_current_dialog();
00360   }
00361 
00362   return lResult ? lResult : DefWindowProc(hDlg, message, wParam, lParam);
00363 }
00364 
00365 LRESULT CALLBACK globalTableauProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
00366 {
00367   vgui_win32_dialog_impl *dlg;
00368 
00369   // Get the dialog box the inline tableau belongs.
00370   dlg = (vgui_win32_dialog_impl *)vgui_win32::instance()->get_current_dialog();
00371 
00372   if ( dlg && dlg->get_inline_tableau_size() > 0 )
00373     dlg->get_current_tab()->OnCmdMsg(message, wParam, lParam);
00374 
00375   return DefWindowProc(hDlg, message, wParam, lParam);
00376 }