feisty meow concerns codebase 2.140
process_anchor.cpp
Go to the documentation of this file.
1/*
2*
3* Name : process_anchor
4* Author : Chris Koeritz
5*
6****
7* Copyright (c) 2000-$now By Author. This program is free software; you can
8* redistribute it and/or modify it under the terms of the GNU General Public
9* License as published by the Free Software Foundation; either version 2 of
10* the License or (at your option) any later version. This is online at:
11* http://www.fsf.org/copyleft/gpl.html
12* Please send any updates to: fred@gruntose.com
13*/
14
15#include "process_anchor.h"
16
18#include <basis/array.h>
19#include <basis/definitions.h>
21#include <basis/astring.h>
22#include <filesystem/filename.h>
25
26using namespace application;
27using namespace basis;
28using namespace filesystem;
29using namespace loggers;
30using namespace structures;
31//using namespace timely;
32
33#undef LOG
34#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
35
36#ifdef __WIN32__
37const int STARTUP_MESSAGE = WM_USER + 123;
38 // the special message we send out on startup of the event loop.
39
40const int TIMER_EVENT_ID = 23;
41 // the ID we use to create a timer, if the user wants one.
42
43// an anchor_association tracks the object related to a window handle.
44struct anchor_association {
45 window_handle _handle;
46 process_anchor *_anchor_object;
47
48 anchor_association(window_handle wh = NULL_POINTER, process_anchor *wo = NULL_POINTER)
49 : _handle(wh), _anchor_object(wo) {}
50};
51
52class anchor_association_list
53: public array<anchor_association>, public virtual root_object
54{
55public:
56 DEFINE_CLASS_NAME("anchor_association_list");
57};
58
59// the associations list keeps track of anchors that have been created so
60// that the window procedure (on win32) can get to the real object.
61
62SAFE_STATIC(anchor_association_list, associations, )
63#endif //win32
64
66
68#ifdef __LINUX__
70#endif
71#ifdef __WIN32__
72: _instance(NULL_POINTER),
73 _anchor_title(new astring),
74 _anchor_class(new astring),
75 _class_reg(NULL_POINTER),
76 _wind_handle(NULL_POINTER),
77 _cycle(0),
78 _defunct(false)
79#endif
80{
81}
82
84{
86#ifdef __WIN32__
87 WHACK(_anchor_title);
88 WHACK(_anchor_class);
89 _class_reg = NULL_POINTER;
90 // remove the association for our anchor.
91 for (int i = 0; i < associations().length(); i++) {
92 if (associations()[i]._handle == _wind_handle) {
93 associations().zap(i, i);
94 break;
95 }
96 }
97#endif
98}
99
100void process_anchor::handle_startup() { /* nothing for base class. */ }
101
102void process_anchor::handle_timer() { /* nothing for base class. */ }
103
104void process_anchor::handle_shutdown() { /* nothing for base class. */ }
105
107{
108#ifdef __LINUX__
110 return true;
111#endif
112#ifdef __WIN32__
113 bool to_return = false;
114 for (int i = 0; i < associations().length(); i++) {
115 window_handle win = associations()[i]._handle;
116 int ret = PostMessage(win, WM_CLOSE, NULL_POINTER, NULL_POINTER);
117 // if we got a healthy return from any post, then we'll say this worked.
118 if (ret) to_return = true;
119 }
120 return to_return;
121#endif
122}
123
125{
126#ifdef __LINUX__
128#endif
129#ifdef __WIN32__
130 return _defunct;
131#endif
132}
133
135{
136#ifdef __LINUX__
138#endif
139#ifdef __WIN32__
140 _defunct = true;
141#endif
142}
143
145{
146 FUNCDEF("close_app_anchor");
147#ifdef __LINUX__
149#endif
150#ifdef __WIN32__
152#ifdef DEBUG_PROCESS_MANAGER
153 LOG(astring("title is: ") + title);
154#endif
155
156//hmmm: add support for linux...
157#ifdef __WIN32__
158 window_handle win_found = FindWindow(NULL_POINTER, to_unicode_temp(title));
159#ifdef DEBUG_PROCESS_MANAGER
160 LOG(astring(astring::SPRINTF, "found window %lx", win_found));
161#endif
162 if (!win_found) {
163 LOG(astring("Failed to find special window for [") + app_name
164 + astring("]"));
165 return false;
166 }
167
168//hmmm:
169//why would we find only one window if there were multiple apps under that
170//name? how does windows deal with that? is there a find window iterator?
171
172 int ret = PostMessage(win_found, WM_CLOSE, NULL_POINTER, NULL_POINTER);
173 if (!ret) {
174 LOG(astring("Failed to send close message to [") + app_name
175 + astring("]"));
176 return false;
177 }
178
179 LOG(astring("Sent close message to [") + app_name + astring("]"));
180#else
181 #ifdef DEBUG_PROCESS_MANAGER
182 LOG("graceful shutdown not implemented for this OS.");
183 #endif
184 return false;
185#endif
186 return true;
187#endif //win32
188}
189
191 const astring &app_name, int cycle)
192{
193#ifdef __LINUX__
194 if (instance) {}
195 return shutdown_alerter::setup(app_name, cycle);
196#endif
197#ifdef __WIN32__
198 if (_wind_handle) return true; // already initialized.
199 // simple initializations first...
200 _instance = instance;
201 _cycle = cycle;
202 *_anchor_title = make_well_known_title(app_name);
203 *_anchor_class = make_well_known_class(app_name);
204 _class_reg = register_class(); // register a new window class for this.
205 _wind_handle = CreateWindow(to_unicode_temp(*_anchor_class),
206 to_unicode_temp(*_anchor_title), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
207 0, CW_USEDEFAULT, 0, NULL_POINTER, NULL_POINTER, _instance, NULL_POINTER);
208 if (!_wind_handle) return false;
209
210 register_anchor(_wind_handle); // hook in our anchor to the list.
211 ShowWindow(_wind_handle, SW_HIDE);
212 UpdateWindow(_wind_handle);
213 PostMessage(_wind_handle, STARTUP_MESSAGE, 0, 0);
214#endif //win32
215 return true;
216}
217
219{
220#ifdef __WIN32__
221 // add the new anchor to our list of associations.
222 associations() += anchor_association(wind, this);
223#else
224 if (wind) {}
225#endif
226}
227
228#ifdef __WIN32__
229ATOM process_anchor::register_class()
230{
231 WNDCLASSEX wcex;
232
233 wcex.cbSize = sizeof(WNDCLASSEX);
234
235 wcex.style = CS_HREDRAW | CS_VREDRAW;
236 wcex.lpfnWndProc = (WNDPROC)WndProc;
237 wcex.cbClsExtra = 0;
238 wcex.cbWndExtra = 0;
239 wcex.hInstance = _instance;
240 wcex.hIcon = NULL_POINTER;
241 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
242 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
243 wcex.lpszMenuName = NULL_POINTER;
244 to_unicode_persist(hold_class, _anchor_class->s());
245 wcex.lpszClassName = hold_class;
246 wcex.hIconSm = NULL_POINTER;
247
248 return RegisterClassEx(&wcex);
249}
250#endif
251
252#ifdef __WIN32__
253LRESULT CALLBACK process_anchor::WndProc(HWND hWnd, UINT message,
254 WPARAM wParam, LPARAM lParam)
255{
256 switch (message) {
257 case STARTUP_MESSAGE: {
258 for (int i = 0; i < associations().length(); i++) {
259 if (associations()[i]._handle == hWnd) {
260 process_anchor &anch = *associations()[i]._anchor_object;
261 // invoke the initial callback so the anchor can initialize.
262 anch.handle_startup();
263
264 // set a timer going if they wanted one.
265 if (anch._cycle)
266 SetTimer(anch._wind_handle, TIMER_EVENT_ID, anch._cycle, 0);
267 break;
268 }
269 }
270 break;
271 }
272 case WM_CLOSE: {
273 for (int i = 0; i < associations().length(); i++) {
274 if (associations()[i]._handle == hWnd) {
275 // invoke the closing callback because we're leaving.
276 associations()[i]._anchor_object->handle_shutdown();
277 associations()[i]._anchor_object->set_defunct();
278 break;
279 }
280 }
281 return DefWindowProc(hWnd, message, wParam, lParam);
282 break;
283 }
284 case WM_DESTROY: {
285 PostQuitMessage(0);
286 break;
287 }
288 case WM_TIMER: {
289 bool found_window = false; // records if we dispatched the event.
290 for (int i = 0; i < associations().length(); i++)
291 if (associations()[i]._handle == hWnd) {
292 // always stop the timer since we're suspending time while we're busy.
293 // more of a desire than a strategy.
294 KillTimer(hWnd, TIMER_EVENT_ID);
295 // invoke the timer callback to give the user some action.
296 associations()[i]._anchor_object->handle_timer();
297 found_window = true;
298 // always set the timer going again after handling it.
299 SetTimer(hWnd, TIMER_EVENT_ID,
300 associations()[i]._anchor_object->_cycle, 0);
301 break;
302 }
303 bool to_return = 0;
304 // if the timer wasn't for one of our anchors, we pass it to the default
305 // window procedure in hopes it will know what the hell to do with it.
306 if (!found_anchor)
307 to_return = DefWindowProc(hWnd, message, wParam, lParam);
308 return to_return;
309 }
310 case WM_PAINT: {
311 PAINTSTRUCT ps;
312 HDC hdc = BeginPaint(hWnd, &ps);
313 // add drawing code here if needed.
314 EndPaint(hWnd, &ps);
315 break;
316 }
317 default: return DefWindowProc(hWnd, message, wParam, lParam);
318 }
319 return 0;
320}
321#endif
322
323#ifdef __WIN32__
325{
326 filename app_short = application_name;
327 return astring("Anchor_for_") + app_short.basename();
328}
329#endif
330
331#ifdef __WIN32__
333{
334 filename app_short = application_name;
335 return astring("Dozeclass_for_") + app_short.basename();
336}
337#endif
338
340 const astring &application_name, int cycle)
341{
342 // prepare the anchor for its role...
343 if (!win.setup(handle, application_name, cycle)) return false;
344#ifdef __LINUX__
345 return shutdown_alerter::launch_console(win, application_name, cycle);
346#endif
347#ifdef __WIN32__
348 MSG msg;
349 msg.hwnd = 0; msg.message = 0; msg.wParam = 0; msg.lParam = 0;
350 while (GetMessage(&msg, NULL_POINTER, 0, 0)) {
351 TranslateMessage(&msg);
352 DispatchMessage(&msg);
353 }
354#endif
355 return true;
356}
357
358
359
360
#define LOG(s)
Represents a sequential, ordered, contiguous collection of objects.
Definition array.h:54
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
Provides operations commonly needed on file names.
Definition filename.h:64
filename basename() const
returns the base of the filename; no directory.
Definition filename.cpp:385
Implements a graceful shutdown procedure for an application.
void set_defunct()
used by the derived class to mark that this object is about to exit.
static bool close_this_program()
causes this particular program to shut down.
bool setup(application_instance handle, const basis::astring &application_name, int timing_cycle=0)
constructs a process_anchor for the "application_name" specified.
virtual void handle_startup()
derived classes can override this to catch the application startup.
virtual void handle_timer()
invoked periodically if the anchor was setup() with a timer "cycle".
static basis::astring make_well_known_class(const basis::astring &application_name)
same as above but for the anchor's class name.
void register_anchor(window_handle anchor)
this supports the anchor being created elsewhere.
static bool launch(process_anchor &anchor, application_instance handle, const basis::astring &app, int cycle=0)
establishes a process_anchor for the program named "app".
process_anchor()
constructor does very little; setup() begins operation.
static bool close_app_anchor(const basis::astring &app_name)
closes the anchor object associated with "app_name".
bool defunct() const
returns true if the object has been marked as defunct.
static basis::astring make_well_known_title(const basis::astring &application_name)
returns the string form of the well-known window title for the process_anchor.
virtual void handle_shutdown()
invoked just prior to the shutdown of this anchor.
virtual ~process_anchor()
A platform-independent way to alert a program that it should shut down immediately.
static bool is_defunct()
returns true if the object has been marked as defunct.
static void set_defunct()
used by the derived class to mark that this object is about to exit.
bool setup(const basis::astring &app_name, int timer_period=0)
constructs a shutdown_alerter for the "app_name" specified.
static void close_this_program()
causes this particular application to begin shutting down.
static bool launch_console(shutdown_alerter &alert, const basis::astring &app_name, int timer_period=0)
this is used to begin execution of a console mode application.
static bool close_application(const basis::astring &app_name)
attempts to close the application named "app_name".
Constants and objects used throughout HOOPLE.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
Support for unicode builds.
void * ATOM
void * application_instance
void * window_handle
void * HDC