anchor_window.cpp

Go to the documentation of this file.
00001 #ifndef ANCHOR_WINDOW_IMPLEMENTATION_FILE
00002 #define ANCHOR_WINDOW_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : anchor_window                                                     *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2000-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "anchor_window.h"
00019 
00020 #include <basis/array.cpp>
00021 #include <basis/convert_utf.h>
00022 #include <basis/istring.h>
00023 #include <basis/log_base.h>
00024 #include <basis/portable.h>
00025 #include <data_struct/static_memory_gremlin.h>
00026 #include <opsystem/filename.h>
00027 
00028 #undef LOG
00029 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00030 
00031 #ifdef __WIN32__
00032 const int STARTUP_MESSAGE = WM_USER + 123;
00033   // the special message we send out on startup of the event loop.
00034 
00035 const int TIMER_EVENT_ID = 23;
00036   // the ID we use to create a timer, if the user wants one.
00037 
00038 // a window_association tracks the object related to a window handle.
00039 
00040 struct window_association {
00041   window_handle _handle;
00042   anchor_window *_window_object;
00043 
00044   window_association(window_handle wh = NIL, anchor_window *wo = NIL)
00045       : _handle(wh), _window_object(wo) {}
00046 };
00047 
00048 class window_association_list
00049 : public array<window_association>, public virtual object_base
00050 {
00051 public:
00052   IMPLEMENT_CLASS_NAME("window_association_list");
00053 };
00054 
00055 // the associations list keeps track of windows that have been created so
00056 // that the window procedure can get to the real object.
00057 
00058 SAFE_STATIC(window_association_list, associations, )
00059 #endif //win32
00060 
00062 
00063 anchor_window::anchor_window()
00064 #ifdef __LINUX__
00065 : shutdown_alerter()
00066 #endif
00067 #ifdef __WIN32__
00068 : _instance(NIL),
00069   _window_title(new istring),
00070   _window_class(new istring),
00071   _class_reg(NIL),
00072   _wind_handle(NIL),
00073   _cycle(0),
00074   _defunct(false)
00075 #endif
00076 {
00077 }
00078 
00079 anchor_window::~anchor_window()
00080 {
00081   set_defunct();
00082 #ifdef __WIN32__
00083   WHACK(_window_title);
00084   WHACK(_window_class);
00085   _class_reg = NIL;
00086   // remove the association for our window.
00087   for (int i = 0; i < associations().length(); i++) {
00088     if (associations()[i]._handle == _wind_handle) {
00089       associations().zap(i, i);
00090       break;
00091     }
00092   }
00093 #endif
00094 }
00095 
00096 void anchor_window::handle_startup() { /* nothing for base class. */ }
00097 
00098 void anchor_window::handle_timer() { /* nothing for base class. */ }
00099 
00100 void anchor_window::handle_shutdown() { /* nothing for base class. */ }
00101 
00102 bool anchor_window::close_this_program()
00103 {
00104 #ifdef __LINUX__
00105   shutdown_alerter::close_this_program();
00106   return true;
00107 #endif
00108 #ifdef __WIN32__
00109   bool to_return = false;
00110   for (int i = 0; i < associations().length(); i++) {
00111     window_handle win = associations()[i]._handle;
00112     int ret = PostMessage(win, WM_CLOSE, NIL, NIL);
00113     // if we got a healthy return from any post, then we'll say this worked.
00114     if (ret) to_return = true;
00115   }
00116   return to_return;
00117 #endif
00118 }
00119 
00120 bool anchor_window::defunct() const
00121 {
00122 #ifdef __LINUX__
00123   return shutdown_alerter::is_defunct();
00124 #endif
00125 #ifdef __WIN32__
00126   return _defunct;
00127 #endif
00128 }
00129 
00130 void anchor_window::set_defunct()
00131 {
00132 #ifdef __LINUX__
00133   return shutdown_alerter::set_defunct();
00134 #endif
00135 #ifdef __WIN32__
00136   _defunct = true;
00137 #endif
00138 }
00139 
00140 bool anchor_window::close_app_window(const istring &app_name)
00141 {
00142   FUNCDEF("close_app_window");
00143 #ifdef __LINUX__
00144   return shutdown_alerter::close_application(app_name);
00145 #endif
00146 #ifdef __WIN32__
00147   istring title = anchor_window::make_well_known_title(app_name);
00148 #ifdef DEBUG_PROCESS_MANAGER
00149   LOG(istring("title is: ") + title);
00150 #endif
00151 
00152 //hmmm: add support for linux...
00153 #ifdef __WIN32__
00154   window_handle win_found = FindWindow(NIL, to_unicode_temp(title));
00155 #ifdef DEBUG_PROCESS_MANAGER
00156   LOG(istring(istring::SPRINTF, "found window %lx", win_found));
00157 #endif
00158   if (!win_found) {
00159     LOG(istring("Failed to find special window for [") + app_name
00160       + istring("]"));
00161     return false;
00162   }
00163 
00164 //hmmm:
00165 //why would we find only one window if there were multiple apps under that
00166 //name?  how does windows deal with that?  is there a find window iterator?
00167 
00168   int ret = PostMessage(win_found, WM_CLOSE, NIL, NIL);
00169   if (!ret) {
00170     LOG(istring("Failed to send close message to [") + app_name
00171         + istring("]"));
00172     return false;
00173   }
00174 
00175   LOG(istring("Sent close message to [") + app_name + istring("]"));
00176 #else
00177   #ifdef DEBUG_PROCESS_MANAGER
00178     LOG("graceful shutdown not implemented for this OS.");
00179   #endif
00180   return false;
00181 #endif
00182   return true;
00183 #endif //win32
00184 }
00185 
00186 bool anchor_window::setup(application_instance instance,
00187     const istring &app_name, int cycle)
00188 {
00189 #ifdef __LINUX__
00190   if (instance) {}
00191   return shutdown_alerter::setup(app_name, cycle);
00192 #endif
00193 #ifdef __WIN32__
00194   if (_wind_handle) return true;  // already initialized.
00195   // simple initializations first...
00196   _instance = instance;
00197   _cycle = cycle;
00198   *_window_title = make_well_known_title(app_name);
00199   *_window_class = make_well_known_class(app_name);
00200   _class_reg = register_class();  // register a new window class for this.
00201   _wind_handle = CreateWindow(to_unicode_temp(*_window_class),
00202       to_unicode_temp(*_window_title), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
00203       0, CW_USEDEFAULT, 0, NIL, NIL, _instance, NIL);
00204   if (!_wind_handle) return false;
00205 
00206   register_window(_wind_handle);  // hook in our window to the list.
00207   ShowWindow(_wind_handle, SW_HIDE);
00208   UpdateWindow(_wind_handle);
00209   PostMessage(_wind_handle, STARTUP_MESSAGE, 0, 0);
00210 #endif  //win32
00211   return true;
00212 }
00213 
00214 void anchor_window::register_window(window_handle wind)
00215 {
00216 #ifdef __WIN32__
00217   // add the new window to our list of associations.
00218   associations() += window_association(wind, this);
00219 #else
00220   if (wind) {}
00221 #endif
00222 }
00223 
00224 #ifdef __WIN32__
00225 ATOM anchor_window::register_class()
00226 {
00227   WNDCLASSEX wcex;
00228 
00229   wcex.cbSize = sizeof(WNDCLASSEX);
00230 
00231   wcex.style = CS_HREDRAW | CS_VREDRAW;
00232   wcex.lpfnWndProc = (WNDPROC)WndProc;
00233   wcex.cbClsExtra = 0;
00234   wcex.cbWndExtra = 0;
00235   wcex.hInstance = _instance;
00236   wcex.hIcon = NIL;
00237   wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
00238   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
00239   wcex.lpszMenuName = NIL;
00240   to_unicode_persist(hold_class, _window_class->s());
00241   wcex.lpszClassName = hold_class;
00242   wcex.hIconSm = NIL;
00243 
00244   return RegisterClassEx(&wcex);
00245 }
00246 #endif
00247 
00248 #ifdef __WIN32__
00249 LRESULT CALLBACK anchor_window::WndProc(HWND hWnd, UINT message,
00250     WPARAM wParam, LPARAM lParam)
00251 {
00252   switch (message) {
00253     case STARTUP_MESSAGE: {
00254       for (int i = 0; i < associations().length(); i++) {
00255         if (associations()[i]._handle == hWnd) {
00256           anchor_window &anch = *associations()[i]._window_object;
00257           // invoke the initial callback so the window can initialize.
00258           anch.handle_startup();
00259 
00260           // set a timer going if they wanted one.
00261           if (anch._cycle)
00262             SetTimer(anch._wind_handle, TIMER_EVENT_ID, anch._cycle, 0);
00263           break;
00264         }
00265       }
00266       break;
00267     }
00268     case WM_CLOSE: {
00269       for (int i = 0; i < associations().length(); i++) {
00270         if (associations()[i]._handle == hWnd) {
00271           // invoke the closing callback because we're leaving.
00272           associations()[i]._window_object->handle_shutdown();
00273           associations()[i]._window_object->set_defunct();
00274           break;
00275         }
00276       }
00277       return DefWindowProc(hWnd, message, wParam, lParam);
00278       break;
00279     }
00280     case WM_DESTROY: {
00281       PostQuitMessage(0);
00282       break;
00283     }
00284     case WM_TIMER: {
00285       bool found_window = false;  // records if we dispatched the event.
00286       for (int i = 0; i < associations().length(); i++)
00287         if (associations()[i]._handle == hWnd) {
00288           // always stop the timer since we're suspending time while we're busy.
00289           // more of a desire than a strategy.
00290           KillTimer(hWnd, TIMER_EVENT_ID);
00291           // invoke the timer callback to give the user some action.
00292           associations()[i]._window_object->handle_timer();
00293           found_window = true;
00294           // always set the timer going again after handling it.
00295           SetTimer(hWnd, TIMER_EVENT_ID,
00296               associations()[i]._window_object->_cycle, 0);
00297           break;
00298         }
00299       bool to_return = 0;
00300       // if the timer wasn't for one of our windows, we pass it to the default
00301       // window procedure in hopes it will know what the hell to do with it.
00302       if (!found_window)
00303         to_return = DefWindowProc(hWnd, message, wParam, lParam);
00304       return to_return;
00305     }
00306     case WM_PAINT: {
00307       PAINTSTRUCT ps;
00308       HDC hdc = BeginPaint(hWnd, &ps);
00309       // add drawing code here if needed.
00310       EndPaint(hWnd, &ps);
00311       break;
00312     }
00313     default: return DefWindowProc(hWnd, message, wParam, lParam);
00314   }
00315   return 0;
00316 }
00317 #endif
00318 
00319 #ifdef __WIN32__
00320 istring anchor_window::make_well_known_title(const istring &application_name)
00321 {
00322   filename app_short = application_name;
00323   return istring("Anchor_for_") + app_short.basename();
00324 }
00325 #endif
00326 
00327 #ifdef __WIN32__
00328 istring anchor_window::make_well_known_class(const istring &application_name)
00329 {
00330   filename app_short = application_name;
00331   return istring("Dozeclass_for_") + app_short.basename();
00332 }
00333 #endif
00334 
00335 bool anchor_window::launch(anchor_window &win, application_instance handle,
00336     const istring &application_name, int cycle)
00337 {
00338   // prepare the window for its role...
00339   if (!win.setup(handle, application_name, cycle)) return false;
00340 #ifdef __LINUX__
00341   return shutdown_alerter::launch_console(win, application_name, cycle);
00342 #endif
00343 #ifdef __WIN32__
00344   MSG msg;
00345   msg.hwnd = 0; msg.message = 0; msg.wParam = 0; msg.lParam = 0;
00346   while (GetMessage(&msg, NIL, 0, 0)) {
00347     TranslateMessage(&msg);
00348     DispatchMessage(&msg);
00349   }
00350 #endif
00351   return true;
00352 }
00353 
00354 
00355 #endif //ANCHOR_WINDOW_IMPLEMENTATION_FILE
00356 

Generated on Fri Nov 28 04:29:30 2008 for HOOPLE Libraries by  doxygen 1.5.1